angular开发过程中遇到的$apply问题
由于一直在项目上并吗使用过angular进行开发,目前会遇到一些比较弱智的问题,所以每次遇到耗时较多的问题都总结一下。
$apply问题
接到一个类似于dropdown这样的需求,点击按钮下拉选择展示,而它的关闭有3中场景。
目前处于展开状态,再次点击按钮,下拉隐藏。
点击里面的任一条件,下拉隐藏。
点击空白处,下拉隐藏。
相信这样的使用场景一定不陌生,因为他经常出现。
一开始的时候想象了一下jquery多么美好,实现起来多么简单,其实angular也很容易。
思路解析:
外层设置一个状态值,通过添加ngClass控制下拉是否显示。设想都是美好的,也通过测试这样没有问题。
实现过程:
1.html书写
<div class="content" ng-class="{'open': vm.open}"> <span class="show" ng-click="vm.toggle()">cilic me!</span> <div class="list"> <ul> <li class="item" ng-repeat="item in list" ng-click="vm.itemClick();">{{item.title}}</li> </ul> </div> </div>
2.css代码控制
.content .list{ display: block; } .content.open .list{ display: block; }
3.mock静态数据
vm.list = [ {title: '下拉选项1'},{title: '下拉选项2'},{title: '下拉选项3'},{title: '下拉选项4'},{title: '下拉选项5'} ];
4.点击按钮控制显示隐藏,我只需要控制open状态为true或false即可。
// 设置初始状态为不显示 vm.open = false; // 显示,关闭浮层 vm.toggle = function() { vm.open = !vm.open; };
5.点击任一下拉选择,隐藏。
vm.itemClick = function() { vm.ticketOpen = false; };
6.点击空白处,隐藏。
$document.off('click').on('click',function() { vm.open = false; });
看到这样的代码,你觉得有问题吗?反正我当时觉得自己一定是对的,但调试结果就是不生效,下拉怎么都不会隐藏。
通过断点调试,页面输出open的值,发现js中的open确实已经发生改变,但是页面的值确没有改变,然后联想到双向数据绑定失效。
谁决定什么事件进入angular context,而哪些又不进入呢?$apply!
这里声明一点ng-click不需要单独去做处理是因为angular已经做了,因此点击带有ng-click的元素时,事件就会被封装到一个$apply调用。
所以上面的问题也显而易见,是因为没有调用$apply,事件没有进入angular context,$digest循环永远没有执行。
so将code修为:
$document.off('click').on('click',function() { vm.open = false; $scope.$apply(); });
这样一测,立马有用了。
$apply是$scope的一个函数,调用它会强制一次$digest循环.
然后看到网上有人说有种更好用的办法,尝试了一下确实有效:
$document.off('click').on('click',function() { $scope.$apply(function () { vm.open = false; }); });
解释为:
原文链接:https://www.f2er.com/angularjs/149228.htmlWhat’s the difference?
The difference is that in the first version,we are updating the values outside the angular context so if that throws an error,Angular will never know.
ObvIoUsly in this tiny toy example it won’t make much difference,
but imagine that we have an alert Box to show errors to our users and we have a 3rd party library that does a network call and it fails.
If we don’t wrap it inside an $apply,Angular will never know about the failure and the alert Box won’t be there.