-
Notifications
You must be signed in to change notification settings - Fork 27.4k
Regression using ngOptions asynchronously in angular 1.3 #9714
Comments
I just ran into this same issue (plunker here: http://plnkr.co/edit/NgPGrklA3ng6bmnPjxmw?p=preview) and ended up with the same solution (pre-filling the options holder with the known selected value). The workaround is kind of ugly but not terrible. Tested in Firefox, Chrome and Safari but did not see the behavior in Firefox. Only tested on OS X. |
This is a big problem for our group. All versions of AngularJS are okay up until the last 1.3.0 version. There's no simple workaround for us as every select box in our application is populated the same way and now none of them work as expected. I hope this bug gets fixed ASAP. Seems like it was introduced with 1.3.0. Now going back to using the RC release while waiting for someone to at least back out the change in the options that was made just prior to the 1.3.0 release :-( |
Can you assign this to me? I think I see the problem, and I'll try to get a pull request ready for tomorrow. |
Fix regression in angular 1.3 where empty string is added to select Closes angular#9714
Fix angular 1.3 regression where empty string was shown Closes angular#9714
Fix angular 1.3 regression where empty string was shown Closes angular#9714
Fix angular 1.3 regression where empty string was shown Closes angular#9714
Otherwise, if the removed option was the empty option (value ''), and the currently selected option had a value of 0, the select would think that the currently selected option had been removed, causing the unknown option to be added again. Fixes angular#9714 Fixes angular#10115 Closes angular#10203
Sounds like this is the root cause for the following issue? |
Otherwise, if the removed option was the empty option (value ''), and the currently selected option had a value of 0, the select would think that the currently selected option had been removed, causing the unknown option to be added again. Fixes angular#9714 Fixes angular#10115 Closes angular#10203
Is this separate from the issue outlined in this plunker? The value isn't displaying in any 1.3.x |
have a look at this one http://plnkr.co/edit/P9WCLicfJjLVCr8nBdqn?p=preview We have the @jayoungers related issue more clean and another issue where ng-options selects the wrong option. |
Should we see the values selected in (http://plnkr.co/edit/P9WCLicfJjLVCr8nBdqn?p=preview)? |
Interestingly enough, adding a |
Something definitely wonky's going on; you would think both of these selects should act the same way (first instantly has the items, 2nd is delayed): http://plnkr.co/edit/SDtfdItrd1ejDcp1ME1e?p=preview adding/removing the track by piece results in the other working |
Looks like I only fixed a specifc case, reopening |
Actually looking again I think the problem is that these lines: https://github.com/angular/angular.js/blob/v1.3.6/src/ng/directive/select.js#L694-L700 forEach(labelMap, function(count, label) {
if (count > 0) {
selectCtrl.addOption(label);
} else if (count < 0) {
selectCtrl.removeOption(label);
}
}); Are using the |
@petebacondarwin We should investigate that, thanks for checking this out. edit: I think that's correct: if an option has the label '1', addOption('1') will set the select element's val to '1', which means the second option is selected. What's strange is that the follwing reproductions work fine in FF34, but fail in Chrome: Maybe just a timing issue? |
Yes - weird. I still think that the |
Just copy/pasting my initial comment from #9691 :
I have been using this small fix without undesirable side-effects in my project since then. (JSFiddle) if you set a breakpoint on the <select ng-model="selected" ng-options="i as i for i in items" class="ng-pristine ng-untouched ng-valid">
<option value="0" selected="selected" label="obj1">obj1</option>
<option value="1" label="obj2">obj2</option>
</select>
|
@Narretz and I paired on this tonight. It turns out that there is a significant problem inside the
Neither of these strategies is adequate. It is feasible to have multiple options with the same label and in any case the underlying selected option could change if the option's label changes compared to its "value". In the case of arrays, using index is flawed as the index of an option can change if it is moved around in the array (or even if another item is simply removed from the front of the array). The suggested fix is to follow the same strategy as This will involve quite a bit of internal refactoring but should hopefully not impact on the public API at all. |
Sounds great guys! If anyone runs into a similar problem in the meantime, the temporary solution I went with was adding a ng-if to one of the select's parent elements to ensure the select doesn't get created until my collections are retrieved from the server. |
maybe it cause by the code
and the code make the select don't show the real value.
|
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: Although it is internal, and not documented, this commit changes the actual strings that are stored as the value of each `<option>` element. We now store a string that is computed by calling `hashKey` on the item in the options collection; before it was the index or key value of the item in the collection. Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. Closes angular#9714
@angrytoro - this is the right idea but |
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element. This commit changes the actual string used as the surrogate key. We now store a string that is computed by calling `hashKey` on the item in the options collection; previously it was the index or key of the item in the collection. Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions` as this provides the ability to specify the key that is stored. Closes angular#9714
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element. This commit changes the actual string used as the surrogate key. We now store a string that is computed by calling `hashKey` on the item in the options collection; previously it was the index or key of the item in the collection. Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions` as this provides the ability to specify the key that is stored. Closes angular#9714
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element. This commit changes the actual string used as the surrogate key. We now store a string that is computed by calling `hashKey` on the item in the options collection; previously it was the index or key of the item in the collection. (This is in keeping with the way that the unknown option value is represented in the select directive.) Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions` as this provides the ability to specify the key that is stored. Closes angular#9714
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element. This commit changes the actual string used as the surrogate key. We now store a string that is computed by calling `hashKey` on the item in the options collection; previously it was the index or key of the item in the collection. (This is in keeping with the way that the unknown option value is represented in the select directive.) Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions` as this provides the ability to specify the key that is stored. Closes angular#9714
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element. This commit changes the actual string used as the surrogate key. We now store a string that is computed by calling `hashKey` on the item in the options collection; previously it was the index or key of the item in the collection. (This is in keeping with the way that the unknown option value is represented in the select directive.) Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions` as this provides the ability to specify the key that is stored. Closes angular#9714
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element. This commit changes the actual string used as the surrogate key. We now store a string that is computed by calling `hashKey` on the item in the options collection; previously it was the index or key of the item in the collection. (This is in keeping with the way that the unknown option value is represented in the select directive.) Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions` as this provides the ability to specify the key that is stored. Closes angular#9714 Closes angular#10639
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element. This commit changes the actual string used as the surrogate key. We now store a string that is computed by calling `hashKey` on the item in the options collection; previously it was the index or key of the item in the collection. (This is in keeping with the way that the unknown option value is represented in the select directive.) Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions` as this provides the ability to specify the key that is stored. Closes angular#8019 Closes angular#9714 Closes angular#10639
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element. This commit changes the actual string used as the surrogate key. We now store a string that is computed by calling `hashKey` on the item in the options collection; previously it was the index or key of the item in the collection. (This is in keeping with the way that the unknown option value is represented in the select directive.) Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions` as this provides the ability to specify the key that is stored. Closes angular#8019 Closes angular#9714 Closes angular#10639
…ns are loaded async **Major reworking of select and ngOptions**: * The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives to override to get their desired behaviour * The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions` directive could be deleted without having to make any changes to the `select` directive. * Select related directives (single/multiple/ngOptions) can provide specific versions of `SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting the `$viewValue` in or out of the actual `<select>` element and its `<option>` children. BREAKING CHANGE: When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element. This commit changes the actual string used as the surrogate key. We now store a string that is computed by calling `hashKey` on the item in the options collection; previously it was the index or key of the item in the collection. (This is in keeping with the way that the unknown option value is represented in the select directive.) Before you might have seen: ``` <select ng-model="x" ng-option="i in items"> <option value="1">a</option> <option value="2">b</option> <option value="3">c</option> <option value="4">d</option> </select> ``` Now it will be something like: ``` <select ng-model="x" ng-option="i in items"> <option value="string:a">a</option> <option value="string:b">b</option> <option value="string:c">c</option> <option value="string:d">d</option> </select> ``` If your application code relied on this value, which it shouldn't, then you will need to modify your application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions` as this provides the ability to specify the key that is stored. BREAKING CHANGE: When iterating over an object's properties using the `(key, value) in obj` syntax the order of the elements used to be sorted alphabetically. This was an artificial attempt to create a deterministic ordering since browsers don't guarantee the order. But in practice this is not what people want and so this change iterates over properties in the order they are returned by Object.keys(obj), which is almost always the order in which the properties were defined. Closes angular#8019 Closes angular#9714 Closes angular#10639
Hi guys,
Just wanted to start by saying that Angular is a wonderful project and I'm having a great time working with it :)
I have an example of the issue in this jsFiddle: http://jsfiddle.net/88aw4yyq/
Consider this HTML:
And this controller:
The
$timeout
simulates any regular AJAX request.{id: '', label: 'Please select...'}
is added for convenience for the user.Expected behavior: 'Please select...' should be selected once the data is loaded.
Actual behavior: An empty option is added on top in the select field.
Angular versions: 1.3.0 this is a regression, 1.2.x was working fine.
Browser versions: Tested on Fx/Chrome (latest versions) on both OS X & Windows.
If anyone else is encountering the issue, here is a workaround:
The text was updated successfully, but these errors were encountered: