什么时候手动调用$apply()方法?

如果AngularJS总是将我们的代码wrap到一个function中并传入$apply(),以此来开始一轮$digest循环,那么什么时候才需要我们手动地调用$apply()方法呢?实际上,AngularJS对此有着非常明确的要求,就是它只负责对发生于AngularJS上下文环境中的变更会做出自动地响应(即,在$apply()方法中发生的对于models的更改)。AngularJS的built-in指令就是这样做的,所以任何的model变更都会被反映到view中。但是,如果你在AngularJS上下文之外的任何地方修改了model,那么你就需要通过手动调用$apply()来通知AngularJS。这就像告诉AngularJS,你修改了一些models,希望AngularJS帮你触发watchers来做出正确的响应。

比如,如果你使用了JavaScript中的setTimeout()来更新一个scope model,那么AngularJS就没有办法知道你更改了什么。这种情况下,调用$apply()就是你的责任了,通过调用它来触发一轮$digest循环。类似地,如果你有一个指令用来设置一个DOM事件listener并且在该listener中修改了一些models,那么你也需要通过手动调用$apply()来确保变更会被正确的反映到view中。

让我们来看一个例子。加入你有一个页面,一旦该页面加载完毕了,你希望在两秒钟之后显示一条信息。你的实现可能是下面这个样子的:

HTML:

<body ng-app="myApp">
<div ng-controller="MessageController">
Delayed Message: {{message}}
</div>
</body>

JavaScript:

/* What happens without an $apply() */

    angular.module(‘myApp‘,[]).controller(‘MessageController‘, function($scope) {

      $scope.getMessage = function() {
setTimeout(function() {
$scope.message = ‘Fetched after 3 seconds‘;
console.log(‘message:‘+$scope.message);
}, 2000);
} $scope.getMessage(); });

通过运行这个例子,你会看到过了两秒钟之后,控制台确实会显示出已经更新的model,然而,view并没有更新。原因也许你已经知道了,就是我们忘了调用$apply()方法。因此,我们需要修改getMessage(),如下所示:

/* What happens with $apply */
angular.module(‘myApp‘,[]).controller(‘MessageController‘, function($scope) { $scope.getMessage = function() {
setTimeout(function() {
$scope.$apply(function() {
//wrapped this within $apply
$scope.message = ‘Fetched after 3 seconds‘;
console.log(‘message:‘ + $scope.message);
});
}, 2000);
} $scope.getMessage(); });

如果你运行了上面的例子,你会看到view在两秒钟之后也会更新。唯一的变化是我们的代码现在被wrapped到了$scope.$apply()中,它会自动触发$rootScope.$digest(),从而让watchers被触发用以更新view。

Note:顺便提一下,你应该使用$timeout service来代替setTimeout(),因为前者会帮你调用$apply(),让你不需要手动地调用它。

而且,注意在以上的代码中你也可以在修改了model之后手动调用没有参数的$apply(),就像下面这样:

$scope.getMessage = function() {
setTimeout(function() {
$scope.message = ‘Fetched after two seconds‘;
console.log(‘message:‘ + $scope.message);
$scope.$apply(); //this triggers a $digest
}, 2000);
};

以上的代码使用了$apply()的第二种形式,也就是没有参数的形式。需要记住的是你总是应该使用接受一个function作为参数的$apply()方法。这是因为当你传入一个function到$apply()中的时候,这个function会被包装到一个try…catch块中,所以一旦有异常发生,该异常会被$exceptionHandler service处理。

随机推荐

  1. Python3: Windows系统上同时安装Python2和Python3

    Python3: Windows系统上同时安装Python2和Python3 为什么要同时安装Python2和Python3环境呢? 因为一些库只支持Python2或者Python3; 在同一台电脑上 ...

  2. 07:urllib与urllib2基本使用

    参考博客:https://blog.csdn.net/chendong_/article/details/51973499 1.1 urllib2发送get请求 # -*- coding:UTF-8 ...

  3. IDEA中使用.ignore插件忽略不必要提交的文件

    使用的IDE是IntelliJ IDEA,发现IDEA在提交项目到本地仓库的时候,会把.idea文件夹中的内容也提交上去,这里面放的是一些项目的配置信息,包括历史记录,版本控制信息等.可以不传到Git ...

  4. Linq join right join left join

    代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...

  5. 啤酒和饮料|2014年蓝桥杯B组题解析第一题-fishers

    啤酒和饮料|2014年第五届蓝桥杯B组题解析第一题-fishers 啤酒和饮料 啤酒每罐2.3元,饮料每罐1.9元.小明买了若干啤酒和饮料,一共花了82.3元. 我们还知道他买的啤酒比饮料的数量少,请 ...

  6. 32位MD5加密补齐丢失的0

    /// <summary> /// 获取32位MD5加密字符串(已补完0) /// </summary> /// <param name="strWord&qu ...

  7. HDU3652 B-number(数位DP)题解

    思路: 这里的状态分为3种,无13和末尾的1,无13且末尾为1,有13,然后DFS 等我搞清楚数位DP就来更新Orz 代码: #include<iostream> #include< ...

  8. 【旧版本】Ubuntu 14.04 下 P416编译器 p4c的安装

    注:此为2017年5月份的安装方法,最新的p4c安装方法见: Ubuntu14.04下 安装p4c 参考: p4c README Ubuntu 14.04 下 P4v16编译器 p4c的安装 系统要求 ...

  9. 查找SQL Server 自增ID值不连续记录

    在很多的时候,我们会在数据库的表中设置一个字段:ID,这个ID是一个IDENTITY,也就是说这是一个自增ID.当并发量很大并且这个字段不是主键的时候,就有可能会让这个值重复:或者在某些情况(例如插入 ...

  10. Thunder团队--Alpha发布用户报告

    用户数量:12人 以下为用户评论:(注:为了保护用户的姓名权,以下用户名以昵称形式给出.) 用户名(昵称) 用户使用频次 用户评论(以图片展示) 小王 3次 米线 2次 孔小姐 5次 乌乌鸟 2次 永 ...