Reputation: 89
I'm trying to do simple thing - bind directive's model to service's data. And all right before service's data loads async (by $timeout or $http request), it simply does not update directive's model.
Live example http://codepen.io/snater/pen/IjvFa
And source:
<div ng-app="asyncServiceTest" ng-controller="testController">
<bind-to-service></bind-to-service>
</div>
app = angular.module "asyncServiceTest", []
app.directive "bindToService", ["dataService", (dataService) ->
restrict: "E"
scope: {}
template: "<div>{{ test }}</div>"
link: (scope) ->
scope.test = dataService.test
]
app.factory "asyncService", ["dataService", "$timeout", (dataService, $timeout) ->
load: ->
dataService.test = "SYNC DATA!" # Works fine
$timeout ->
dataService.test = "ASYNC DATA!" # Doesn't work ((
, 2000
]
app.factory "dataService", ->
test: "Init Data"
app.controller "testController", ["$scope", "asyncService", ($scope, asyncService) ->
asyncService.load()
]
Call $apply on $rootScope in asyncService does not works, it's expected, but i've tried.
Upvotes: 2
Views: 2164
Reputation: 11
The main issue with your code is you are trying to change the direct reference of the test object when the data changes using async methods. This causes the problem because you binded the test object "REFERENCE" with the directive's model so you should not change it for the data-binding to be alive. if you change the reference then the binding will be lost.
So save your data in test object's property like "test.value" and change the value not the test reference.
Here is the updated code:
app = angular.module "asyncServiceTest", []
app.directive "bindToService", ["dataService", (dataService) ->
restrict: "E"
scope: {}
template: "<div>{{ test.value }}</div>"
link: (scope) ->
scope.test = dataService.test;
]
app.factory "asyncService", ["dataService", "$timeout", (dataService, $timeout) ->
load: ->
dataService.test.value = "SYNC DATA!"
$timeout ->
dataService.test.value = "ASYNC DATA!"
, 2000
]
app.factory "dataService", ->
test: {value:""};
app.controller "testController", ["$scope", "asyncService", ($scope, asyncService) ->
asyncService.load()
]
Here is the updated link:
http://codepen.io/kalyansriram/pen/BCmla
Upvotes: 1
Reputation: 42669
You should use the .
notation when doing binding due to prototypal nature of javascript. I have updated the live example.
http://codepen.io/anon/pen/jverH
Basically i changed the service to
app.factory "dataService", ->
test: {data:"Init Data"}
and did other corresponding changes.
Basically when you did
scope.test = dataService.test;
you just assigned the scope test
value to a string. But any changes to dataService test
string are not reflected as expected. In programming terms its like pass by value.
Read about scope prototypal inheritance and how it works to understand why what you did does not work.
Upvotes: 2