it-swarm.com.ru

$ смотреть объект

Я хочу следить за изменениями в словаре, но по какой-то причине смотреть обратный вызов не вызывается.

Вот контроллер, который я использую:

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

    $scope.$watch('form', function(newVal, oldVal){
        console.log('changed');
    });
}

Вот скрипка .

Я ожидаю, что обратный вызов $ watch будет срабатывать при каждом изменении имени или фамилии, но этого не происходит.

Как правильно это сделать?

307
Vladimir Sidorenko

Вызовите $watch с true в качестве третьего аргумента:

$scope.$watch('form', function(newVal, oldVal){
    console.log('changed');
}, true);

По умолчанию при сравнении двух сложных объектов в JavaScript они проверяются на «ссылочное» равенство, которое спрашивает, ссылаются ли два объекта на одно и то же, а не на «значение», которое проверяет, являются ли значения всех свойств этих объектов объекты равны.

Согласно документации Angular , третий параметр предназначен для objectEquality:

Когда objectEquality == true, неравенство watchExpression определяется в соответствии с функцией angular.equals . Чтобы сохранить значение объекта для последующего сравнения, используется функция angular.copy . Следовательно, это означает, что просмотр сложных объектов будет иметь неблагоприятные последствия для памяти и производительности.

551
rossipedia

Объект 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++;
});
}
13
Jason

Небольшой совет по производительности если у кого-то есть сервис хранилища данных с ключом -> пары значений:

Если у вас есть служба с именем dataStore , вы можете обновлять timestamp всякий раз, когда ваш большой объект данных изменяется . Таким образом, вместо глубокого просмотра всего объекта, вы наблюдаете только временную отметку на предмет изменений.

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();
    }

});

И в директиве вы смотрите только метку времени, чтобы изменить

app.directive("myDir", function ($scope, dataStore) {
    $scope.dataStore = dataStore;
    $scope.$watch('dataStore.getChange("myKey")', function(newVal, oldVal){
        if(newVal !== oldVal && newVal){
            // Data changed
        }
    });
});
12
Ferenc Takacs

Причина, по которой ваш код не работает, заключается в том, что $watch по умолчанию выполняет проверку ссылок. Итак, в двух словах, убедитесь, что объект, который передается ему, является новым объектом. Но в вашем случае вы просто изменяете какое-то свойство объекта формы, а не создаете новое. Чтобы заставить его работать, вы можете передать true в качестве третьего параметра.

$scope.$watch('form', function(newVal, oldVal){
    console.log('invoked');
}, true);

Это будет работать, но вы можете использовать $ watchCollection, который будет более эффективным, чем $ watch, потому что $watchCollection будет следить за мелкими свойствами объекта формы. Например.

$scope.$watchCollection('form', function (newVal, oldVal) {
    console.log(newVal, oldVal);
});
4
sol4me

Поскольку вы ищете изменения объекта формы, лучший подход к просмотру заключается в использовании
$watchCollection. Пожалуйста, посмотрите в официальную документацию для различных характеристик производительности.

4
Ramesh Papaganti

Попробуй это:

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

    function track(newValue, oldValue, scope) {
        console.log('changed');
    };

    $scope.$watch('form.name', track);
}
1
Tarun

Для тех, кто хочет наблюдать за изменением объекта в массиве объектов, мне показалось, что это работает (как и другие решения на этой странице):

function MyController($scope) {

    $scope.array = [
        data1: {
            name: 'name',
            surname: 'surname'
        },
        data2: {
            name: 'name',
            surname: 'surname'
        },
    ]


    $scope.$watch(function() {
        return $scope.data,
    function(newVal, oldVal){
        console.log(newVal, oldVal);
    }, true);
0
Max