I have 4 directives, all accessing the same service 'checkoutData'. The first 3 directives load the checkoutData service with data (shipping & billing information). When I debug I can see they share the same instance because the data is present for all 3. The 4th directive (continueCheckout) is responsible for making sure all data is valid before performing other actions. The problem is that the checkoutData service data is then empty. I can breakpoint in the first line of checkoutData and can see it is only being called once, so I know there is only 1 instance. What's happening?
Continue Checkout Directive
(function() {
angular.module('checkoutApp').directive('continueCheckout', function() {
return {
restrict: 'E',
scope: {
'nextStep': '@',
'buttonText': '@'
},
template: '<a href ng-click="validate()"><button type="submit" class="btn btn-default">{{buttonText}}</button></a>',
controller: function ($scope, $location, $log, checkoutData) {
checkoutData.printData();
$scope.validate = function () {
checkoutData.printData();
if (checkoutData.isValid()) {
$location.path("/" + $scope.nextStep);
}
}
}
}
});
})();
checkoutData.js
(function() {
angular.module('checkoutApp').factory('checkoutData', ['$log', function($log) {
var data = {
shippingOptionId: null,
billingOptionId: null,
shipping: {},
billing: {}
};
var inputForms = [];
var printData = function () {
$log.debug(JSON.stringify(inputForms));
$log.debug(JSON.stringify(data.shipping));
$log.debug(data.shippingOptionId);
};
var isValid = function() {
printData();
return false;
//return _.every(data.inputForms, function(form) { return form.valid });
};
return {
shipping: data.shipping,
setValid: function(formName, valid) {
inputForms[formName].valid = valid;
},
initializeForm: function(formName) {
inputForms[formName] = {};
},
isValid: isValid,
printData: printData
}
}]);
})();
ShippingOptions.js (one of the directives that works and can see checkout data)
(function() {
angular.module('checkoutApp').directive('shippingOptions', function() {
return {
restrict: 'E',
templateUrl: 'Scripts/Checkout/ShippingOptions/shippingOptions.html',
controller: function ($scope, $log, shippingOptionsService, checkoutData) {
$scope.selectedShippingOption = {};
$scope.checkoutData = checkoutData;
checkoutData.initializeForm('shippingOptions');
$scope.$watch('shippingOptionsForm.$valid', function (newVal) {
checkoutData.setValid('shippingOptions', newVal);
});
$scope.$watch('selectedShippingOption', function (newVal) {
checkoutData.selectedShippingId = newVal;
});
$scope.shippingOptions = [
{ id: 1, name: 'UPS Ground', cost: '11.32', display: 'UPS Ground ($11.32)', moreInfo: 'ups ground more info' },
{ id: 2, name: 'UPS 3 Day', cost: '17.92', display: 'UPS 3 Day ($17.92)', moreInfo: 'ups 3 day more info' },
{ id: 3, name: 'UPS 2 Day', cost: '20.76', display: 'UPS 2 Day ($20.76)', moreInfo: 'ups 2 day more info' }
];
}
}
});
})();
The problem is the isValid function is treating data.inputForms as if it's an array. It's being loaded as associative objects (key value collection) so it cannot be iterated over using .forEach. Here is the working code for isValid()
var isValid = function () {
for (var key in data.inputForms) {
if (data.inputForms.hasOwnProperty(key)) {
if (!data.inputForms[key].valid) {
return false;
}
}
}
return true;
};