I am trying to bind a selectedContinent object to a drop down list.
Application Description
I am building a piece of an application which should represent a fairly simple use case, dealing with simple related lists (i.e. states to countries to continents). The idea is to learn AngularJS in a progressively complex application.
I have successfully built functionality that performs basic CRUD operations on the "Continents" ... the most basic of the lists.
I now need to up the difficulty, just a notch, and create a screen which performs CRUD operations on a particular Country. Each country is, of course related to a continent.
Design
The Continents and Contries are accessed by the application via Angular Factory "services". Each factory returns a singleton service (I realize that I could have used a Service "service" instead but I learned factories first and didn't feel like I needed to rewrite this piece).
Each service provides the ability to access CRUD functions but also stores a "selected" item. I will just talk about the continent service since it's the one I am struggling with.
So the view begins life initializing a list of continents from the data store and storing them in an array in the continent service.
Continent Service Code with the init function shown
var appSvcs = appSvcs || angular.module("app.services", ["app.repositories"]);
appSvcs.factory('ContinentService', ['ContinentRepository','Utilities', 'GlobalConfig',
function (db, util, globalConfig) {
'use strict';
var continentSvc = null,
getContinentService = function() {
if (continentSvc === null) {
continentSvc = new function () {
var self = this,
selectedContinentIndex = -1;
//#region public properties
this.continents = [];
this.selectedContinent = null;
//#endregion public properties
//#region public methods
this.initContinentList = function () {
return db.getContinents(); // returns a promise
};
this.setSelectedContinent = function (continentId) {
var continent = self.continents.filter(function (element) {
return element.Id === continentId;
});
self.selectedContinent = angular.copy(continent[0]);
selectedContinentIndex = self.continents.indexOf(continent[0]);
};
// more methods go here
//#endregion public methods
}
}
return continentSvc;
};
return {
getContinentService: getContinentService
}
}]);
The controller of the view that initializes the list of continents and populates the "continents" array in the service.
angular.module("ListMgrApp").controller('CountryPanelCtrl',
['$scope', 'Utilities', 'LayoutManager', 'CountryService', 'ContinentService',
function ($scope, util, layout, countrySvc, continentSvc) {
'use strict';
//#region $scope fields and variables
$scope.countrySvc = countrySvc.getCountryService();
$scope.continentSvc = continentSvc.getContinentService();
//#endregion $scope fields and variables
//#region private fields
var $uiCountryList = $('.country-list');
//#endregion private fields
//#region private methods
function init() {
//
// initialize the continent list
$scope.continentSvc.initContinentList().then(
function (response) {
$scope.continentSvc.continents = response.data;
},
function (reason) {
//TODO: Handle Error
});
// other initialization methods are here
};
//#endregion private methods
init();
}]);
I use this array to populate a drop down list in a view ... Which works well; the list is successfully populated with a list of continents.
<select name="ContinentList" style="width:100%;"
data-ng-model="continentSvc.selectedContinent"
data-ng-selected="continentSvc.selectedContinent"
data-ng-change="setSelectedContinent()"
data-ng-options="continent as continent.Name for continent in continentSvc.continents | orderBy:'Name'">
<option style="display:none;" value="">Select a Continent</option>
</select>
Also, based on my understanding of comments posted here, this is properly configured so that a continent OBJECT is selected whenever the list selection is changed and not just a single field/property value.
The problem I am having is setting the selected continent programmatically. It's probably worth noting at this time that there is a second controller working here as well. This controller manages the list of countries. Since both views however, use the continent service, which returns a singleton, the data and any changes to it are reflectd in both controllers. When a user selects an existing country from a list that selection sets the "selectedContinent" property of the service to the continent assigned to the country.
$scope.setSelection = function (country) {
$scope.continentSvc.setSelectedContinent(country.ContinentId);
// see above service code sample for definition of "setSelectedContinent"
}
Since this selectedContinent is defined in the service I expect that it's being changed to affect anythign bound to it. And I I have verified this to be the case by putting a simple output template in the view with the drop down list, and observing that this DOES CHANGE when the country is selected.
{{ continentSvc.selectedContinent.Name }}
The problem is that, even though the test output above is being bound properly, the drop down list reverts to an unselected state. It does not stay on whatever is selected, it changes to "nothing" being selected. The "continentSvc.selectedContinent" specified as the ng-model on the DDL is not reflected as the selected drop down list item even though it has changed. I do not understand why this is. My test output confirms that the "continentSvc.selectedContinent" has indeed changed and that that change is reaching it's bound elements. And since it is set as the ng-model of the DDL I woudl expect the DDL to change as well. ???
In an effort to provide enough information I hope I haven't gotten too verbose. I appreciate your attention and assistance.
I have looked at and taken away good information form the following posts but none resolved this issue.
How to select an option in a dropdown list angularjs
How to set a selected option of a dropdown list control using angular JS
AngularJS - ng-option dropdown list not setting ng-model value when False selected