简体   繁体   中英

How to bind directive model to async service data

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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM