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

IE8 - 10: Rendering doesn't seem to work properly with select directive #4749

Closed
wesleycho opened this issue Nov 1, 2013 · 15 comments
Closed

Comments

@wesleycho
Copy link
Contributor

I am not able to reproduce this currently unfortunately, but I am seeing some strange behavior here for these browsers in particular with 1.2.0-rc.2. For Chrome & Firefox, this works just fine.

We have select elements nested in an ng-repeat, and each repeated element has two selects, one to set a parent object to one model, and the other to set a child object of the parent to another model. The select element with the children objects are filtered in ng-options according to the repeater array in ng-repeat, and the particular instance object from ng-repeat (i.e. ng-repeat="item in items", so ng-options=".... foo in array | filter: filterFoos(items, item)). The filter modifies the items you can select from in the second select element according to what has already been selected for that particular parent object, say subtopics of a parent topic & not being allowed to select a duplicate of what has already been selected.

In IE8 - 10, I can select the same parent topic in two different repeated select elements. I can then select different children options for the first time in each of the other repeated select elements, and the filter displays the correct set. However, once you change one of those selected options for the select that selects from children objects, IE8 - 10 lose track, and fail to render them correctly.

I have a scope.$watch in the controller that is dealing with this template, and currently I employ this hack to make the problem a benign one in IE8:

`$timeout(function () {
  $('.lte9 select').each(function (idx, elem) {
    $(elem).find('option').each(function (idx2, option) {
      $(option.text($(option).text() + ' ');
    });
  });
  $(elem).hide().show();
});

However, this does not solve the problem of the same value showing in IE9 and IE10 when the loss of correct rendering happens - Angular is still keeping track of the model correctly, and Angular renders the DOM correctly here. This is an IE display problem with dynamic options that isn't quite solved correctly in Angular.

It should be noted, that hack could easily be implemented in a directive without jQuery for those interested readers.

@wesleycho
Copy link
Contributor Author

Just a further update on this if anyone is stuck here, I updated this hack in order to get correct behavior in IE9 & IE10 with this:

$timeout(function () {
  $('.lte10 select').each(function (dx, elem) {
    elem.options[elem.selectedIndex].text += ' '
  });
});

@ghost ghost assigned btford Jan 4, 2014
@IgorMinar
Copy link
Contributor

@wesleycho if this is just a rendering issue then you should pass false argument to $timeout so that a digest is not triggered unnecessarily

@IgorMinar
Copy link
Contributor

a fix that could make it into angular could most likely not use $timeout, is there another way around this?

@wesleycho
Copy link
Contributor Author

I could take a look at it, this hack was created under extreme time pressure - the problem is purely a rendering issue though due to IE8 - 10 (not sure about 11) not correctly rendering updated options in the select element.

@tbosch tbosch modified the milestones: 1.2.12, 1.2.11 Feb 3, 2014
@wesleycho
Copy link
Contributor Author

So I did some investigation, and it would appear that the fix should appear inside the render function of the select directive. However, the two "fixes" I came up with both cause IE to execute a blur as soon as you click the select element, but otherwise work as they're supposed to in forcing the browser re-render.

I might have been looking in the wrong place to try to implement a fix, but I suspect that scope.$watch(render) may be causing the render callback to fire an excessive number of times and somehow is related to the fixes I came up with not working in an acceptable manner.

The issue here is that cloning a DOM template (in this case, the usage of var optionTemplate = jqLite(document.createElement('option') & optionTemplate.clone()) along with a potentially async execution causes IE to not update DOM rendering appropriately. However, simply replacing all usage of optionTemplate.clone() with document.createElement('option') does not seem to be enough to fix this issue.

From what I understand, this is a problem present in all IE browsers, including IE11.

@tbosch tbosch modified the milestones: 1.2.13, 1.2.12 Feb 7, 2014
@jreading
Copy link

+1

@btford btford modified the milestones: 1.2.14, 1.2.13 Feb 15, 2014
@IgorMinar IgorMinar modified the milestones: 1.3.0-beta.1, 1.2.14 Mar 1, 2014
@btford btford modified the milestones: 1.3.x, 1.3.0-beta.1 Mar 4, 2014
@Viatori
Copy link

Viatori commented Jun 10, 2014

+1 Any fixes for this yet?

@dnchristiansen
Copy link

Can the priority on this be increased? It happens with what seems to me to be a very common use case. If your model doesn't have any kind of initial value, the select gets messed up the first time you select an option. See the following fiddles:

http://jsfiddle.net/eFP4g/ (1.2.20)
http://jsfiddle.net/yc4Uw/ (1.3.0-beta.15)

It happens in IE9, IE10, and IE11

It looks like this specific issue was fixed with 1.2.21 (http://jsfiddle.net/sLC9b/). I'm guessing this is the same as issue #7692

@caitp
Copy link
Contributor

caitp commented Jul 15, 2014

this is being worked on @dnchristiansen

@dnchristiansen
Copy link

If it helps, I posted a SO on this when we first ran into this. There a few different workarounds people came up with.

http://stackoverflow.com/questions/12942681/how-to-fix-ie-select-issue-when-dynamically-changing-options

@asranjan
Copy link

Adding couple of lines the following places (marked in bold as ** ) in render function of the selectDirective in angular.js worked fine for me. I am looking if there is any other possible solution other than patching angularJS or the forEach given below?

            if (existingOption.label !== option.label) {
              lastElement.text(existingOption.label = option.label);
              **lastElement.attr('label', existingOption.label);**
            }

and

              (element = optionTemplate.clone())
                  .val(option.id)
                  .attr('selected', option.selected)
                  .text(option.label);
              **element.attr('label', option.label);**

The issue was the label attribute of HTMLOptionElement is not the same as the text attribute if label is blank in IE.

This can be seen verified by adding the following code after the screen has loaded and looking at the web console of FF and IE to see the difference. If you uncomment the last line where the label is set to text it works fine. Alternatively patch angular.js as above.

// This is an IE fix for not updating the section of dropdowns which has ng-options with filters
angular.forEach($("select"), function (currSelect) {
    console.log("1.text ", currSelect.options[currSelect.selectedIndex].text);
    console.log("1.label ", currSelect.options[currSelect.selectedIndex].label);
    //console.log("1.innerHTML ", currSelect.options[currSelect.selectedIndex].innerHTML);
    //console.log("1.textContent ", currSelect.options[currSelect.selectedIndex].textContent);
    //console.log("1.cN.data ", currSelect.options[currSelect.selectedIndex].childNodes[0].data);
    //console.log("1.cN.nodeValue ", currSelect.options[currSelect.selectedIndex].childNodes[0].nodeValue);
    //console.log("1.cN.textContent ", currSelect.options[currSelect.selectedIndex].childNodes[0].textContent);
    //console.log("1.cN.wholeText ", currSelect.options[currSelect.selectedIndex].childNodes[0].wholeText);
    //console.log("1. ", currSelect.options[currSelect.selectedIndex], "\n");

    //currSelect.options[currSelect.selectedIndex].label = "xyz";
    //currSelect.options[currSelect.selectedIndex].label = currSelect.options[currSelect.selectedIndex].text;
});

@wesleycho
Copy link
Contributor Author

That is not a good patch for Angular, as Angular should not be requiring jQuery in order to fix this issue, or be running a very unperformant block of code like such, due to essentially calling document.getElementsByTagName & iterating over each node on each $digest.

From what I understand from @rodyhaddad, this has been fixed on master - can you confirm @caitp?

@caitp
Copy link
Contributor

caitp commented Aug 14, 2014

cdc7db3 and c286094 reverts part of the (select) problem, but I don't know if it actually fixes the issue.

@dnchristiansen
Copy link

Adding the two lines of code from @asranjan above fixes the issue for me. Any reason those changes couldn't be made in the angular code?

@btford btford removed the gh: issue label Aug 20, 2014
@IgorMinar
Copy link
Contributor

this has been fixed already and works as expected in IE10 with 1.3.0-rc.2: http://jsfiddle.net/9kmk1wsv/1/

if there are still some remaining issues, please create a jsfiddle/plunker and a new issue. thanks!

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

10 participants