Reputation: 2073
I have a problem binding data with angular.
My model:
<div id="ng-app-MyApp">
<ng-view></ng-view>
</div>
controller:
angular.module("MyApp.controllers", []).
controller("myController", function($scope, service) {
$scope.someprop = "12";
$scope.nameFilter = "text here";
$scope.val = "";
setTimeout(function() {
$scope.val = "321";
}, 1000);
$.when(service.getItems()).done(function (items) {
console.log(items.length);
$scope.someprop = "hello";
});
});
index.html:
<div>
<input type="text" ng-model="nameFilter" />
<div>{{nameFilter}}</div>
<table>
<tr>
<td>{{someprop}}</td>
<td>{{val}}</td>
</tr>
</table>
</div>
I use manual binding (angular.bootstrap($("#ng-app-MyApp")[0], ["MyApp"]);
). service.getItems()
returns jQuery deferred object.
When page loads, I expect that value of someprop
become "hello" and val
will be equals to "321". But actually nothing happens. When I start typing into textbox, then data binding is performed and I can see that someprop="hello" and val="321" on UI.
I can't figure out, why this properties are not updated automatically, but only when I start typing into textbox?
Upvotes: 1
Views: 84
Reputation: 2972
Both items aren't being set because they have missed the digest. Everything you want to use databinding with must be done with a service.
To override this here's what you need to do:
setTimeout(function() {
$scope.$apply(function () {
$scope.val = "321";
});
}, 1000);
$.when(service.getItems()).done(function (items) {
console.log(items.length);
$scope.$apply(function () {
$scope.someprop = "hello";
});
});
Upvotes: 0
Reputation: 34207
add $scope.$apply()
$.when(service.getItems()).done(function (items) {
console.log(items.length);
$scope.someprop = "hello";
$scope.$apply();
});
You need to call it because you are handling the callback outside of angular's framework (jquery) and the event of refreshing the dependencies does not get raised.
$apply
is the function that 'reloads/refreshes' the bindings
if possible, i recommend you to try avoiding jQuery in your angular code
if service.getItems()
is a simple ajax request, use $http
angular's service instead of jQuery and edit your custom service like this:
service:
...
service.getItems = function()
{
return $http.get('<url>');
};
...
controller:
service.getItems()
.success(function(data)
{
console.log(items.length);
$scope.someprop = "hello";
});
note that using pure angular, you don't need to add $apply()
Upvotes: 1
Reputation: 8465
You miss the $digest process which is responsible for two-way data binding in angularjs (although why do you bother to use jQuery for promises when you can achieve exactly the same with pure angularjs)
to avoid that you can do it several ways
$.when(service.getItems()).done(function (items) {
console.log(items.length);
$scope.apply(function(){
$scope.someprop = "hello";
})
});
$.when(service.getItems()).done(function (items) {
console.log(items.length);
$timeout(function(){
$scope.someprop = "hello";
})
});
$.when(service.getItems()).done(function (items) {
console.log(items.length);
$scope.someprop = "hello";
$scope.$digest()
});
although the last one is a bit tricky, if the app is big and digest happens more often it might throw an error digest already in progress
Upvotes: 1