如何解决IEselect问题时dynamic更改选项

我有一套select,都有相同的选项。 然后,我通过filter运行这些选项,以便在select中不显示在不同select中select的任何选项。 看到这个jsFiddle (在非IE浏览器),看看我的意思。 基本上我阻止select中多次select相同的选项

现在,我所做的在IE中有一个问题。 在IE中打开那个小提琴(我只在IE9中试过,但我猜测以前的版本有相同的问题)。 将最后一个select更改为AAA。 注意3个其他select全部改变了他们显示的内容。 他们的模型并没有改变,但IE在某些方面窒息时,选项更改。

我的问题是第一个,我一般做这个function有问题吗? 在Chrome和FF中,这个代码正是我想要的,但是我正在做一些我不应该做的事情? 其次,我怎么能在IE浏览器中解决这个问题? 我尝试了一些会清除和重新设置模型的超时,但是显而易见的东西却跳了起来。 我想知道是否有一个良好的,干净的,低影响的解决方法。

任何帮助将非常感激。 谢谢。

–UPDATE–

这已经在Angular 1.3.3版本中使用AS Ranjan的解决scheme 修复了。 用1.3.3看新的小提琴: http : //jsfiddle.net/m2ytyapv/

//dummy code so I can post the edit 

我在另一个晚上经历了同样的问题,抛出所有我能想到的东西之后,我得出结论:IE只是不想在使用select时处理更新filter。

我的解决scheme是改变你的select看起来像这样:

  <select class="selectList" ng-repeat="currId in selectedIds" ng-model="selectedIds[$index]" ng-options="currOption.id as currOption.value for currOption in myObj | myfilter:selectedIds:$index" data-ng-change="fixIE()"></select> 

他们现在有一个class级和他们的变化。 然后在你的控制器中做这个有趣的小代码:

 $scope.fixIE = function(){ //code to check if IE so the other browsers don't get this ugly hack. var selectLists = document.querySelectorAll(".selectList"); for(var x = 0;x < selectLists.length; x++){ selectLists[x].parentNode.insertBefore(selectLists[x], selectLists[x]); } }; 

它所做的是撕掉DOM中的元素,并将其replace到相同的位置。 这是一个工作小提琴jsFiddle

我尝试过的其他一些解决scheme并没有涉及到javascript,就像切换select的显示/可见性一样。 让他们的zIndex移动。 唯一确定的就是这段代码。

我有修复。

我们必须添加和删除选项列表来触发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); }); } } } ]); 

我终于想出了一个适合我需求的解决scheme。 基本上看起来似乎发生的是,在选定的索引选项的文本指向过去是在那个地方的旧string。 我相信改变这个文本更新string和/或引用。 我做了这样的事情:

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

这里是更新的小提琴: http : //jsfiddle.net/H48sP/35/

在我的应用程序中,我有一个指令,这些select,所以我做element.find("select")而不是$("select")来限制元素select的范围。 在所有摘要循环运行后,文本被强制刷新并正确显示。

如果遇到同样的问题,您可能需要像在小提琴中一样添加$timeout ,并且/或者您可能需要稍后删除添加到选项文本的额外空间(如果这成为问题)。

在angular.js的selectDirective的render函数中添加几行以下的地方(用粗体标记为**)对我来说工作得很好。 我正在寻找是否有任何其他可能的解决scheme,而不是修补angularJS或forEach下面给出?

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

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

问题是如果IE中的标签是空白的,那么HTMLOptionElement的标签属性与text属性不同。

这可以通过在屏幕加载之后添加以下代码来validation,并查看FF和IE的Web控制台以查看区别。 如果您取消注释标签设置为文本的最后一行,则可以正常工作。 或者如上所述修补angular.js。

 // 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; }); 

这个问题似乎与filter返回的选项的顺序有关。 当您将最后一个选项更改为A ,其他select选项会更改。 什么似乎导致IE浏览器的问题是选定的选项改变的地方。 在第一个select框C中,按以下顺序从选项中select: A, B, C, D 。 选定的选项是第三个选项 。 当您将第四个select框从G更改为A ,filter会将第一个框中的选项更改为B, C, D, G 。 所选的选项现在是第二个选项 ,这会导致与IE的问题。 这可能是Angular中的一个bug,也可能是IE中的一些奇怪的行为。 我已经创build了一个分支,通过确保所选元素始终是过滤的选项中的第一个选项:

  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/ (旧)

更新:

我做了一些debugging,发现在IE中导致问题的行,但我不明白为什么。 它看起来像一个渲染错误或什么的。 我创build了另一个解决方法,不需要重新安排选项 – 这是一个指令,用于监视select元素的更改。 如果检测到更改,则会附加一个选项并立即将其删除:

 .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(); } }) }); } } } }); 

只需添加ie-select-fix来selectng-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/ (新)

我已经find了与IE浏览器相同的错误..这个错误是克隆DOM节点的结果..

如果你像(jQuery风格)那样实例化一个SELECT:

 $select = $template.clone(); 

然后做:

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

你会得到错误,如上所述..

但是,如果你实例化

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

没有错误发生:)

哦,我会去地狱的以下build议…!

我尝试了这些build议,但都没有为我工作。

我实际上是使用Angular在每个选项中填充多个选项。

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

有时,Angular会填充这些控件,新的数据会出现,但是在IE中,你不能上下滚动查看所有的选项。

但是,如果你点击F12,修改宽度,并将其恢复到原始宽度,那么IE将再次恢复原状,并且可以在值列表中上下滚动。

所以,我的解决scheme是在Angular完成填充控件之后的一秒钟左右。

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

(我告诉你这是一个狡猾的修补程序..)

还有一件事:请记住,在IE11中, navigator.appName现在将返回NETSCAPE (而不是MSIEMicrosoft Internet Explorer )…所以当你testing你的代码是在IE还是在一个体面的浏览器上运行的时候要小心。

你已经被警告..

似乎ie9有索引的问题。 拿第二个例子,并将其更改为以下代码:

  var hwcalcModule = angular.module('ie9select', []); function AnimalCtrl($scope) { $scope.categories = [{ name: "Cats", kinds: ["Lion", "Leopard", "Puma"] }, { name: "Dogs", kinds: ["Chihua-Hua", " Yorkshire Terrier", "Pitbull"] }]; $scope.animals = [{ category: $scope.categories[1], kind: $scope.categories[1].kinds[1] }]; $scope.changeCategory = function (animal) { console.log(animal.category.name); var name = animal.category.name; var index = 0; angular.forEach($scope.categories, function (currentOption) { console.log(currentOption.name); if (name == currentOption.name) { console.log(index); $scope.animals = [{ category: $scope.categories[index], kind: $scope.categories[index].kinds[0] }]; } index++; }); } } 

http://jsfiddle.net/seoservice/nFp62/10/

根据Mathew Berg的回答,我修改了它使用AngularJS指令:

 angular.module('select',[]).directive("select", function() { return { restrict: "E", require: "?ngModel", scope: false, link: function (scope, element, attrs, ngModel) { if (!ngModel) { return; } element.bind("change", function() { //Fix for IE9 where it is not able to properly handle dropdown value change //The fix is to rip out the dropdown from DOM and add it back at the same location if (isIE9){ this.parentNode.insertBefore(this, this); //this rips the elements out of the DOM and replace it into the same location. } }) } } }); 

这样修复适用于项目中的所有select元素,您不必更改任何现有的HTML标记。 我也用下面的方法来检测IE版本,把isIE9variables设置为true

 var Browser = { IsIE: function () { return navigator.appVersion.indexOf("MSIE") != -1; }, Navigator: navigator.appVersion, Version: function() { var version = 999; // we assume a sane browser if (navigator.appVersion.indexOf("MSIE") != -1) // bah, IE again, lets downgrade version number version = parseFloat(navigator.appVersion.split("MSIE")[1]); return version; } }; var oldIE = false; //Global Variable var isIE9 = false; //Global Variable if (Browser.IsIE && Browser.Version() <= 8) { oldIE = true; } if (Browser.IsIE && Browser.Version() == 9) { isIE9 = true; } 

$ watch to scope。$ watchCollection使上面的@kkurni解决scheme适用于IE9。 只是想帮助其他人在IE9中仍然有问题,当他们改变select选项。

如果您更改某个属性,则呈现会更新并同步。 一个无害的更改可能是将selectedIndex属性设置为它自己的值:

 function fixIEselect() { for (var nForm = 0; nForm < document.forms.length; ++nForm) { var form = document.forms[nForm]; var children = form.children; for (var nChild = 0; nChild < children.length; ++nChild) { var child = children.item(nChild); if (child.tagName == "SELECT") { alert("Fixed: " + child.name); child.selectedIndex = child.selectedIndex; // dummy nop but not } } } } fixIEselect(); 

在添加dynamic选项之后,执行控制重新渲染的成本较低。 所以,而不是插入/删除虚拟元素的下拉菜单,您可以重置CSS样式,导致控制渲染,例如

 selElement.style.zoom = selElement.style.zoom ? "" : 1; 

我有一个解决scheme的IEselect列表问题

修复之前: http : //plnkr.co/edit/NGwG1LUVk3ctGOsX15KI?p=preview

修复后: http : //plnkr.co/edit/a7CGJavo2m2Tc73VR28i?p=preview

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

我刚刚添加了虚拟选项的dom重新select并删除它。 让我知道它适用于你