How to fix IE select issue when dynamically changi

2019-01-13 03:44发布

I have a set of selects that all have the same options. Then I run those options through a filter so that any options that are selected in a different select don't show up in the select. See this jsFiddle (in non-IE browser) to see what I mean. Basically I'm preventing the same option from being selected multiple times among the selects

Now, what I've done has an issue in IE. Open that fiddle in IE (I've only tried it in IE9, but I'm guessing previous versions have the same issue). Change the last select to AAA. Notice how the 3 other selects all changed what they display. The model for them did not change, but IE somehow chokes when the options are changed.

My questions is first, am I doing something wrong with this functionality in general? This same code does exactly what I want in Chrome and FF, but am I doing something that I just shouldn't be? Second, how can I get around this in IE? I tried some timeouts that would clear and re-set the model, but things noticeable jumped around. I'm wondering if there's a good, clean, low impact workaround for this.

Any help would be much appreciated. Thanks.

--UPDATE--

This has been fixed in Angular itself with version 1.3.3 using A. S. Ranjan's solution below. See new fiddle with 1.3.3: http://jsfiddle.net/m2ytyapv/

//dummy code so I can post the edit

13条回答
看我几分像从前
2楼-- · 2019-01-13 04:23

I have the fix.

We have to add and remove options list to trigger the rendering in IE8.

http://kkurni.blogspot.com.au/2013/10/angularjs-ng-option-with-ie8.html


/**
 * Fix for IE select menus getting stuck when their underlying list changes.
 * Original code: http://kkurni.blogspot.com.au/2013/10/angularjs-ng-option-with-ie8.html
 * 
 * Set the `ie-select-fix` attribute to the model expression that should trigger the list to re-render.
 * 
 * @example <select ng-model="modelValue" ie-select-fix="itemList" ng-options="item.label for item in itemList">
 */
app.directive('ieSelectFix', ['$document',
        function($document) {

            return {
                restrict: 'A',
                require: 'ngModel',
                link: function(scope, element, attributes, ngModelCtrl) {
                    var isIE = $document[0] && $document[0].attachEvent;
                    if (!isIE) return;

                    var control = element[0];
                    //to fix IE8 issue with parent and detail controller, we need to depend on the parent controller
                    scope.$watch(attributes.ieSelectFix, function() {
                        // setTimeout is needed starting from angular 1.3+
                        setTimeout(function() {
                            //this will add and remove the options to trigger the rendering in IE8
                            var option = document.createElement("option");
                            control.add(option,null);
                            control.remove(control.options.length-1);
                        }, 0);
                    });
                }
            }
        }
    ]);
查看更多
Explosion°爆炸
3楼-- · 2019-01-13 04:26

The problem seems to be related to the order of the options returned by the filter. When you change the last option to A, the other select options changes. What seems to cause a problem for IE is that the selected option changes place. In the first select box C is selected from the options in the following order: A, B, C, D. The selected option is the third option. When you change the forth select box from G to A, the filter changes the options in the first box to B, C, D, G. The selected option is now the second option, and this causes a problem with IE. This might be a bug in Angular, or it might be to some strange behavior in IE. I've created a fork that works around this by making sure that selected element is always the first option from the filtered options:

   var newOptions = [],selected;
    angular.forEach(allOptions, function (currentOption) {
        if (!isIdInUse(selectedIds, currentOption.id)){
            newOptions.push(currentOption);
        }else if(currentOption.id == selectedIds[parseInt(index)]){
            selected = currentOption;
        }
    });
    if(selected){newOptions.unshift(selected);}

http://jsfiddle.net/XhxSD/ (old)

Update:

I did some debugging and found the line that causes problems in IE, but I don't understand why. It does seem like a rendering bug or something. I've created another workaround that doesn't require any rearranging of the options - it's a directive that watches for changes on the select element. If a change is detected it appends an option and removes it immediately:

.directive('ieSelectFix',function($timeout){
  return {
    require:'select',
    link: function (scope, element) {
      var isIE = document.attachEvent;

      if(isIE){
        $timeout(function(){
          var index = element.prop('selectedIndex'), children = element.children().length;
          scope.$watch(function(){
            if(index !== element.prop('selectedIndex') || children !== element.children().length){
              index = element.prop('selectedIndex');
              children = element.children().length;
              var tmp =angular.element('<option></option>');
              element.append(tmp);
              tmp.remove();
            }
          })

        });
      }
    }
  }
});

Just add ie-select-fix to select elements inside ng-repeats:

<div ng-app="myApp" ng-controller="MyCtrl">
  <select ie-select-fix ng-repeat="currId in selectedIds" ng-model="selectedIds[$index]"  ng-options="currOption.id as currOption.value for currOption in myObj | myfilter:selectedIds:$index"></select><br>
  {{selectedIds}}
</div>

http://jsfiddle.net/VgpyZ/ (new)

查看更多
手持菜刀,她持情操
4楼-- · 2019-01-13 04:27

I have a workaround for the IE picklist issue

Before Fix:http://plnkr.co/edit/NGwG1LUVk3ctGOsX15KI?p=preview

After Fix:http://plnkr.co/edit/a7CGJavo2m2Tc73VR28i?p=preview

$("select").click(function(){
  $(this).append('<option></option>');
   $(this).find('option:last').remove();

});

I just added dummy option for the dom to rerender the select and removed it. let me know it works for you

查看更多
欢心
5楼-- · 2019-01-13 04:29

I've finally come up with a solution that works for my needs. Basically what appears to be happening is that the text for the option at the selected index is pointing to the old string that used to be in that place. I believe changing this text updates the strings and/or references. I did something like this:

angular.forEach($("select"), function (currSelect) {
     currSelect.options[currSelect.selectedIndex].text += " ";
});

Here is the updated fiddle: http://jsfiddle.net/H48sP/35/

In my app, I have a directive where these selects are, and so I do element.find("select") instead of $("select") to limit the scope of the element selecting. The text is forced to refresh and so displays correctly after all the digest cycles run.

If you have run into this same issue, you may need to add a $timeout like in the fiddle, and/or you may need to later remove the extra space that was added to the option text if that becomes a problem.

查看更多
再贱就再见
6楼-- · 2019-01-13 04:29

Oh, I'm going to hell for the following advice...!

I tried these suggestions, but none worked for me.

I was actually using Angular to populate select controls with multiple options in each.

<select class="cssMultipleSelect" multiple="multiple" ...>

Sometimes, Angular would populate these controls, the new data would appear, but in IE, you couldn't scroll up and down to view all of the options.

But, if you hit F12, modified the width, and put it back to its original width, then IE would burst back into life again, and you could scroll up and down in the list of values.

So, my solution was to call this, a second or so after Angular had finished populating the controls:

function RefreshMultipleSelectControls()
{
    //  A dodgy fix to an IE11 issue.
    setTimeout(function () {
        $(".cssMultipleSelect").width("");
    }, 1500);
    setTimeout(function () {
        $(".cssMultipleSelect").width(298);
    }, 1600);
}

(I told you this was a dodgy fix..)

One other thing: remember that in IE11, navigator.appName will now return NETSCAPE (rather than MSIE or Microsoft Internet Explorer)... so be careful when you're testing if your code is running on IE, or on a decent browser.

You've been warned..!!

查看更多
放我归山
7楼-- · 2019-01-13 04:32

i've found the same bug in IE with select's.. this bug is the result of cloning DOM nodes..

if you instantiating a SELECT like (jQuery style):

$select = $template.clone();

and then doing:

$select.html('<option>111</option>');

you'll get the bug, described above..

BUT, if you instantiate

$select = $('< div />').html( $template ).html();

no bugs occurred :)

查看更多
登录 后发表回答