今天学习angular的时候,我将对于数据定义和操作方法都放到service
里面,dom
操作当然是放到了directive
里面,然后碰到ng-repeat
视图不刷新的情况:
index.html
<ul ng-controller="MainController">
<li ng-repeat="book in books track by book.title">
<span>{{book.title}}</span>
<span>{{book.author}}</span>
</li>
<!--<button ng-click="add()">添加</button>-->
</ul>
<button add-book-button>Add Book</button>
directive.js
app.directive('addBookButton',function($_book){
return {
restrict: 'A',
link: function(scope, ele, attr){
ele.bind('click',function(){
$_book.service.addBook({title: 'Hello,world', name: 'XL'});
})
}
}
});
service.js
app.service('$_book',['$rootScope',function($rootScope){
this.service = {
books: [
{
title: 'Magician',
author: 'Raymood'
},
{
title: 'The Hobbit',
author: 'J.R.R Tolkien'
}
],
addBooks: function(book){
this.books.push(book);
$rootScope.broadcast('books.update');
}
}
}])
MainController.js
app.controller('MainController',function($scope){
$scope.books = $scope.service.books;
$scope.$on('books.update',function(){
$scope.books = $scope.service.books;
console.log($scope.books); //这里打印出来的是包含3个object的数组,但是view层只显示一开始页面刷新的2个object
})
})
出现的问题是MainController.js
里面注释的部分。
但是如果我在MainController.js
里面添加一个ng-click
事件,触发添加数组这个事件的话,在view层是会动态添加新object
的。
暂时没找到是什么原因导致这个情况的出现。
刚看到评论,又想了一下,的确有点跑题了,根本原因是books的修改是通过dom事件触发的,这已经脱离angular了,导致angular的watch无反应,因此需要在dom事件处理完毕后手动调用apply触发angular的脏检查,正确的解决办法应该是:
controller中的$apply是不需要的。
例子
-------------------------原答案------------------------
关键是这句话,你把scope的books对象跟service的books对象绑定到一起,ng-repeat也是绑定到同样的对象,换句话说这三个对象的引用是相同的,view的更新是伴随着脏检查的,而angular的脏检查有三种极致:
引用reference
集合collection
值value
区别直接从官网截张图吧:
同时注意通过reference watch的对象:
回到你的例子,books是通过reference进行watch的,这就意味着你对books数组里面内容的修改是不会导致脏检查。
明白这一点暴力的解决办法很简单:更新数据后通过调用
$scope.$apply("books")
手动触发angular的脏检查流程.例子
注意你在ng-repeat中设置了track为title,这意味着相同title的book会被认为重复,导致报错,所以我在新增book的时候添加了一个变量。另外,你的service方法名、方法体看着有点别扭,顺手改了下。