0

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/

0

3 Answers 3

4

You have to use this:

var changeId = function () {
    console.log('pre change:' + id);
    this.id = 'World';
    console.log('post change:' + id);
};
Sign up to request clarification or add additional context in comments.

1 Comment

Damn it, I knew I was missing something simple. Thanks.
3

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.

1 Comment

Thank you for the explanation behind the this based solution. In my scenario that is actually fine as that is the only way I'll be using it.
1

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

this.id = "World"

instead of

id = "World"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.