注意模型的变化

时间:2015-10-02 00:24:31

标签: javascript angularjs

我在指令的链接功能中有以下代码:

link: function (scope, elem, attrs, ngModel) {
        $(elem).datagrid({
            columns: [[
                { field: 'ck', checkbox: 'true' },
                { field: 'ProjectID', title: 'Project ID', width: '30%' },
                { field: 'Name', title: 'Name' }
            ]]                
        });
        ngModel.$render = function (value) {
            $(elem).datagrid('loadData', ngModel.$viewValue);
        };
        scope.$watch('projectList', function (newValue, oldValue) {
            $(elem).datagrid('loadData', ngModel.$viewValue);
        });

    }

当最初为Array $ scope.projectList分配数据时,两个侦听器都会被触发。我的控制器中的某个地方(仅用于测试)我在$ scope.projectList中添加了另一个元素:

$scope.test = function () {
    var project = $scope.projectList[0];
    $scope.projectList.push(project);
}

此时没有听众被解雇。有人可以解释为什么会这样吗?

由于

2 个答案:

答案 0 :(得分:2)

$watch仅检查projectList数组的引用是否已更改,它不会对集合执行深入监视。将数组分配给范围变量时,更改此引用,但随后修改此数组会使引用保持不变。在您的情况下,使用$watchCollection()方法似乎更合适。

值得注意的是,$watchCollection仅检查集合元素引用是否已更改,例如通过添加/删除/替换项目。它不会检查这些元素本身是否已被修改。

如果您希望对收藏品进行深入观察,请将true作为第三个参数传递给$watch()

scope.$watch('projectList', function (newValue, oldValue) {
    $(elem).datagrid('loadData', ngModel.$viewValue);
}, true);  // <--- note the objectEquality flag set to true

但是,请注意,如果集合中的项目很复杂并且需要更多时间来比较它们,这可能会对性能产生影响。

您还可以查看Angular docs的$ scope了解更多信息(向下滚动$watch()$watchCollection()方法说明)。

答案 1 :(得分:1)

这是因为普通的$ watch函数只是看引用相等,所以如果你做了这样的事情:

var project = $scope.projectList[0];
$scope.newProjectList = [];
$scope.newProjectList.push(project);
$scope.projectList = $scope.newProjectList;

然后它会触发你的手表因为$ scope.projectList的对象引用发生了变化。

如果你想要你的例子:

var project = $scope.projectList[0];
$scope.projectList.push(project);

要触发手表,那么你要么必须要做

scope.$watch('projectList', function (newValue, oldValue) {
    $(elem).datagrid('loadData', ngModel.$viewValue);
}, true);

(将$作为最后一个参数传递给$ watch会导致$ watch进行深度相等比较,对于大对象或大型列表,这可能会很慢)

OR

scope.$watchCollection('projectList', function (newValue, oldValue) {
    $(elem).datagrid('loadData', ngModel.$viewValue);
});

(这与普通$ watch在引用相等方面类似,但它特别针对列表。因此,在主要参考检查之上,它还对集合中的每个项目进行参考检查或者数组,所以它会触发像.push和.pop这样的东西

他们都有自己的优势,这取决于你正在寻找什么样的支票。另外,请记住$ watch返回一个取消注册函数,你可以用它来清除它,你通常会在范围内做。$ on('$ destroy'。如果不这样做,它们只会停留一段时间,如果你有很多,可能会流失。

这是一个很好的 article关于3种口味的手表之间的所有差异