Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

ng-options provided empty option #15454

Closed
johan-miller opened this issue Nov 30, 2016 · 1 comment
Closed

ng-options provided empty option #15454

johan-miller opened this issue Nov 30, 2016 · 1 comment

Comments

@johan-miller
Copy link

Note: for support questions, please use one of these channels: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#question. This repository's issues are reserved for feature requests and bug reports.

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
When using ng-if on an empty default option a javascript error is thrown.
TypeError: element.removeAttribute is not a function at removeAttr (https://code.angularjs.org/1.5.9/angular.js:3343:13) at JQLite.(anonymous function) [as removeAttr] (https://code.angularjs.org/1.5.9/angular.js:3479:9) at removeEmptyOption (https://code.angularjs.org/1.5.9/angular.js:29457:23) at SelectController.writeNgOptionsValue [as writeValue] (https://code.angularjs.org/1.5.9/angular.js:29491:15) at NgModelController.ngModelCtrl.$render (https://code.angularjs.org/1.5.9/angular.js:31826:20) at ngModelWatch (https://code.angularjs.org/1.5.9/angular.js:28422:14) at Scope.$digest (https://code.angularjs.org/1.5.9/angular.js:17747:34) at Scope.$apply (https://code.angularjs.org/1.5.9/angular.js:18021:24) at bootstrapApply (https://code.angularjs.org/1.5.9/angular.js:1806:15) at Object.invoke (https://code.angularjs.org/1.5.9/angular.js:4762:19)

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).
https://plnkr.co/edit/29iYtxHrrp5beeCmwsuW

What is the expected behavior?
No error is thrown.

What is the motivation / use case for changing the behavior?
It has worked in previous versions.

Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.
Same code works fine in 1.5.8. Seems to be broken since version 1.5.9. Also in the latest snapshot.

Other information (e.g. stacktraces, related issues, suggestions how to fix)
I have seen suggestions to use ng-show to achieve the same functionality. This does fix the javascript error but also introduces another problem with IE. IE still displays the empty option even when when ng-show="false".

@Narretz
Copy link
Contributor

Narretz commented Nov 30, 2016

Should have been caused by this: d31b3a6

Narretz added a commit to Narretz/angular.js that referenced this issue Nov 30, 2016
Narretz added a commit to Narretz/angular.js that referenced this issue Nov 30, 2016
Narretz added a commit to Narretz/angular.js that referenced this issue Dec 1, 2016
gkalpak referenced this issue Dec 1, 2016
When the select model changes, we add the "selected" attribute to the selected option, so that
screen readers know which option is selected.

Previously, we failed to remove the attribute from the selected / empty option when the model changed
to match a different option, or the unknown / empty option.

When using "track by", the behavior would also show when a user selected an option, and then the
model was changed, because track by watches the tracked expression, and calls the $render function
on change.

This fix reads the current select value, finds the matching option and removes the "selected"
attribute.

IE9 had to be special cased, as it will report option.hasAttribute('selected') === true even
if the option's property and attribute have been unset (even the dev tools show not selected attribute).

I've added a custom matcher that accounts for this behavior. In all other browsers, property and
attribute should always be in the same state. Since few people will use screen readers with IE9, I
hope this is a satisfactory solution to the problem.

Fixes #14892
Fixes #14419
Related #12731
PR (#14894)
Narretz added a commit that referenced this issue Dec 2, 2016
When the "empty option" element contains a transclusion directive, the result of the compilation always includes a comment node. Since we are adding / removing the "selected" attribute on the empty option, we need to make sure it's an actual element.

To solve this, we take advantage of the fact the each option element has an option directive that tries to register the option with the selectController. With ngOptions, this registerOption function is normally noop'd since it's not possible to add dynamic options. Now if the result of the empty option compilation is a comment, we re-define the function so that it catches empty options when they are actually linked / rendered.

Closes #15454
Closes #15456
Narretz added a commit to Narretz/angular.js that referenced this issue Dec 2, 2016
When the "empty option" element contains a transclusion directive, the result of the compilation always includes a comment node. Since we are adding / removing the "selected" attribute on the empty option, we need to make sure it's an actual element.

To solve this, we take advantage of the fact the each option element has an option directive that tries to register the option with the selectController. With ngOptions, this registerOption function is normally noop'd since it's not possible to add dynamic options. Now if the result of the empty option compilation is a comment, we re-define the function so that it catches empty options when they are actually linked / rendered.

Related angular#15454
Closes angular#15459
@Narretz Narretz closed this as completed in 245b271 Dec 2, 2016
ellimist pushed a commit to ellimist/angular.js that referenced this issue Mar 15, 2017
When the "empty option" element contains a transclusion directive, the result of the compilation always includes a comment node. Since we are adding / removing the "selected" attribute on the empty option, we need to make sure it's an actual element.

To solve this, we take advantage of the fact the each option element has an option directive that tries to register the option with the selectController. With ngOptions, this registerOption function is normally noop'd since it's not possible to add dynamic options. Now if the result of the empty option compilation is a comment, we re-define the function so that it catches empty options when they are actually linked / rendered.

Closes angular#15454
Closes angular#15459
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants