Comment résoudre le problème de sélection d’IE lors de la modification dynamic d’options

J’ai un ensemble de sélections qui ont toutes les mêmes options. Ensuite, je lance ces options via un filtre afin que les options sélectionnées dans une sélection différente n’apparaissent pas dans la sélection. Voir ce jsFiddle (dans le navigateur non-IE) pour voir ce que je veux dire. En gros, j’empêche que la même option soit sélectionnée plusieurs fois parmi les sélections

Maintenant, ce que j’ai fait a un problème avec IE. Ouvrez ce violon dans IE (je l’ai seulement essayé dans IE9, mais je suppose que les versions précédentes ont le même problème). Changer le dernier choix à AAA. Notez comment les 3 autres sélections ont toutes changé ce qu’elles affichent. Le modèle pour eux n’a pas changé, mais IE a en quelque sorte étouffé lorsque les options sont modifiées.

Mes questions sont d’abord, est-ce que je fais quelque chose de mal avec cette fonctionnalité en général? Ce même code fait exactement ce que je veux dans Chrome et FF, mais est-ce que je fais quelque chose que je ne devrais pas faire? Deuxièmement, comment puis-je contourner cela dans IE? J’ai essayé des timeouts qui effaceraient et remettraient en place le modèle, mais les choses ont fait un bond. Je me demande s’il existe une solution de contournement efficace, propre et à faible impact.

Toute aide serait très appréciée. Merci.

–METTRE À JOUR–

Cela a été corrigé dans Angular lui-même avec la version 1.3.3 en utilisant la solution d’AS Ranjan ci-dessous. Voir le nouveau violon avec 1.3.3: http://jsfiddle.net/m2ytyapv/

//dummy code so I can post the edit 

J’ai connu le même problème l’autre soir et après avoir jeté tout ce que je pouvais imaginer, je suis arrivé à la conclusion que IE ne voulait tout simplement pas gérer les filtres de mise à jour lors de l’utilisation de selects.

Ma solution est de changer vos sélections pour ressembler à ceci:

   

Ils ont maintenant un cours et un changement sur eux. Ensuite, dans votre contrôleur, faites ce petit bout de code amusant:

 $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]); } }; 

Ce qu'il fait, c'est extraire les éléments du DOM et les remplacer au même endroit. Voici un violon de travail jsFiddle

Certaines des autres solutions que j’ai essayées qui n’impliquaient pas javascript étaient des choses comme basculer l’affichage / la visibilité de la sélection. Avoir leur zIndex déplacé. La seule chose qui à coup sûr était ce morceau de code.

J’ai le correctif

Nous devons append et supprimer la liste des options pour déclencher le rendu dans 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` atsortingbute to the model expression that should sortinggger the list to re-render. * * @example  

J’ai finalement trouvé une solution qui répond à mes besoins. Fondamentalement, il semble que le texte de l’option de l’index sélectionné pointe sur l’ancienne chaîne qui se trouvait à cet endroit. Je pense que changer ce texte met à jour les chaînes et / ou les références. J’ai fait quelque chose comme ça:

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

Voici le violon mis à jour: http://jsfiddle.net/H48sP/35/

Dans mon application, j’ai une directive où ces sélections sont, et je fais donc element.find("select") au lieu de $("select") pour limiter la scope de la sélection de l’élément. Le texte est obligé de se rafraîchir et s’affiche donc correctement après l’exécution de tous les cycles de digestion.

Si vous avez rencontré ce même problème, vous devrez peut-être append un $timeout comme dans le violon, et / ou supprimer ultérieurement l’espace supplémentaire ajouté au texte de l’option si cela pose un problème.

L’ajout de quelques lignes aux endroits suivants (marqués en gras comme **) dans la fonction de rendu de la commande selectDirective dans angular.js a bien fonctionné pour moi. Je cherche s’il y a une autre solution possible autre que le patch angularJS ou le forEach donné ci-dessous?

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

et

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

Le problème était que l’atsortingbut label de HTMLOptionElement n’était pas le même que l’atsortingbut text si l’étiquette était vide dans IE.

Cela peut être vu vérifié en ajoutant le code suivant après le chargement de l’écran et en regardant la console Web de FF et IE pour voir la différence. Si vous décommentez la dernière ligne où l’étiquette est définie sur le texte, cela fonctionne correctement. Sinon, corrigez angular.js comme ci-dessus.

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

Le problème semble être lié à l’ordre des options renvoyées par le filtre. Lorsque vous modifiez la dernière option en A , les autres options de sélection changent. Ce qui semble poser problème à IE, c’est que l’option sélectionnée change de place. Dans la première case, C est sélectionné parmi les options dans l’ordre suivant: A, B, C, D L’option sélectionnée est la troisième option . Lorsque vous modifiez la quasortingème case de sélection de G à A , le filtre modifie les options de la première case en B, C, D, G L’option sélectionnée est maintenant la deuxième option , ce qui pose un problème avec IE. Cela pourrait être un bogue dans Angular, ou un comportement étrange dans IE. J’ai créé un fork autour de cela en veillant à ce que l’élément sélectionné soit toujours la première option parmi les options filtrées:

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

Mettre à jour:

J’ai fait du débogage et trouvé la ligne qui pose problème dans IE, mais je ne comprends pas pourquoi. Cela ressemble à un bogue de rendu ou quelque chose. J’ai créé une autre solution de contournement qui ne nécessite aucune réorganisation des options – c’est une directive qui surveille les modifications sur l’élément select. Si une modification est détectée, elle ajoute une option et la supprime immédiatement:

 .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(''); element.append(tmp); tmp.remove(); } }) }); } } } }); 

Ajoutez simplement ie-select-fix pour sélectionner des éléments dans ng-repeats:

 

{{selectedIds}}

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

J’ai trouvé le même bug dans IE avec select’s .. ce bogue est le résultat du clonage de noeuds DOM.

si vous instanciez un SELECT comme (style jQuery):

 $select = $template.clone(); 

et ensuite faire:

 $select.html(''); 

vous aurez le bogue, décrit ci-dessus ..

MAIS, si vous instanciez

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

aucun bogue n’est survenu 🙂

Oh, je vais en enfer pour le conseil suivant …!

J’ai essayé ces suggestions, mais aucune n’a fonctionné pour moi.

J’utilisais en fait Angular pour remplir des contrôles sélectionnés avec plusieurs options dans chacun.

  

Parfois, Angular remplit ces commandes, les nouvelles données apparaissent, mais dans IE, vous ne pouvez pas faire défiler les options pour voir toutes les options.

Mais si vous appuyez sur F12, modifiez la largeur et la remettez à sa largeur d’origine, IE reprendrait vie et vous pourriez faire défiler la liste de valeurs vers le haut ou le bas.

Donc, ma solution a été d’appeler ceci, une seconde après que Angular ait fini de remplir les contrôles:

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

(Je vous ai dit que c’était une solution douteuse ..)

Une autre chose: rappelez-vous que dans IE11, navigator.appName retournera maintenant NETSCAPE (plutôt que MSIE ou Microsoft Internet Explorer ) … alors faites attention lorsque vous testez si votre code s’exécute sur Internet Explorer ou sur un navigateur décent.

Tu as été prévenu..!!

Il semble que 9 ont un problème avec l’index. En prenant le deuxième exemple et le changer pour le code suivant, cela a fonctionné:

  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/

Sur la base de la réponse de Mathew Berg , je l’ai modifiée pour travailler avec la directive AngularJS:

 angular.module('select',[]).directive("select", function() { return { ressortingct: "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. } }) } } }); 

De cette manière, le correctif s’applique à tous select éléments de select du projet et vous n’avez pas à modifier les balises HTML existantes. J’ai également utilisé la méthode suivante pour détecter la version d’IE pour définir la variable isIE9 sur 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; } 

J’ai dû modifier la scope. $ Watch to scope. $ WatchCollection pour que la solution @kkurni ci-dessus fonctionne pour IE9. Je voulais juste aider les autres utilisateurs qui rencontraient encore des problèmes dans IE9 à restituer des options de sélection lorsqu’ils changent.

Le rendu est mis à jour et synchronisé si vous modifiez un atsortingbut. Un changement anodin peut être de définir l’atsortingbut selectedIndex sur sa propre valeur:

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

Il existe un moyen moins onéreux d’imposer le rendu du contrôle après l’ajout d’options dynamics. Ainsi, au lieu d’insérer ou de supprimer un élément factice dans la liste déroulante, vous pouvez réinitialiser les styles CSS qui provoquent le rendu du contrôle, par exemple

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

J’ai une solution de contournement pour le problème de la liste de sélection IE

Avant de corriger: http://plnkr.co/edit/NGwG1LUVk3ctGOsX15KI?p=preview

Après correction: http://plnkr.co/edit/a7CGJavo2m2Tc73VR28i?p=preview

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

Je viens d’append une option fictive pour que le dom réexécute la sélection et la supprime. laissez-moi savoir que cela fonctionne pour vous