AngularJS1 指令隔离作用域中的双向绑定模型数据不能及时更新

阅读 3.8k
5 个回答

clipboard.png

这个应该是你想要的效果吧?其实解决方式很简单,在 index.html 里面把 $scope.currentPageNo = 1 改成 $scope.current = { pageNo: 1 }

当然,相应地:

$scope.toSearch = function(){
    console.log('To search ' + $scope.current.pageNo);
};
<div simple-pagination total-items="pager.totalItems" items-per-page="pager.itemsPerPage" max-items-num="pager.maxItemsNum" current="current" change-page-no="toSearch()"></div>

另外 directive 定义部分也要改:

scope: {
    totalItems: '=totalItems',
    itemsPerPage: '=itemsPerPage',
    maxItemsNum: '=maxItemsNum',
    current: '=current',
    changePageNo: '&changePageNo'
},

读完 AngularJS 的官方 wiki 就明白了:https://github.com/angular/an...

讲道理,楼上说到的,用 $watch 或者 $timeout 之类的应该也行,但恐怕不是最好的写法。


我个人觉得,这是 JavaScript 中传值方式导致的。。你可以考虑下,JS 中这段代码输出的是啥:

function update(a, b, c)
{
  a = a * 2;
  b.value = 2;
  c = {value: 2};
}

var num = 10;
var foo = {value: 1};
var bar = {value: 1};

update(num, foo, bar);

console.log(num);
console.log(foo.value);    
console.log(bar.value);

//output: 
// 10
// 2
// 1

numbar 都没有变。印象中,这种传值方式应该符合 pass by sharing: https://en.wikipedia.org/wiki...
不过我一直的理解是:primitive value 是 pass by value的,而 Object 就是 pass by reference我知道这样说可能不够确切。。

这里的 update 可以近似的理解为 AngularJS 中的 $scope.$apply(),是由 $watch 检测到 $dirty 的情况下触发的。foo.value 相当于我的写法里面的 current.pageNo,当然这个 current$scope 上的一个属性。num 相当于你的写法里面的 $scope.currentPageNo

所以这时候,我们需要的是直接把 current 这个 Object 按照引用(Pass by reference)的方式传进来,而不是把 Object 里面的某一个属性按照值传递(Pass by value)的方式传进来。


试着帮你分析一下,从点击到输出 console log 的过程:

  1. 点击了页码,ng-click 的绑定使得 directive 中的 changeCurrentPageNo() 这个方法触发

  2. 触发后,directive 的 scope.currentPageNo 会更新,但这一步并不会让 parent 更新

  3. 然后你调用了来自父级的方法 changePageNo(),这时候父级只知道你调用了 changePageNo 这个方法,然而并不知道 currentPageNo 已经在 directive 中改变。确切一点儿说,你改的是值本身,而不是改了引用。请参考上面例子中的 bar 情况。所以,这时候只有 directive 内部知道,而父级不知道

  4. 这时候,"digest loop" 得到了第一步触发,启用了 $watch(当然也会触发 dirty 检查)。但由于父级上的值并没有改变,你在 console.log 的时候,还是原来的值。既然也没监测到变化,当然,页面上的数据也是不会更新的

  5. directive 执行完毕,触发 $apply,这时候 currentPageNo 终于得到了更新,父级的也更新了,但这个发生的太晚,你已经看不到了。不过,你在下一次调用的 changePageNo 的时候,console log 才会输出这一次的值,然后又把它更新到了一个新的值

不知道这样分析是否正确。

$timeout(function(){

$scope.xxx = xxx

}, 0)
原因在于调用第三方方法,angular不能捕捉到变化

试试$watch这个函数,手动刷新

在link里面注册$watch

调用外部方法后,要数据同步,需要手工执行 $scope.$digest(). 或者 将执行部分放在 $scope.$apply()方法内 来使Angular触发脏检查.

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题