Subtitle: Don’t Trust Your Eyes
My project has been bouncing technologies like basketballs against the backboard. The latest techno-basketball to sink is Angular.js. I don’t intend to do a thorough review of this technology here since it is well documented in the Google/Stackoverflow community. But I have been having fun with populating a <Select> tag’s options using the built in angular directives.
First here are some links I found useful in my quest to resolve this issue:
- http://docs.angularjs.org/api/ng.directive:select [Angular’s own docs]
- Stackoverflow: How to set value property in angularjs ng-options?
- DZone: Angular.js: ng-select and ng-options
Basically I am replacing this code block (originally coded to work in a Dust.js format:
<!-- Year --> <div> <label for="yearID">Year:</label> <div> <select id="yearID" name="year" value="{{ academicRecords[0].completionYear }}" ng-model="academicRecords[0].completionYear"> title="Please select the completion year"></select>
… with the Angular directive code below:
<select ng-options="y.value as y.option for y in yearList" ng-model="academicRecords[0].completionYear"> <option style="display:none" " title="Please select the completion year"> Year: </option> </select>
First thing i have to do is create a $scope.yearList (my name) variable to populate the list:
$scope.yearList = $scope.getYearList();
And here is $scope.getYearList() function and the other supporting variable/function to populate this list:
$scope.getYearList = function () {
var min = 50 ; // Number of years to reach back to
var year = new Date().getFullYear();
var yearArray = [];
do {
// yearID.add( new Option(year,year), null );
yearArray.push($scope.yearObject(year--));
min--;
} while (min>0);
return yearArray;
}
// Create individual JSON Array objects to populate list
$scope.yearObject = function (year) {
return {
option: ""+year , value : ""+year }
}
Assign the appropriate function call to the <select>’s ng-option:
ng-options="y.value group by y.option for y in yearList"
$scope.yearList as entry point fulfills this request (fills out my list.)
With everything setup I have a beautiful (auto-populated) Select List of Option Labels appropriately populating. My head scratcher at this point is controlling which values goe into the ‘Value=”” ‘ tag. It is being generated as a 0 based list. {0-49 in this case}
But the option value is correct (see 2012) above. So it *can’t* (famous last words) be a monumental effort get the correct values in “value=” as well.
So I Google search the following: angular ng-option value.
And here is what I come up with:
- {Repeat from above link list}
Stackoverflow: How to set value property in angularjs ng-options? - Angular.js: ng-select and ng-options by CHRISTIAN GROBMEIER
- Using a case where the year comes back as 1984, submitting the form I see the following result (from Google Chrome Dev Mode):
YearCompleted:
Constructor
$dirty: false
$error: Object
$formatters: Array[0]
$invalid: false
$modelValue: “1984”
$name: “YearCompleted”
$parsers: Array[0]
$pristine: true
$render: function render()
{ $setPristine: function ()
{ $setValidity: function (validationErrorKey, isValid)
{ $setViewValue: function (value)
{ $valid: true $viewChangeListeners: Array[0] $viewValue: “1984”
Despite the <option value=”0″>2013</option> not being the value=”” we may intuitively KNOW should be present (via standard HTML processing,) the 2-way binding correct delivers the correctly selected value upon submit.An astute developer should rightly note my example’s values and text are the same :
<option value=2013>2013</option>
So I ran a quick test in which I changed the JSON populating the target select tag
$scope.yearObject = function (year) { return { value: 'Pass Me! Pass Me!'+year , text : ''+year } }
Notice for the “value : ” JSON element I added:
'Pass Me! Pass Me!'+year ,
GIVEN: none of the above code populating the SELECT tag was modified
RESULT: refreshing browser, choosing year 2001:
Despite choosing ‘2001’, it still shows ‘2013’ selected.
We will see this is an auto-magical mind bender at this point.
I Click [SUBMIT] and the Chrome DevConsole reveals to me the submitted values (via 2 way binding) are the following:
$valid: true YearCompleted: Constructor $dirty: true $error: Object $formatters: Array[0] $invalid: false $modelValue: "Pass Me! Pass Me!2001" $name: "YearCompleted" $parsers: Array[0] $pristine: false $render: function render() { $setPristine: function () { $setValidity: function (validationErrorKey, isValid) { $setViewValue: function (value) { $valid: true $viewChangeListeners: Array[0] $viewValue: "Pass Me! Pass Me!2001"
Intuitively any Web Developer will expect the “Value” property of an <Option> tag to get picked up and passed to the 2-way binding (causing us to see the list Id’s in the
“value” property as a problem.) But (beyond the scope of my research tonight) Angular is tracking the values elsewhere, so upon submit, the appropriate value {probably keyed to the Id’ values} is bound to the variable/object. This is why I subtitled this blog post Don’t Trust Your Eyes.
Hopefully this will be found helpful to those who initially have this same question as you start working with Angular. Happy Coding!