I have read several posts and articles relating to this issue and they have helped me devise some work arounds but do not explain (at least in a way I understand) why this doesn't work.
I created a factory service whose job is to manage a list of continents and a single selected continent. Controllers interact with this service via a public API expressed as an object literal.
var appSvcs = appSvcs || angular.module("app.services", ["app.repositories"]);
appSvcs.factory('ContinentService', ['ContinentRepository',
function (db) {
'use strict';
//#region Private Fields and Variables
var continents = [],
selectedContinent = null;
selectedContinentIndex = -1;
//#endregion Private Fields and Variables
//#region Private Methods
function initContinents() {
return db.getContinents(); // return a promise
};
function setSelectedContinent(continent) {
selectedContinent = angular.copy(continent);
selectedContinentIndex = continents.indexOf(continent);
};
//#endregion Private Methods
//
// Public API
return {
continentService: {
continents: continents,
selectedContinent: selectedContinent,
setSelectedContinent: setSelectedContinent,
initContinents: initContinents,
}
}
}]);
The controller interacts with the continentService via the public API. In the controller I add a reference to the API on the local $scope ...
$scope.svc = svc.continentService;
Since the factory is supposed to be a singleton, what I expect is that when the controller calls the public method "setSelectedContinent()", the selectedContinent and selectedContinentIndex properties will be set and then be available to the host controller and any other controller that implements this factory. This has not proven to be the case. In the second line below a type error is thrown ... "Cannot read property 'Id' of null". This suggests that the selectedContinent property of the service was not set.
$scope.svc.setSelectedContinent(continent);
console.log($scope.svc.selectedContinent.Id + " :: " + $scope.svc.selectedContinent.Name);
When, however, I set the property directly, it works fine - sorta. There is processing that the method setSelectedContinen()t does that needs to be performed and setting it directly obviously does not allow that to happen.
$scope.svc.selectedContinent = continent;
console.log($scope.svc.selectedContinent.Id + " :: " + $scope.svc.selectedContinent.Name);
I have included the complete controller code for reference in case that's helpful.
angular.module("ListMgrApp").controller('ContinentPanelCtrl',
['$scope', 'ContinentService',
function ($scope, svc) {
'use strict';
//#region Fields and Variables
$scope.svc = svc.continentService;
var $uiContinentList = $('.continent-list');
///#endregion Fields and Variables
//#region private methods
function init() {
//
// Show the pane
$scope.svc.initContinents().then(
function (response) {
$scope.svc.continents = response.data;
},
function (reason) {
//TODO: Handle Error
});
};
//#endregion private methods
//#region $scope methods
$scope.setSelectedContinent = function (continent) {
// $scope.svc.selectedContinent = continent; <-- works but not sufficient
$scope.svc.setSelectedContinent(continent); // <-- Needs to work but does not
console.log(continent.Id + " :: " + continent.Name);
$uiContinentList.find('li[data-id="' + continent.Id + '"]').addClass("selected");
}
//#endregion $scope methods
init();
}]);