Как отслеживать источник обновлений модели $watch в AngularJS?

В моем многопользовательском приложении AngularJS у меня есть объект модели в моей области. Эта модель может управляться как с помощью ввода пользователем, так и с сервера.

У меня есть наблюдатель $watch для отслеживания модели и обновления пользовательского интерфейса. Можно ли определить источник/причину моего обновления модели из моей функции $watch? Без этой проверки у меня проблемы с циклами обратной связи (например, UI → Server → UI).

ОБНОВЛЕНИЕ: некоторый код

Контроллер:

$scope.elementProperties = { left: 0 };

$scope.$watch('elementProperties.left', function(newVal, oldVal) { changeSelectedElementProperty('left', newVal, oldVal); } );

Директива

angular.module('myapp.ui-editor').directive('myappPropertiesPanel', function () {
    return {
        templateUrl: 'views/ui-editor/myappPropertiesPanel.html',
        restrict: 'A',
        scope: { elementProperties: '=' },

        link: function postLink (scope, element, attrs) {
            scope.$watch('elementProperties.left', function(newVal, oldVal) { console.log('PropertiesPanel change left', newVal, oldVal); } );
        }
    };
});

Ответ 1

Одним из способов достижения этого является использование событий вместо $watch

Смотрите рабочий плукер здесь

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

Вот что вы можете сделать.

В обработчике then вашего HTTP-вызова перед установкой нового значения, полученного из веб-службы, в модель, опубликуйте событие с полезной нагрузкой, содержащей старое значение и новое значение, как показано ниже:

$http.get('url goes here')
 .then(function (response) {
     scope.$broadcast('UPDATE_FROM_SERVER',
                      {oldValue: scope.elementProperties.left, newValue: response.data.left});
     scope.elementProperties.left = response.data.left;
  };

Затем в вашем элементе управления формы, где пользователь изменит значение, прикрепите ng-click, как показано ниже:

ng-change="userChangeHandler(elementProperties.left, '{{elementProperties.left}}')

Обратите внимание на цитаты вокруг '{{elementProperties.left}}'. Это гарантирует, что функция обработчика изменений получит старое значение свойства.

Теперь вы можете прослушивать эти события изменений, как показано ниже:

  $scope.$on('UPDATE_FROM_SERVER', function (event, changes) {
    // This code will be invoked when the data is changed by the server
    $scope.messages.push('Data changed by Server from ' + changes.oldValue + ' to ' + changes.newValue);
  });

  $scope.$on('UPDATE_FROM_USER', function (event, changes) {
    // This code will be invoked when the data is changed by the user
    $scope.messages.push('Data changed by User from ' + changes.oldValue + ' to ' + changes.newValue);
  });

Ответ 2

Вы должны попытаться отделить логику, которая происходит при вводе пользователя и обновлении сервера.

Один из способов сделать это - заставить часы всегда обновлять модель пользовательского интерфейса. На стороне IU используйте ng-model и ng-change. Например.

<input ng-model="myModel" ng-change="watchMyModel(myModel)">

Таким образом, когда вы нажмете на свою функцию $scope.watchMyModel, вы узнаете, что изменения произошли из исходного кода.