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;
};
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.