How to call multiple functions / chain of calls using ng-click

Hi I have a button that launches two functions. Is there a way for updateDetails to only run after changeColor has finished? Currently updateDetails is pulling the old config with the old color, not the changed color.

ng-click="changeColor(color.code); updateDetails()"

      

Here's a view:

<div ng-controller="ColorsCtrl">
  <div ng-controller="HeaderCtrl">
    <div byo-header>
    </div>

    <div ng-repeat="color in colors" class="row">
      <div class="small-12 columns">
            <div ng-controller="ButtonsController">
                <div class="button-group">
              {{ isSelected(color.code) }}
                <button ng-click="changeColor(color.code); updateDetails()" type="radio" class="button" ng-model="selectedColor" btn-radio="color.code">{{color.name}}</button>
            </div>
            </div>  
      </div>
    </div>
    <br/>
    <br/>
    <div class="row">
        <div class="small-4 small-offset-4 columns">
        <!-- Proceed to packages if available -->
            <a ng-if="hasPackage" href="#/packages/{{modelCode}}" class="button">Packages</a>
        <!-- Proceed to options if packages not available -->
        <a ng-if="!hasPackage" href="#/options/{{modelCode}}" class="button">Options</a>
        </div>
    </div>    
  </div>
</div>

      

Here's the value for changeColor () in ColorsCtrl:

$scope.changeColor = function(newColorCode){
        //swap previous selected color with new
        configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
            $scope.configuration = configuration;               
        });

    }

  }

      

Here is the updateDetails in HeaderCtrl

    $scope.updateDetails = function(){
        $scope.summaryDetails = getSummaryDetails();
    }

      

+3


source to share


2 answers


Technically, you could write inline on the condition that it changeColor

returns a promise and your service call should return a promise (which is better compared to the traditional looping around callbacks).

First change your service to return a promise like: -

 function configuratorService($http){
      this.addOption = function(modelCode, colorCode){
          return $http.post("Addoption", {modelCode:modelCode, colorCode:colorCode})
                 .then(function(response){ 
                   //logic to get configuration or whatever
                   return response.data
          });
     }
  }

      

In ColorsCtrl:

$scope.changeColor = function(newColorCode){
     //return promise   
    return configuratorService.addOption($scope.modelCode, newColorCode)
         .then( function(configuration){
            $scope.configuration = configuration;     
            /*You could even return the data by doing the following*/          
            //return $scope.configuration = configuration;
        });
    }
 }

      

In HeaderCtrl:

$scope.updateDetails = function(){//<-- if you are returning data from changeColor you could even use it here
    $scope.summaryDetails = getSummaryDetails();
}

      

and finally in your opinion:

ng-click="changeColor(color.code).then(updateDetails)"

      

Demo example



angular.module('app', []).controller('HeaderCtrl', function($scope) {
  $scope.updateDetails = function() {
    //check the console
    console.log('UpdateDetails');
    $scope.summaryDetails = "Summary Details after option changeColor";
  }
}).controller('ColorsCtrl', function($scope, configuratorService) {
  $scope.changeColor = function(newColorCode) {
    //swap previous selected color with new
    return configuratorService.addOption().then(function(configuration) {
      //check the console
      console.log('Option Added');
      $scope.configuration = configuration;
    });
  }
}).service('configuratorService', function($timeout) {
  this.addOption = function() {
    //Justa proxy for an ansyn operation and return call
    return $timeout(function() {
      return "Color Updated"
    }, 1000);
  }
});
      

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">

  <div ng-controller="ColorsCtrl">
    <div ng-controller="HeaderCtrl">

      <button ng-click="changeColor().then(updateDetails)">Update</button>
      {{summaryDetails}}
    </div>
  </div>
      

Run codeHide result


There are many other options and better ways to do this. One is presented in TymeJV's answer: The problem is that your controllers are tightly coupled and can affect reuse, and you will need to do additional layouts to add a non-existent method updateDetails

during testing ColorsCtrl

.

Although this approach in my answer has its own problem, because now your opinion should know something (that the method returns a promise) that it shouldn't. There are other ways to better deal with this scenario, one simple approach is to use eventing or the pub / sub pattern that notifies another controller that something has happened here, do whatever you want to do. This design will make it more loosely coupled and more reusable and testable.

You can only use the angular event bus like $ broadcast or $ emit as applicable, combined with $ on to accomplish this task, or you can create a pub / sub design .

With a simple event, you simply do the following: -

In ColorsCtrl:

    $scope.changeColor = function(newColorCode){
        configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
            $scope.configuration = configuration;
            //BroadCast an event, this will notify any child scopes that has subscribed to this event.   
            $scope.$broadCast("Configuration_Udpated");                           
          });
       }
   }

      

In HeaderCtrl, subscribe to the event and register the updateDetails method:

//....
$scope.updateDetails = function(){
    $scope.summaryDetails = getSummaryDetails();
}


//...
$scope.$on("Configuration_Udpated", $scope.updateDetails)

      

Note: - Try using promises rather than passing callbacks to the service. You can find many articles online regarding promise templates .

+4


source


Since changeColor

- the async operation is not, you cannot wait for a row. You will need to call the function in the callback:

$scope.changeColor = function(newColorCode){
    //swap previous selected color with new
    configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
        $scope.configuration = configuration;  
        $scope.updateDetails();             
    });
}

      



If this function is used else, where you don't always want to call the update, pass the param parameter:

$scope.changeColor = function(newColorCode, shouldUpdate){
    //swap previous selected color with new
    configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
        $scope.configuration = configuration;  
        if (shouldUpdate) $scope.updateDetails();             
    });
}

ng-click="changeColor(color.code, true);"

      

+6


source







All Articles