Reputation: 3925
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
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
Reputation: 211
You pass function in another object and function scope is changed Try:
this.id = "World"
instead of
id = "World"
Upvotes: 1
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