It looks like this. I load my page and my form displays with values fetched. These values are being fetched by an http service. At the top of the form there is my custom directive (select box):
.directive('categorySelectBox', function(){
return {
restrict: "A",
replace: true,
scope: {
// all properties here need to be added to
// the directive in order to be picked up
taxonomies: '='
,chosen: '='
},
templateUrl: "ngapp/js/tpl/select-box.html"
};
})
the directive template:
<select class="form-control"
ng-options="option.label for option in taxonomies track by option.value"
ng-model="chosen"
chosen="chosen"
taxonomies="taxonomies">
<option value="">Please select a category</option>
My controller is like this:
.controller('DashboardCtrl', ['$scope', 'DbResourceSrv', function($scope, DbResourceSrv){
$scope.$watch('cid', function() {
$scope.formBusy = true;
$scope.c = DbResourceSrv.getDbResource('response.php', 'company', $scope.cid)
.then(function(data) {
$scope.c = data;
angular.forEach(data, function(value, key) {
$scope.c.push({key: value});
});
});
$scope.tax = DbResourceSrv.getDbResource('response.php', 'taxonomy', '')
.then(function(data) {
$scope.taxonomies = [];
$scope.chosen = [];
angular.forEach(data, function(value, key) {
$scope.taxonomies.push({label: value.name, value: value.term_taxonomy_id});
});
// subtract 1 because $scope.c is 0-based
var catId = $scope.c.category - 1;
$scope.chosen = $scope.taxonomies[catId];
$scope.formBusy = false;
});
});
$scope.updateCompany = function(cid) {
var formData = $scope.c;
$scope.formBusy = true;
$scope.doCompanyUpdate = DbResourceSrv.updateDbResource('response.php', cid, formData)
.then(function(response) {
$scope.formBusy = false;
});
};
}]);
Usually I do see my category (which is also fetched from the database, just in a separate call $scope.tax
Now, I tried with $watch
ing the chosen scope property but it doesnt change anything. I also tried using a directive controller to make sure scope.chosen
is set there but it seems to me even though I'm loading both processes with promises - the category fetching misfires when one is loaded before the other because they are tied too tightly.
Any suggestions for code improvement so i can avoid seeing the default Please select a category
option selected on page load?
You were correct: you have two promises which aren't guaranteed to resolve in order, and this is a problem. In the case where the second "beats" the first, it won't be able to calculate catId
, since $scope.c
isn't populated yet.
$scope.c = DbResourceSrv.getDbResource('response.php', 'company', $scope.cid)
.then(function(data) {
$scope.c = data; // not guaranteed to be set when it's needed
});
$scope.tax = DbResourceSrv.getDbResource('response.php', 'taxonomy', '')
.then(function(data) {
var catId = $scope.c.category - 1;
$scope.chosen = $scope.taxonomies[catId];
});
A solution is to use $q.all
, which accepts an array of promises as an argument and returns another promise which is resolved only when all of the passed in promises resolve.
It would look something like this:
$q.all([$scope.c, $scope.tax]).then(function(results){
var catId = $scope.c.category - 1;
$scope.chosen = $scope.taxonomies[catId];
});
You should be able to leave the bulk of your existing promise callbacks in tact - just move whatever relies on both AJAX requests having returned.