188

我有一个网页用作单个实体的编辑器,它位于 $scope.fieldcontainer 属性中的深度图。从我的 REST API(通过 $resource)获得响应后,我将手表添加到“fieldcontainer”。我正在使用这款手表来检测页面/实体是否“脏”。现在我正在让保存按钮弹跳,但我真的想让保存按钮不可见,直到用户弄脏模型。

我得到的是手表的单个触发器,我认为这是因为 .fieldcontainer = ... 分配在我创建手表后立即发生。我正在考虑只使用“dirtyCount”属性来吸收最初的误报,但这感觉非常hacky......我认为必须有一种“Angular 惯用”的方式来处理这个问题 - 我不是唯一的一个使用手表检测脏模型。

这是我设置手表的代码:

 $scope.fieldcontainer = Message.get({id: $scope.entityId },
            function(message,headers) {
                $scope.$watch('fieldcontainer',
                    function() {
                        console.log("model is dirty.");
                        if ($scope.visibility.saveButton) {
                            $('#saveMessageButtonRow').effect("bounce", { times:5, direction: 'right' }, 300);
                        }
                    }, true);
            });

我只是一直在想,除了用“if (dirtyCount >0)”来保护我的“UI弄脏”代码之外,还有一种更清洁的方法来做到这一点......

4

5 回答 5

489

第一次调用侦听器时,旧值和新值将相同。所以只需这样做:

$scope.$watch('fieldcontainer', function(newValue, oldValue) {
  if (newValue !== oldValue) {
    // do whatever you were going to do
  }
});

这实际上是 Angular 文档推荐的处理方式

在观察者注册到作用域后,监听器 fn 被异步调用(通过 $evalAsync)来初始化观察者。在极少数情况下,这是不可取的,因为当 watchExpression 的结果没有改变时调用了侦听器。要在侦听器 fn 中检测这种情况,您可以比较 newVal 和 oldVal。如果这两个值相同(===),则由于初始化而调用了侦听器

于 2013-09-20T11:23:59.910 回答
120

在初始加载之前设置一个标志,

var initializing = true

然后当第一个 $watch 触发时,执行

$scope.$watch('fieldcontainer', function() {
  if (initializing) {
    $timeout(function() { initializing = false; });
  } else {
    // do whatever you were going to do
  }
});

该标志将在当前摘要周期结束时被拆除,因此不会阻止下一个更改。

于 2013-06-05T21:57:52.907 回答
44

我意识到这个问题已经得到解答,但是我有一个建议:

$scope.$watch('fieldcontainer', function (new_fieldcontainer, old_fieldcontainer) {
    if (typeof old_fieldcontainer === 'undefined') return;

    // Other code for handling changed object here.
});

使用标志是可行的,但你不觉得有一点代码味道吗?

于 2014-05-07T23:55:25.453 回答
4

在初始加载当前值期间,旧值字段未定义。因此,下面的示例可帮助您排除初始加载。

$scope.$watch('fieldcontainer', 
  function(newValue, oldValue) {
    if (newValue && oldValue && newValue != oldValue) {
      // here what to do
    }
  }), true;
于 2016-08-03T21:58:52.723 回答
3

只需验证新 val 的状态:

$scope.$watch('fieldcontainer',function(newVal) {
      if(angular.isDefined(newVal)){
          //Do something
      }
});
于 2015-05-04T14:58:43.820 回答