2015-09-03 1 views
3

J'ai 2 dates - début et fin. Je veux valider (et ré-assurer) commencer < fin. Je suis averti qu'ils changent en utilisant $ watch, puis je vais les changer pour m'assurer que la condition est remplie, mais ensuite il déclenche le $ watch à nouveau et ensuite j'obtiens des itérations maximum atteintes de $ digest et les choses vont au sud.

Donc, ma question est - comment puis-je changer les variables qui sont regardées à l'intérieur du $watch sans provoquer un cycle infini. (En plus d'avoir plus de contrôles et de les changer que si elles réellement besoin d'être changé)

Voici mon 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); 
      } 
     } 
    } 
} 
+0

simplement définir une variable de drapeau. Définissez le drapeau une fois que votre condition est vraie et n'autorisez une action que si l'indicateur n'est pas encore défini. –

+0

Je pense que vous serez mieux servi en utilisant des événements DOM enveloppés angulaires pour votre validation de date, comme 'ng-blur',' ng-change' ... – tiledcode

+0

Je voudrais aller avec une variable booléenne, par exemple. manualChange. Cela doit être défini sur false au début de validateStartEndTime. Ensuite, dans chaque montre, si manualChange est true, appelez validateStartEndTime, sinon définissez manualChange sur true et renvoyez. – dchar

Répondre

1

Honnêtement je préférerais trouver un moyen d'éviter de changer une variable regardé constamment. Mais, si vous le voulez vraiment, vous pouvez annuler l'enregistrement de votre fonction $ watch lorsque vous devez modifier les variables que vous regardez et réenregistrer ensuite la fonction $ watch.

Pour annuler l'enregistrement d'une fonction $ watch, il vous suffit d'obtenir la référence et de l'appeler lorsque vous en avez besoin. N'oubliez pas que lorsque vous regardez une variable pour la première fois, elle déclenche automatiquement la fonction. Ma suggestion est de toujours faire la vérification si l'ancienne variable est vraiment modifiée.

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

J'espère que cela fonctionne pour vous. Malheureusement, je ne peux pas tester ce code maintenant.

+0

La vérification de oldvalue === newvalue est super. Comment pourrais-je procéder à la radiation? J'appelle myWatch de l'intérieur de la montre $? Et puis quand est-ce que je le réinscris? – AlexD

+0

Vous vous enregistrez à nouveau après avoir modifié la variable qui n'a pas été regardée pendant un moment. – Daniele

0

je combine les suggestions et conseils de tous ceux qui ont répondu à quelque chose comme ceci:

$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; 
    } 
} 

De cette façon, je fais que je fais aussi peu de modifications que possible. Je suis ouvert aux suggestions si quelqu'un a