$观看一个物体

Vla*_*nko 313 javascript angularjs angularjs-scope

我想要查看字典中的更改,但由于某种原因,不会调用监视回调.

这是我使用的控制器:

function MyController($scope) {
    $scope.form = {
        name: 'my name',
        surname: 'surname'
    }

    $scope.$watch('form', function(newVal, oldVal){
        console.log('changed');
    });
}
Run Code Online (Sandbox Code Playgroud)

这是小提琴.

我希望每次更改名称或姓氏时都会触发$ watch回调,但不会发生.

这样做的正确方法是什么?

ros*_*dia 564

调用$watchtrue作为第三个参数:

$scope.$watch('form', function(newVal, oldVal){
    console.log('changed');
}, true);
Run Code Online (Sandbox Code Playgroud)

默认情况下,在比较JavaScript中的两个复杂对象时,将检查它们是否为"引用"相等,它会询问两个对象是否引用相同的东西,而不是"值"相等,它会检查这些属性的所有属性的值对象是平等的.

根据Angular文档,第三个参数用于objectEquality:

何时objectEquality == true,watchExpression的不等式是根据angular.equals函数确定的.要保存对象的值以供以后比较,请使用该angular.copy函数.因此,这意味着观看复杂对象将产生不利的记忆和性能影响.

  • 有.默认情况下,如果您没有传递"true",那么如果监视的值是对象或数组,它将检查引用相等性.在这种情况下,您应该明确指定属性,例如`$ scope.$ watch('form.name')`和`$ scope.$ watch('form.surname')` (16认同)
  • 谢谢.这正是我错过的.杰森,你是对的 - 你并不总是希望看到递归的物体,但就我而言,这正是我所需要的. (3认同)
  • 这是一个很好的答案,但我想有时候你不想递归地观察一个物体 (2认同)

Jas*_*son 13

form对象并没有改变,只是name属性

更新小提琴

function MyController($scope) {
$scope.form = {
    name: 'my name',
}

$scope.changeCount = 0;
$scope.$watch('form.name', function(newVal, oldVal){
    console.log('changed');
    $scope.changeCount++;
});
}
Run Code Online (Sandbox Code Playgroud)


Fer*_*acs 12

如果有人拥有带键 - >值对的数据存储类服务,则性能提示很少:

如果您有一个名为dataStore的服务,则可以在大数据对象发生更改时更新时间戳.这样,您只需要观察变化的时间戳,而不是深入观察整个对象.

app.factory('dataStore', function () {

    var store = { data: [], change: [] };

    // when storing the data, updating the timestamp
    store.setData = function(key, data){
        store.data[key] = data;
        store.setChange(key);
    }

    // get the change to watch
    store.getChange = function(key){
        return store.change[key];
    }

    // set the change
    store.setChange = function(key){
        store.change[key] = new Date().getTime();
    }

});
Run Code Online (Sandbox Code Playgroud)

在指令中,您只是在观察要更改的时间戳

app.directive("myDir", function ($scope, dataStore) {
    $scope.dataStore = dataStore;
    $scope.$watch('dataStore.getChange("myKey")', function(newVal, oldVal){
        if(newVal !== oldVal && newVal){
            // Data changed
        }
    });
});
Run Code Online (Sandbox Code Playgroud)


sol*_*4me 5

您的代码不起作用的原因是因为$watch默认情况下会进行引用检查。因此,简而言之,请确保传递给它的对象是新对象。但是在您的情况下,您只是在修改表单对象的某些属性,而不创建新属性。为了使其正常工作,您可以true作为第三个参数传递。

$scope.$watch('form', function(newVal, oldVal){
    console.log('invoked');
}, true);
Run Code Online (Sandbox Code Playgroud)

它将起作用,但是您可以使用$ watchCollection,它比$ watch效率更高,因为$watchCollection它将监视表单对象上的浅层属性。例如

$scope.$watchCollection('form', function (newVal, oldVal) {
    console.log(newVal, oldVal);
});
Run Code Online (Sandbox Code Playgroud)