angular.js icon indicating copy to clipboard operation
angular.js copied to clipboard

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

Open aeharding opened this issue 11 years ago • 9 comments

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

aeharding avatar Mar 31 '14 18:03 aeharding

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 https://github.com/angular/angular.js/commit/31c450bcee53d0a3827b7e0a611e9013b2496506).

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

tbosch avatar Mar 31 '14 22:03 tbosch

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

tbosch avatar Mar 31 '14 22:03 tbosch

Definitely! I'll see what I can do.

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

Thanks again

aeharding avatar Apr 01 '14 13:04 aeharding

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).

aeharding avatar Apr 01 '14 20:04 aeharding

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 avatar Apr 01 '14 20:04 caitp

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

caitp avatar Apr 01 '14 20:04 caitp

@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 avatar Apr 01 '14 20:04 aeharding

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 avatar Apr 02 '14 14:04 caitp

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 avatar Mar 29 '18 07:03 mgol