Kyle Muir
Kyle Muir

Reputation: 3925

AngularJS - Service exposing a string

I have a problem where I have a service which exposes a string. There is a function on this service which updates the value of the string. The service internally knows that the value has changed, however, externally the value NEVER updates.

If I nest the string inside an object then it all works, but I don't really want to nest it.

Can anyone explain why this is happening? It feels like it should work and feels like I am missing something basic.

Service:

myApp.service('neverChanges', function () {
    var id = 'Hello';
    var changeId = function () {
        console.log('pre change:' + id);
        id = 'World';
        console.log('post change:' + id);
    };

    return {
        id: id,
        changeId: changeId
    };
});

Controller:

myApp.controller('Controller1', ['neverChanges', function (neverChanges) {
    this.idValue = function() {
        return neverChanges.id;
    }
    this.clickHandler = function () {
        console.log('Trust me, I did fire...');
        neverChanges.changeId();
        console.log('external post change:' + neverChanges.id);
    };
}]);

Markup:

<div ng-app="myApp">
    <div ng-controller="Controller1 as vm">
         <h3>This will never change:</h3>
        <button ng-click="vm.clickHandler()">Click Me!</button>
        <p>Values:</p>
        <p>id: {{vm.idValue()}}</p>
</div>

Fiddle showing the two scenarios: http://jsfiddle.net/KyleMuir/2nhoc2rz/

Upvotes: 0

Views: 90

Answers (3)

yankee
yankee

Reputation: 40840

The problem is that you have local variable id: var id = 'Hello';

Later in the function you copy the value of this local variable into an object that you return:

return {
        id: id,
        changeId: changeId
    };

So from here on the returned object has a propery id which is COPY of your original id variable, and your changeId function just changes your local variable, but of course not the copy.

To prevent that you would need to keep a reference to the object that you return. That could e.g. look like this:

var result = {id:'Hello'};
result.changeId = function () {
    console.log('pre change:' + result.id);
    result.id = 'World';
    console.log('post change:' + result.id);
};
return result;

See working version: http://jsfiddle.net/y4mxazqh/

This way you get rid of the local variable id and you can change the object that you returned.

Of course the return also creates a copy of the reference to your local variable result. But since both the returned reference and your local variable point to the same object, you can change the content of that object and after that both references still reference an object that's id has now changed.

EDIT:

Essentially originof's answer solves the same problem with a different approach: Because you call vm.clickHandler() the function clickHandler() gets the this set to vm and vm in turn is the object that you returned. Thus you can access the returned object. However be aware, that if you execute code like this:

var func = vm.clickHandler();
func();

this would not be the same. In this case this would not get set to vm and you are lost. You should be aware of this situation when you choose the this-based solution.

Upvotes: 3

Taras Kostiuk
Taras Kostiuk

Reputation: 211

You pass function in another object and function scope is changed Try:

this.id = "World"

instead of

id = "World"

Upvotes: 1

Manuel Mazzuola
Manuel Mazzuola

Reputation: 795

You have to use this:

var changeId = function () {
    console.log('pre change:' + id);
    this.id = 'World';
    console.log('post change:' + id);
};

Upvotes: 4

Related Questions