Angular.js Select tag via ‘ng-control’

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:

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}

Image

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:

  • 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:

angular.js.select-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!