Javascript 如何在AngularJS中跟踪$watch模型更新的来源?

Javascript 如何在AngularJS中跟踪$watch模型更新的来源?,javascript,angularjs,angularjs-scope,Javascript,Angularjs,Angularjs Scope,在我的多用户AngularJS应用程序中,我的作用域上有一个模型对象。此模型可以通过用户输入和服务器更新进行操作 我有一个$watch observer来跟踪模型并更新UI。是否可以从my$watch函数中确定模型更新的来源/原因?如果没有该检查,我的反馈循环(例如UI)就会出现问题→服务器→用户界面) 更新:一些代码 控制器: $scope.elementProperties = { left: 0 }; $scope.$watch('elementProperties.left', fun

在我的多用户AngularJS应用程序中,我的作用域上有一个模型对象。此模型可以通过用户输入和服务器更新进行操作

我有一个$watch observer来跟踪模型并更新UI。是否可以从my$watch函数中确定模型更新的来源/原因?如果没有该检查,我的反馈循环(例如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); } );
        }
    };
});

您应该尝试将用户输入和服务器更新时发生的逻辑解耦

一种方法是让$watch始终更新UI模型。在IU端,使用ng模型和ng更改。例如

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


这样,当您点击$scope.watchMyModel函数时,您将知道更改来自后端

实现这一点的一种方法是使用事件而不是
$watch

在我的plunker中,我加入了一个
$interval
,它将通过每隔几秒钟更改一次值来模拟web服务调用

这是你能做的

在http调用的
then
处理程序中,在将从web服务检索的新值设置为模型之前,发布一个包含旧值和新值的有效负载的事件,如下所示:

$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-change="userChangeHandler(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);
  });
然后,在表单控件中,用户将在其中更改值,附加一个
ng单击
,如下所示:

$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-change="userChangeHandler(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);
  });
注意
'{{elementProperties.left}}'
周围的引号。这将确保ChangeHandler函数将获得属性的旧值

现在,您可以收听以下更改事件:

$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-change="userChangeHandler(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);
  });
“是否可以从my$watch函数中确定模型更新的来源/原因?”


简而言之,答案是否定的。当观察者测试oldWatchedValue===newWatchedValue并发现其未通过相等性检查时,不可能知道更改的来源,因为更改在更改时未标记,而是在以下摘要上标记。因此,没有什么可以约束这样一个事实,即更改的来源发生了更改。

当数据来自服务器/ui时,您不能只设置一些标志吗?您可以提供示例吗?标志有意义,或者使用广播事件可能有助于或在elementProperties上设置一个新属性,其中包含最后一个更改源,但如何从UI(例如
myappPropertiesPanel
指令)检测是否发生了更改
scope.$watch
似乎按照它们发出的顺序触发,因此控制器
$watch
语句在指令发出之前触发。