简体   繁体   English

AngularJS $ watch - 无限循环

[英]AngularJS $watch - infinite loop

I have 2 dates - start and end. 我有2个日期 - 开始和结束。 I want to validate (and re-assure) start < end. 我想验证(并重新确保)开始<结束。 I get notified they change using $watch, and then I go and change them to make sure the condition is met, but then it triggers the $watch again and then I get max iterations reached of $digest and things go south. 我收到通知,他们使用$ watch更改,然后我去更改它们以确保满足条件,但然后它再次触发$ watch然后我得到$ digest达到最大迭代次数。

So my question is - how do I change variables that are watched inside the $watch without causing infinite cycle. 所以我的问题是 - 如何更改$watch内观察的变量而不会导致无限循环。 (Aside from having more checks and changing them only if they actually needs to be changed) (除了有更多检查并且只有在实际需要更改时才更改它们)

Here is my code: 这是我的代码:

var TIME_DAY = 1000 * 60 * 60 * 24;

$scope.$watch('timeFilter.startTime', function () {
    validateStartEndTime();
},true);

$scope.$watch('timeFilter.endTime', function () {
    validateStartEndTime();
},true);

function validateStartEndTime() {
    if ($scope.timeFilter.startTime != null && $scope.timeFilter.endTime != null) {
        // Remove all seconds
        if ($scope.timeFilter.startTime.getSeconds() > 0)
            $scope.timeFilter.startTime.setSeconds(0);
        if ($scope.timeFilter.endTime.getSeconds() > 0)
            $scope.timeFilter.endTime.setSeconds(0);
        if ($scope.timeRange.minTime.getSeconds() > 0)
            $scope.timeRange.minTime.setSeconds(0);
        if ($scope.timeRange.maxTime.getSeconds() > 0)
            $scope.timeRange.maxTime.setSeconds(0);

        // When start time isn't before end time
        if ($scope.timeFilter.startTime >= $scope.timeFilter.endTime) {
            // We want to increase end time by 1 minute, if possible - do it. Else - reduce start time by 1 minute
            if ($scope.timeFilter.endTime < $scope.timeRange.maxTime) {
                $scope.timeFilter.endTime.setMinutes($scope.timeFilter.startTime.getMinutes() + 1);
            } else {
                $scope.timeFilter.startTime.setMinutes($scope.timeFilter.startTime.getMinutes() - 1);
            }
        }

        // Start time before min time
        if ($scope.timeFilter.startTime < $scope.timeRange.minTime) {
            $scope.timeFilter.startTime = $scope.timeRange.minTime;
            if ($scope.timeFilter.endTime <= $scope.timeFilter.startTime) {
                $scope.timeFilter.endTime = $scope.timeFilter.startTime;
                $scope.timeFilter.endTime.setMinutes($scope.timeFilter.endTime.getMinutes() + 1);
            }
        }

        // End time after max time
        if ($scope.timeFilter.endTime > $scope.timeRange.maxTime) {
            $scope.timeFilter.endTime = $scope.timeRange.maxTime;
            if ($scope.timeFilter.startTime >= $scope.timeFilter.endTime) {
                $scope.timeFilter.startTime = $scope.timeFilter.endTime;
                $scope.timeFilter.startTime.setMinutes($scope.timeFilter.startTime.getMinutes() - 1);
            }
        }
    }
}

Honestly I would prefer to find a way to avoid to change a variable that is watched constantly. 老实说,我宁愿找到一种方法来避免改变一直被观察的变量。 But, if you really want, you could deregister your $watch function when you have to change your variables being watched and then re-register again the $watch function. 但是,如果你真的想要,你可以在必须更改被监视的变量时取消注册$ watch函数,然后再次重新注册$ watch函数。

To deregister a $watch function you just need to get the reference and invoke when you need. 要取消注册$ watch函数,您只需要获取引用并在需要时调用。

var myWatch = $scope.$watch('timeFilter.startTime', function () {
   validateStartEndTime();
},true);
myWatch(); // It will deregister it.

Bear in mind that sometimes when you first watch a variable, it will trigger automatically the function. 请记住,有时当您第一次看变量时,它会自动触发该功能。 My suggestion is to always make the check if the old variable is really changed. 我的建议是总是检查旧变量是否真的改变了。

var myWatch = $scope.$watch('timeFilter.startTime', function (newValue, oldValue) {
   if(newValue === oldValue){
      return;
   }
   validateStartEndTime();
},true);

I hope it works for you. 我希望这个对你有用。 Unfortunately I cannot test this code right now. 不幸的是,我现在无法测试此代码。

I combined the suggestions and advice from everyone who replied to something like this: 我结合了回复这样的人的建议和建议:

$scope.$watch('timeFilter.startTime', function(newValue, oldValue) {
    if (newValue === oldValue) return;
    validateStartEndTime();
}, true);

$scope.$watch('timeFilter.endTime', function(newValue, oldValue) {
    if (newValue === oldValue) return;
    validateStartEndTime();
}, true);

function validateStartEndTime(startChanged) {
    if ($scope.timeFilter.startTime == null || $scope.timeFilter.endTime == null) return;
    var tempStart = new Date($scope.timeFilter.startTime), tempEnd = new Date($scope.timeFilter.endTime);
    if ($scope.timeRange.minTime && $scope.timeRange.maxTime) {
        // Logic start

        // Logic ends

        if ($scope.timeFilter.startTime !== tempStart)
            $scope.timeFilter.startTime = tempStart;
        if ($scope.timeFilter.endTime !== tempEnd)
            $scope.timeFilter.endTime = tempEnd;
    }
}

This way I make sure I do as little changes as possible. 这样我确保尽可能少做一些改变。 I'm open to suggestions if anyone has any 如果有人有任何建议,我愿意接受建议

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM