Search code examples
javascriptangularjsangularjs-scope

Angular $scope property gets overwritten when passed into function as an argument


I have an odd situation that I can't seem to figure out.

In Angular 1.4, I have a variable on the scope object used as a model to collect form data, $scope.videoModel. When a form is submitted, the model gets passed into a function, ng-submit="createVideo(videoModel), where a bunch of processing and regex happens. For example, extract a YouTube id.

Everything works as intended, but even though I am passing in the scope object as an argument (payload) to a function , certain attributes that are updated on the argument, also get updated on the $scope.

For eample, if I pass in $scope.videoModel.youtube into createVideo as payload, then extract the Youtube ID and assign it as payload.youtube = payload.youtube.match(regEx);, the $scope.videoModel.youtube property also gets updated. I can see this since the form value gets changed from a complete url to just the id.

It seems that passing in videoModel as an argument to a function does not create a copy to the variable, but instead references it. I can't seem to find anything about it. I believe I could simply create a new variable like this var tempVar = payload, but that seems wacky and I wonder if I'm doing something fundamentally incorrect.

Does videoModel get passed in a reference and not a copy?

Here is a sampling of the code clipped for brevity.

HTML

<div class="form-group">
    <label for="inputPassword3" class="col-sm-2 control-label">YouTube Url</label>
    <div class="col-sm-10">
        <input class="form-control" ng-class="{ 'has-error' : newvideo.youtube.$invalid && newvideo.youtube.$touched, 'is-valid': newvideo.youtube.$valid }"  placeholder="Youtube Url" ng-model="videoModel.youtube" name="youtube" ng-pattern="youtubeValidateRegex" required>
        <div class="help-block" ng-messages="newvideo.youtube.$error" ng-show="newvideo.youtube.$touched">
            <p ng-message="required">YouTube Url is required.</p>
            <p ng-message="pattern">Please input a valid YouTube Url.</p>
        </div>
    </div>
</div>
 <div class="form-group">
    <div class="col-sm-offset-2 col-sm-10" ng-if="!success">
     <button class="btn btn-default" ng-click="newVideo(videoModel)" ng-disabled="newvideo.$invalid"> Publish</button>
 </div>
      </div>

JS

$scope.videoModel = {
  youtube: 'https://www.youtube.com/watch?v=VkzVgiYUEIM',
  vimeo: 'https://vimeo.com/193391290'

};

  $scope.newVideo = function(payload) {
            $scope.processing = true;
            payload.user = $scope.user._id;
            payload.filename = $scope.filename;
            console.log(payload);
              if(payload.type === 'vimeo') {
                var matchVM = payload.vimeo.match($scope.vimeoExtractRegex);
                console.log(matchVM);
                if(matchVM) { //todo: helpers
                  payload.vimeo = matchVM[5];
              } else {
                return toastr.error('Unable to extract Vimeo ID');
              }
            }
              if(payload.type === 'youtube') {
                var matchYT = payload.youtube.match($scope.youtubeExtractRegex);
                  if (matchYT && matchYT[1].length === 11) { //todo: helpers
                    payload.youtube = matchYT[1];
                  } else {
                    return toastr.error('Unable to extract YouTube ID');
                  }
              }
            Videos.newVideo(payload)
                .then(function(result) {
                    toastr.success('New video created.');
                    $scope.processing = false;
                    $scope.success = true;
                    $scope.result = result.data.result;
                    $scope.payload = result.data.payload;  //I do assign part of the result to $scope.payload... but that still doesn't explain videoModel.youtube getting overwritten.
                })
                .catch(function(response) {
                    $scope.error = true;
                    toastr.error(response.data.message, response.data.status);
                });
                return $scope.success;
        };

Solution

  • In JavaScript, object references are values.

    Because of this, objects will behave like they are passed by reference:

    If a function changes an object property, it changes the original value.

    Changes to object properties are visible (reflected) outside the function.

    http://www.w3schools.com/js/js_function_parameters.asp