3

这是场景:

小提琴

$scope.$watch('obj.value',function(val, oldVal) {
    if (val === oldVal) return;
    MyService.update($scope.obj, $scope.result).then(function(response){
        $scope.results.push(response);
    }, function(response) {
        $scope.obj.value = oldVal;
         $scope.results.push(response);
    });
});

我在一个值上设置了一个手表,并在它发生变化时将其更新为 db。但是如果由于某种原因更新失败(连接问题、服务器错误、无效会话、权限不足等),我想将该值恢复到以前的版本。在小提琴中,您可以看到如果您选择“拒绝延迟”并尝试更改值会发生什么 - 它会启动失败请求、恢复值和 $watch 触发器的无限循环。

目前我正在范围上设置一个标志以指示请求失败并且下一个 $watch 不应调用该服务。但我正在寻找减少这种样板代码的方法。

当然,我总是可以使用其他一些方式来通知范围,例如 ng-change,但是我失去了对旧值的引用。我可以将参考保留在我的范围内,但这比目前的情况还要糟糕。

你有什么想法应该如何处理这些情况?基本上我正在寻找的是一种在 $watch 中更新模型而不触发进一步 $watches 的方法,如果这甚至可能的话。

4

3 回答 3

12

使用 ng-change 指令代替观察者,并使用内部状态变量来存储上次成功保存的值。

看看它在行动:http: //jsfiddle.net/Zmetser/vscGP/6/

function MyCtrl($scope, MyService) {
    var lastSaved;
    $scope.obj = {value: "foo"};
    $scope.results = [];
    $scope.result = "1";

    lastSaved = $scope.obj.value;

    $scope.sentinel = function ( value ) {
        MyService.update($scope.obj, $scope.result).then(function(response){
            lastSaved = angular.copy($scope.obj.value);
            $scope.results.push(response);
        }, function(response) {
            if ( lastSaved )
                $scope.obj.value = lastSaved;
            $scope.results.push(response);
        });
    };
}

<input type="text" ng-model="obj.value" ng-change="sentinel(obj.value)"/>
于 2013-06-04T12:02:25.167 回答
1

除了使用超时或 $timeout,您还可以使用闭包来封装您重置的布尔标志。

(function WatchWithRevert () {
    var justReverted = false;
    $scope.$watch('obj.value',function(val, oldVal) {
        //if (val === oldVal) return;
        if (justReverted) {
            justReverted = false;
            return;
        }
        MyService.update($scope.obj, $scope.result).then(function(response){
            $scope.results.push(response);
        }, function(response) {
            $scope.obj.value = oldVal;
            justReverted = true;
            $scope.results.push(response);
        });
    });
})();
于 2014-04-28T21:14:12.617 回答
0

基本上,你做对了。观察者观察被观察的对象,所以你能做的最好的事情就是告诉它闭上一只眼睛等待下一次观察。

您可以使用$timeout设置一个临时标志,以便尽快清理

_skipWatch = false

rollBackLocally = (newVal, oldVal) ->
  _skipWatch = true
  angular.copy oldVal, newVal
  # schedule flag reset just at the end of the current $digest cycle
  $timeout (-> _skipWatch = false), 0

$scope.$watch 'obj.value', (newVal, oldVal) ->
  return if _skipWatch
  MyService.doSomething().then 
    ((response) -> $scope.results.push(response)),
    (-> rollBackLocally newVal, oldVal)
于 2013-06-04T11:52:40.587 回答