0

I'm working in Angular. I've created a simple service to illustrate the issue I'm seeing. When someone calls the setProfile method on this service, my goal is to set the 'profile' to a new object literal that contains the new property values. However, when I do this it does not appear that consumers of this service can see the updates. In other words, they see the old 'profile' object, not the new one. However, if I just update the individual properties instead of assigning the 'profile' to a new object literal, they see the updates just fine. I am VERY confused.

This code works (i.e. after the setProfile method is called, consumers see the updated values):

(function () {
angular.module('myApp').factory('myService', function () {

    var profile = {
        firstName: '',
        lastName: ''
    };

    var setProfile = function (firstName, lastName) {
        profile.firstName = firstName;
        profile.lastName = lastName;
    };

    return {
        setProfile: setProfile,
        profile: profile
    }
});
}());

But this does not work (i.e. when I assign the profile to a new object literal, consumers do not see the new object):

(function () {
angular.module('myApp').factory('myService', function () {

    var profile = {
        firstName: '',
        lastName: ''
    };

    var setProfile = function (firstName, lastName) {
        profile = {
            firstName: firstName,
            lastName: lastName
        };
    };

    return {
        setProfile: setProfile,
        profile: profile
    }
});
}());

Here is an example of how the service may be used:

module.run(['$rootScope', 'currentUser', function ($rootScope, currentUser) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
    debugger;
    if (!currentUser.firstName == 'test') {
        return;
    }
});
}]);
spoof3r
  • 607
  • 8
  • 23

1 Answers1

1

This is expected because the consumers of profile have a reference to the initial object that is created. So if you update the object via profile.firstName = 'bob' you are updating the same object. However when you set the profile via profile = {firstname: 'bob'} you are creating a whole new object when you use the curly braces and any consumers of the first profile object don't know about the new one.

One way to get around this is with a $watch but it is usually best to avoid a $watch if you can for performance reasons.

Something else to keep in mind is that all angular factory/services are Singletons. So when you're new to Angular you may expect that a new currentUser gets injected every time your controller starts up when in reality all injections are referencing the same instance of currentUser.

Ryan
  • 5,845
  • 32
  • 27
  • So are variables that point to object literals pointing to a reference or a value? If its by value then this would make sense, otherwise it does not. Because if it by reference, that means my factory returned an object that has a profile property, which references the internal property, which references an object literal. So updating the internal profile object to a new object would just update the reference. Am I missing something? – spoof3r Aug 22 '15 at 07:33
  • Both ;) Maybe this will make more sense: http://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language – Ryan Aug 22 '15 at 07:48
  • Wow, I had no idea! How have I used JS so long without knowing this? Thank you so much!!! – spoof3r Aug 22 '15 at 08:03