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

Custom <select> directive: Transclude and replace <option>s not working in IE9 #6926

Open
aeharding opened this issue Mar 31, 2014 · 9 comments

Comments

@aeharding
Copy link

Please check out the following JSfiddle (since Plunker doesn't work in IE9):
http://jsfiddle.net/Rpe36/

Basically, I have myDirective that is an element. I transclude and replace with the following template:

<select class="some" ng-transclude></select>

It doesn't work. :(

If I use the ngOptions attribute and nothing transcluded, it works fine! Go figure.

I don't know if this is a larger problem with IE9, or something that could be fixed in Angular.

Thanks!
Alex

@tbosch tbosch self-assigned this Mar 31, 2014
@tbosch
Copy link
Contributor

tbosch commented Mar 31, 2014

Hi,
thanks for reporting. I could verify this bug against the latest 1.3.0-beta.4 release.

We already fixed this problem for table elements like tbody, ... but not yet for option elements (see 31c450b).

A workaround would be to define your directive as an attribute on a select element, see this fiddle: http://jsfiddle.net/Rpe36/3/

@tbosch tbosch added this to the Backlog milestone Mar 31, 2014
@tbosch
Copy link
Contributor

tbosch commented Mar 31, 2014

Given the commit linked above, this should be easy to implement. Would you like to try to create a PR for this?

@tbosch tbosch removed their assignment Mar 31, 2014
@aeharding
Copy link
Author

Definitely! I'll see what I can do.

Also, thanks for the workaround, I am doing something similar for the moment.

Thanks again

aeharding pushed a commit to aeharding/angular.js that referenced this issue Apr 1, 2014
the compiler will wrap it with a <select> tag. This satisfies IE9.

Closes angular#6926
aeharding pushed a commit to aeharding/angular.js that referenced this issue Apr 1, 2014
the compiler will wrap it with a <select> tag. This satisfies IE9.

Closes angular#6926
@aeharding
Copy link
Author

So the pull request I just made only partially fixes the root problem.

@tbosch, I think you slightly misunderstood me -- I'm talking about transcluding these troubled elements, not putting them in a template.
Essentially, if I transclude items (whether they are <option>s or <thead>) inside of a directive the a template of <select> or <table> (respectfully), I have this problem.

(This pull request is still useful though, as it fixes a directive with a template of <option> root element that is replaced...)

From my research, the larger issue might be something that would need to be changed in JQLite. I see that JQLite adds content using innerHTML and a dummy <div> preceding it.

Unfortunately, IE9 and before has a major bug with completely ignoring elements such as <thead> and <select>, instead just grabbing its contents and throwing them inside a text node...

For example:

angular.element('<option>Hello!</option><option>There!</option>');

This ONLY breaks if JQLite is not replaced by jQuery. jQuery has somehow gotten around this issue to get it working in IE9. However, since angular still uses JQLite internally, the problem persists when adding jQuery into the picture.

The reason the pull request above fixes this for templates is that the elements are surrounded by their specific parent element to be happy. For example, the following works great:

angular.element('<select><option>Hello!</option><option>There!</option></select>');

Overall, I'm not terribly worried, and I do not think this problem is worth everyone's time given the workarounds that exist. I do think it should be documented somewhere (if not here).

@caitp
Copy link
Contributor

caitp commented Apr 1, 2014

Here's the thing: HTML5 has some super silly rules about "allowed content" for particular nodes. What this means is, there's very little we can actually do about this.

One thing that you CAN do, if you want to transclude table content into a directive which uses a select tag for its template, is to make the directive an attribute directive. This way, the browser's HTML parser won't care that you are putting <option> tags as children of the <select> tag, and you'll be able to transclude them just fine.

This is a problem with the HTML parser, and sadly, there is very little we can do to circumvent that with custom elements. Theoretically, WebComponents might address this (and may have already addressed this for the <content> tags), but for Angular 1.x, there ain't much we can do. Take it up with hixie maybe? :p

@caitp
Copy link
Contributor

caitp commented Apr 1, 2014

I'm not sure if we actually need this fix for <option> tags though, does jqLite('<option>') produce an empty collection?

@aeharding
Copy link
Author

@caitp I totally agree with you. It's kinda unfortunate that the spec is that strict, and even worse that the browser is so strict while the HTML is being manipulated (before it's actually inserted into the DOM).

Also: Yes, it looks like it does on IE9.

aeharding pushed a commit to aeharding/angular.js that referenced this issue Apr 1, 2014
the compiler will wrap it with a <select> tag. This satisfies IE9.

Closes angular#6926
@caitp
Copy link
Contributor

caitp commented Apr 2, 2014

Hmm, I see why jqLite('<option>') fails in angular 1.x but not jQuery 2.x

Our constructor for elements is extremely simple. I think we could improve this without adding too much code. The question is whether or not it's worth it.

I need something to do today though, so I'll hack on improving the jqLite HTML parser for a few minutes, we can look at it.

caitp added a commit to caitp/angular.js that referenced this issue Apr 2, 2014
Previously, the jqLite constructor was limited and would be unable to circumvent many of the HTML5
spec's "allowed content" policies for various nodes. This led to complicated and gross hacks around
this in the HTML compiler.

This change refactors these hacks by simplifying them, and placing them in jqLite rather than in
$compile, in order to better support these things, and simplify code.

While the new jqLite constructor is still not even close to as robust as jQuery, it should be more
than suitable enough for the needs of the framework, while adding minimal code.

Closes angular#6941
Closes angular#6926
caitp added a commit to caitp/angular.js that referenced this issue Apr 2, 2014
Previously, the jqLite constructor was limited and would be unable to circumvent many of the HTML5
spec's "allowed content" policies for various nodes. This led to complicated and gross hacks around
this in the HTML compiler.

This change refactors these hacks by simplifying them, and placing them in jqLite rather than in
$compile, in order to better support these things, and simplify code.

While the new jqLite constructor is still not even close to as robust as jQuery, it should be more
than suitable enough for the needs of the framework, while adding minimal code.

Closes angular#6941
Closes angular#6926
caitp pushed a commit to caitp/angular.js that referenced this issue Apr 2, 2014
caitp added a commit to caitp/angular.js that referenced this issue Apr 2, 2014
Previously, the jqLite constructor was limited and would be unable to circumvent many of the HTML5
spec's "allowed content" policies for various nodes. This led to complicated and gross hacks around
this in the HTML compiler.

This change refactors these hacks by simplifying them, and placing them in jqLite rather than in
$compile, in order to better support these things, and simplify code.

While the new jqLite constructor is still not even close to as robust as jQuery, it should be more
than suitable enough for the needs of the framework, while adding minimal code.

Closes angular#6941
Closes angular#6926
caitp pushed a commit to caitp/angular.js that referenced this issue Apr 2, 2014
caitp added a commit to caitp/angular.js that referenced this issue Apr 2, 2014
Previously, the jqLite constructor was limited and would be unable to circumvent many of the HTML5
spec's "allowed content" policies for various nodes. This led to complicated and gross hacks around
this in the HTML compiler.

This change refactors these hacks by simplifying them, and placing them in jqLite rather than in
$compile, in order to better support these things, and simplify code.

While the new jqLite constructor is still not even close to as robust as jQuery, it should be more
than suitable enough for the needs of the framework, while adding minimal code.

Closes angular#6941
Closes angular#6926
caitp pushed a commit to caitp/angular.js that referenced this issue Apr 2, 2014
caitp added a commit to caitp/angular.js that referenced this issue Apr 2, 2014
Previously, the jqLite constructor was limited and would be unable to circumvent many of the HTML5
spec's "allowed content" policies for various nodes. This led to complicated and gross hacks around
this in the HTML compiler.

This change refactors these hacks by simplifying them, and placing them in jqLite rather than in
$compile, in order to better support these things, and simplify code.

While the new jqLite constructor is still not even close to as robust as jQuery, it should be more
than suitable enough for the needs of the framework, while adding minimal code.

Closes angular#6941
Closes angular#6926
caitp pushed a commit to caitp/angular.js that referenced this issue Apr 2, 2014
caitp added a commit to caitp/angular.js that referenced this issue Apr 2, 2014
Previously, the jqLite constructor was limited and would be unable to circumvent many of the HTML5
spec's "allowed content" policies for various nodes. This led to complicated and gross hacks around
this in the HTML compiler.

This change refactors these hacks by simplifying them, and placing them in jqLite rather than in
$compile, in order to better support these things, and simplify code.

While the new jqLite constructor is still not even close to as robust as jQuery, it should be more
than suitable enough for the needs of the framework, while adding minimal code.

Closes angular#6941
Closes angular#6926
caitp pushed a commit to caitp/angular.js that referenced this issue Apr 2, 2014
caitp added a commit to caitp/angular.js that referenced this issue Apr 2, 2014
Previously, the jqLite constructor was limited and would be unable to circumvent many of the HTML5
spec's "allowed content" policies for various nodes. This led to complicated and gross hacks around
this in the HTML compiler.

This change refactors these hacks by simplifying them, and placing them in jqLite rather than in
$compile, in order to better support these things, and simplify code.

While the new jqLite constructor is still not even close to as robust as jQuery, it should be more
than suitable enough for the needs of the framework, while adding minimal code.

Closes angular#6941
Closes angular#6926
caitp pushed a commit to caitp/angular.js that referenced this issue Apr 2, 2014
caitp pushed a commit to caitp/angular.js that referenced this issue Apr 2, 2014
caitp pushed a commit to caitp/angular.js that referenced this issue Apr 2, 2014
@btford btford removed the gh: issue label Aug 20, 2014
@Narretz Narretz removed the PRs plz! label Sep 26, 2015
@mgol
Copy link
Member

mgol commented Mar 29, 2018

I'm not convinced we'll fix it given age of the ticket.

But for anyone interested, JSFiddle no longer works in IE 9 so I ported the test case to JS Bin & updated AngularJS to 1.6.9; it's still broken in IE 9 & works in IE 10+: http://output.jsbin.com/qofuhag.

@mgol mgol modified the milestones: Backlog, Ice Box Mar 29, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.