简体   繁体   中英

Angular $watch only triggered once with onclick

I have a function in an angular service containing an ajax call doing the following:

function performCall($scope){
   $scope.dataFail = false;

   var promise = doAjaxCall();
   promise.then(function(data){
      if(data.rootElement){
         //process...
      }else{
         $scope.dataFail=true;
      }
   }
}

And a $watch expression in my controller watching dataFail and displaying a dialog with an option to call performCall when the dialog is confirmed:

$scope.$watch('dataFail', function(dataFail){
    if(dataFail){
        //open dialog
        $( "#ajaxFailurePopup" ).dialog({
            zIndex: 3003,
            title: "Note:",
            modal:true, // Disable controls on parent page
            buttons: {
                Ok: {
                    text: 'Retry >',
                    "class" : 'ppButton floatRight',
                    click:
                      function() {
                                             service.performCall($scope);
                         $("#ajaxFailurePopup").remove();
                       }
                    }
                }
            });
        };
    });

This works fine on initialisation when the ajax call first fails. However, after this no changes made to dataFail are registered by the $watch . Does anybody have any suggestions?

Resolved by wrapping call to performCall in $scope.apply:

$scope.apply(
   service.performCall($scope);
)

The dataFail flag was being set in the performCall method. Apologies.

There are couple of problems with your code:

  1. In Angular, $watch expression callback function is called only if expression has changed the value. Since you're never resetting your 'dataFail' flag the expression never gets called in subsequent calls. You should set your flag variable to false inside the $watch expression.

  2. In dialog you are calling $("#ajaxFailurePopup").remove(); which removes the #ajaxFailurePopup element from the DOM, hence the dialog is unable to initialize again. You should use $('#ajaxFailurePopup').dialog('destroy');

Working plnkr: http://embed.plnkr.co/wcooiJ

Since you say that the watch fires on the first failed request, but no on subsequent failed requests, is it possible that you're not resetting $scope.dataFail to false for successful requests? If $scope.dataFail is only set to false during initialization, the value never changes and your watch won't get called. Setting $scope.dataFail to true if it´s already true won't fire the watch since Angular can't tell that it changed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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