Hi I have a button that fires off two functions like so. Is there a way for the updateDetails to run only after changeColor has finished? The updateDetails is currently pulling an old configuration with the old color, and not the changed color.
ng-click="changeColor(color.code); updateDetails()"
Here is the 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 is changeColor() in the ColorsCtrl:
$scope.changeColor = function(newColorCode){
//swap previous selected color with new
configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
$scope.configuration = configuration;
});
}
}
Here is updateDetails in the HeaderCtrl
$scope.updateDetails = function(){
$scope.summaryDetails = getSummaryDetails();
}
Hi I have a button that fires off two functions like so. Is there a way for the updateDetails to run only after changeColor has finished? The updateDetails is currently pulling an old configuration with the old color, and not the changed color.
ng-click="changeColor(color.code); updateDetails()"
Here is the 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 is changeColor() in the ColorsCtrl:
$scope.changeColor = function(newColorCode){
//swap previous selected color with new
configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
$scope.configuration = configuration;
});
}
}
Here is updateDetails in the HeaderCtrl
$scope.updateDetails = function(){
$scope.summaryDetails = getSummaryDetails();
}
Share
Improve this question
edited Jan 3, 2015 at 19:03
PSL
124k21 gold badges256 silver badges243 bronze badges
asked Dec 30, 2014 at 21:44
user3562751user3562751
2631 gold badge5 silver badges15 bronze badges
3
-
Technically you could write inline if your call returns a promise, what operation are you doing inside
configuratorService.addOption
? – PSL Commented Dec 30, 2014 at 22:11 - @PSL I am doing a put – user3562751 Commented Dec 30, 2014 at 22:19
- Instead of passing a callback if you return a promise from your service you could write it inline in the view. I can show an exmaple if you want. – PSL Commented Dec 30, 2014 at 22:21
2 Answers
Reset to default 6Since changeColor
is an async operation - no, you can't wait inline. You'd have 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 and you don't always want to call update, pass a flag param:
$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);"
Technically you could write inline provided changeColor
returns promise and inturn your service call must return a promise (which is better pared to traditional passing around callbacks anyways).
First change your service to return a promise, an example:-
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 view:
ng-click="changeColor(color.code).then(updateDetails)"
An example Demo
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./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>
There are many other options and better ways to do it. One provided in the TymeJV answer, the issue there is that your controllers bees tightly coupled with one another and could affect re-usability and you would need to do extra mocks to add the non existent method updateDetails
while testing ColorsCtrl
.
While this approach in my answer has its own problem because now your view needs to know something (that the method returns promise) which it should not. There are other ways to handle this scenario in a better way: One simple approach is to use eventing or a pub/sub pattern which notifies other controller that something has happened here do whatever you want to do. Such kind of design will make it more loosely coupled and more reusable and testable.
You can make use of angular event bus itself, like $broadcast or $emit as per applicability bined with $on ,to perform this task or you could create a pub/sub design yourself.
With simple eventing you would just do this:-
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 an event and register updateDetails method:
//....
$scope.updateDetails = function(){
$scope.summaryDetails = getSummaryDetails();
}
//...
$scope.$on("Configuration_Udpated", $scope.updateDetails)
Side note:- Try to make use of the promises rather than passing callbacks to the service. You can find a lot of articles on the web regarding promise patterns.