AngularJS - 同步触发$ watch

时间:2013-06-12 12:38:52

标签: javascript angularjs

$watch要更改对象并设置$scope.changed = true,但有些情况下,我想在以编程方式更改数据后立即将其设置为false:< / p>

$scope.$watch('data', function() {
    $scope.changed = true;
}, true);

function loadData(data) {
    $scope.data = data;

    // I want to run $scope.$apply() here so the $watch is triggered
    // before changed is set back to false
    $scope.$apply();

    $scope.changed = false;
}

// in DOM:
<div ng-click="loadData(newData)">

如果我使用非角度事件手动运行loadData它可以正常工作(当然后来再次$apply范围),但如果我从上面的{{1}中运行它然后它出现错误,“$ apply has in progress”。

在大多数情况下使用ngClick可以正常工作,但在某些地方我真的希望它同步发生。

$timeout

是否可以同步应用范围更改,或者我是否更改处理错误?

感谢。

3 个答案:

答案 0 :(得分:3)

如果您没有做一些非常特别的事情,可以使用angular.equals检查两个对象是否相等。将其与angular.copy结合使用,即可获得原始数据的副本。

$scope.isDirty = function () {
    return !angular.equals(initialData, $scope.data);
}

Plunker

这样做,您无需担心$watch功能的顺序,代码也会更容易理解。

性能方面,这可能会更重。您可以通过更改来优化它,以便在更改数据时仅更改isDirty。

答案 1 :(得分:0)

ngclick将占用$apply处理程序,因此您无法在事件处理函数中运行需要$apply的进程,只需$timeout函数中的所有操作:

function loadData(data){
    $timeout(function(){
        $scope.data = data;
        $scope.$apply();
        $scope.changed = false;
    });
}

试试这个,但没有经过测试......

答案 2 :(得分:0)

您可以使用第二个$scope变量来跟踪更改是否来自特定功能,并根据该变量启用$scope.changed中的$watch变量分配。

添加变量以充当loadData()功能中的标记。在这种情况下,我们将其称为$scope.explicitChange

function loadData(data) {
    $scope.data = data;

    // I want to run $scope.$apply() here so the $watch is triggered
    // before changed is set back to false
    $scope.$apply();

    $scope.changed = false;
    $scope.explicitChange = true;
}

检查$scope.explicitChange中是否设置了$watch

$scope.$watch('data', function(){
    if(!$scope.explicitChange){
        $scope.changed = true;
    }
    else{
        // Reset $scope.explicitChange
        $scope.explicitChange = false;
    }
}, true);