每个接触angualrJS的前端工程师都会遇到这样一个问题,为什么model数据改变了,但是view也就是页面上却没有变化,比如发现设置了颜色,可是颜色没有变,设置了值改变,可是也没变,但是console.log()能看到数据已经改变了。
然后其他人就会说那就加上$scope.apply()吧,然后你就会很神奇地发现,页面上按照想要的样子改变了。
那么$scope.apply()究竟是做了什么?
angularJS通过watcher去监听model的变化,当监听到model数据改变时,就会触发$watcher去更新页面上视图的变化。
而$scope.apply()是调用了$digest(),就是angualrJS的脏检查(就是检测变化,变化了就脏了,和之前不同了。)
怎样正确调用$scope.apply()?
观察下面两个函数,上面的函数是普通的function,下面的是$scope的function,而上面的函数不能触发脏检查(angualrJS没有办法检测到值的变化),这是因为这个函数是在angularJS的监听范围之外的,所以没有去改变view。
function getMeterType() {
meterService.getMeterSubTypes(function (data) {
$scope.meterType = data;
if ($scope.meterType) {
$('.meterDevice a').eq(0).addClass("active");
}
})
}
$scope.changeMeterType = function (id, index) {
$('.meterDevice a').eq(index).addClass("active").siblings().removeClass("active");
}
这个时候就需要我们告诉angularJS,你需要做脏检查,需要更新页面的数据和样式了。
加上$scope.$apply()之后,就是告诉angularJS去检查变化的方式,就会触发$digest(),angular就会去检测变化,更新视图了。
function getMeterType() {
meterService.getMeterSubTypes(function (data) {
$scope.meterType = data;
if ($scope.meterType) {
$timeout(function () {
$('.meterDevice a').eq(0).addClass("active");
$scope.$apply();
});
}
})
}
为什么要调用$timeout()?
如果你调用apply的时候$digest正在执行,就会看到这样的报错。
$digest already in progress
而$timeout会隐性出发digest的执行,而且会延迟执行,会在上一个digest循环完成后的下一刻,触发digest,就可以完美避开上图的报错了。