Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angularjs ng-model select not updating properly

Tags:

angularjs

I've got a very simple form with a select that contains all the states + abbreviations. When using the keyboard to navigate the second keypress doesn't change ng-model value in certain circumstances. For example if you tab to the select element and hit T it will properly select Tennessee and TN will be placed into the ng-model. Hitting down arrow or T a second time updates the displayed value to Texas, but ng-model is still set to TN. Weirdly enough this doesn't occur if its 2 different letters, so T followed by A correctly puts AL into the ng-model.

The HTML looks like this:

<div>
    <label for="user_city">City</label>
    <input type="text" name="user_city" id="user_city" ng-model="user.city" />
    <label for="user_state">State*</label>
    <select name="user_state" id="user_state" ng-model="user.state" style="width: 228px" required>
        <option value="AL">Alabama</option>
        <option value="AK">Alaska</option>
        <option value="AZ">Arizona</option>
        <option value="AR">Arkansas</option>
        <option value="CA">California</option>
        <option value="CO">Colorado</option>
        <option value="CT">Connecticut</option>
        <option value="DE">Delaware</option>
        <option value="DC">District Of Columbia</option>
        <option value="FL">Florida</option>
        <option value="GA">Georgia</option>
        <option value="HI">Hawaii</option>
        <option value="ID">Idaho</option>
        <option value="IL">Illinois</option>
        <option value="IN">Indiana</option>
        <option value="IA">Iowa</option>
        <option value="KS">Kansas</option>
        <option value="KY">Kentucky</option>
        <option value="LA">Louisiana</option>
        <option value="ME">Maine</option>
        <option value="MD">Maryland</option>
        <option value="MA">Massachusetts</option>
        <option value="MI">Michigan</option>
        <option value="MN">Minnesota</option>
        <option value="MS">Mississippi</option>
        <option value="MO">Missouri</option>
        <option value="MT">Montana</option>
        <option value="NE">Nebraska</option>
        <option value="NV">Nevada</option>
        <option value="NH">New Hampshire</option>
        <option value="NJ">New Jersey</option>
        <option value="NM">New Mexico</option>
        <option value="NY">New York</option>
        <option value="NC">North Carolina</option>
        <option value="ND">North Dakota</option>
        <option value="OH">Ohio</option>
        <option value="OK">Oklahoma</option>
        <option value="OR">Oregon</option>
        <option value="PA">Pennsylvania</option>
        <option value="RI">Rhode Island</option>
        <option value="SC">South Carolina</option>
        <option value="SD">South Dakota</option>
        <option value="TN">Tennessee</option>
        <option value="TX">Texas</option>
        <option value="UT">Utah</option>
        <option value="VT">Vermont</option>
        <option value="VA">Virginia</option>
        <option value="WA">Washington</option>
        <option value="WV">West Virginia</option>
        <option value="WI">Wisconsin</option>
        <option value="WY">Wyoming</option>
    </select>
</div>

Here is a jsfiddle demonstrating the issue: http://jsfiddle.net/cKF6Q/2/

To duplicate, click the city box and then press TAB to focus the select box and type T T. You'll see user.state go to TN on the first press of T, but the second one is ignored.

NOTE: This is only the SECOND keypress so you have to reload the page between tests.

like image 411
brocksamson Avatar asked Mar 26 '14 18:03

brocksamson


1 Answers

I had the exact same problem. Here's a jsFiddle - the first dropdown has been "fixed", the second one has not (just for demonstration).

<div ng-app>
    <input type="text" name="name" ng-model="form.name" />
    <select name="expirationMonth" ng-model="form.expirationMonth">
        <option value="">--</option>
        <option>01</option>
        <option>02</option>
        <option>03</option>
        <option>04</option>
        <option>05</option>
        <option>06</option>
    </select>
    <select name="expirationYear" ng-model="form.expirationYear">
        <option>2014</option>
        <option>2015</option>
        <option>2016</option>
        <option>2017</option>
    </select>

    <pre>{{ form | json }}</pre>
</div>

I noticed it with the down arrow key. I tab onto the field and press the down arrow. The first key press updates the model. The second key press updates the form element but not the model. The third key press and every key press after that updates the model as you would expect.

The Fix

Add an extra option with a blank value to the top of the list. By making the value blank, it will not interfere with form validation (marking the field as required, for instance). Also, AngularJS does allow you to include one static option when you bind to an array. From the AngularJS docs:

Optionally, a single hard-coded <option> element, with the value set to an empty string, can be nested into the <select> element. This element will then represent the null or "not selected" option.

UPDATE: Browser Diff

I've noticed that Chrome will update the display of the model with each keypress of the down arrow (except the second keypress when the static default option is not present, obviously). Chrome was the browser I used when writing the fiddle. Firefox, on the other hand, does not update the display of the model until i tab or click out of the field. Internet Explorer 11 updates the model "on the fly" similar to Chrome, but I wasn't able to reproduce this "2nd keypress issue" on IE 11. I don't have any other browsers to test on.

like image 174
Brian Oliver Avatar answered Sep 24 '22 05:09

Brian Oliver