64 votes

Comment réparer internet explorer, sélectionnez problème lors de l'évolution dynamique des options

J'ai un ensemble de sélectionne que tous ont les mêmes options. Puis-je exécuter ces options au moyen d'un filtre de façon à ce que toutes les options sont sélectionnées dans un autre, sélectionnez ne pas afficher dans le sélectionner. Voir ce jsFiddle (non-IE) pour voir ce que je veux dire. Fondamentalement, je suis à la prévention de la possibilité d'être sélectionné plusieurs fois parmi les sélectionne

Maintenant, ce que j'ai fait a un problème dans IE. Ouvert que le violon dans IE (j'ai seulement essayé de IE9, mais je devine que les précédentes versions ont le même problème). Modifier la dernière sélectionnez AAA. Remarquez comment les 3 autres sélectionne tous changé de ce qu'ils affichent. Le modèle pour eux n'a pas changé, mais IE en quelque sorte étouffe lorsque les options sont modifiées.

Ma questions est d'abord, suis-je en train de faire quelque chose de mal avec cette fonctionnalité en général? Ce même code est exactement ce que je veux en Chrome et FF, mais je fais quelque chose que j'ai juste ne devrait pas l'être? Deuxièmement, comment puis-je obtenir autour de cette dans IE? J'ai essayé de certains délais d'attente qui serait claire et re-définir le modèle, mais les choses visibles sauté autour de. Je me demandais si il y a une bonne, propre, à faible impact solution de contournement pour ce.

Toute aide serait grandement appréciée. Merci.

29voto

Mathew Berg Points 7247

J'ai vécu la même question l'autre soir, et après avoir jeté tout ce que je pouvais penser à elle que je suis venu à la conclusion que IE ne veut tout simplement pas gérer la mise à jour des filtres lors de l'utilisation sélectionne.

Ma solution est de changer votre sélectionne pour ressembler à ceci:

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

Ils ont maintenant une classe et une ng-changement sur eux. Puis dans votre contrôleur de ce faire plaisir peu de code:

$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 est rip les éléments du DOM et de les remplacer dans le même emplacement. Voici un travail de violon jsFiddle

Certaines autres solutions que j'ai essayé et qui n'impliquent pas de javascript, c'étaient des choses comme le basculement de l'affichage et de la visibilité de la sélectionner. Ayant leur zIndex est déplacé. La seule chose que bien sûr fixe c'était ce morceau de code.

20voto

kkurni Points 527

J'ai le correctif.

Nous avons d'ajouter et de supprimer des options de la liste 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` 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);
                    });
                }
            }
        }
    ]);

12voto

dnc253 Points 11784

J'ai enfin trouvé une solution qui fonctionne pour mes besoins. Fondamentalement, ce qui semble se passer, c'est que le texte de l'option à l'index pointe de l'ancienne corde que l'habitude d'être dans ce lieu. Je crois que la modification de ce texte met à jour les chaînes de caractères et/ou des références. J'ai fait quelque chose comme ceci:

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

Voici la mise à jour du violon: http://jsfiddle.net/H48sP/35/

Dans mon application, j'ai une directive, lorsque ces sélectionne sont, et donc je ne l' element.find("select") au lieu de $("select") afin de limiter la portée de l'élément de la sélection. Le texte est obligé de rafraîchir et donc affiche correctement après toutes les digérer les cycles d'exécution.

Si vous avez rencontré ce même problème, vous devrez peut-être ajouter un $timeout comme dans le violon, et/ou vous devrez peut-être plus tard, supprimer l'espace supplémentaire qui a été ajouté à l'option de texte si cela devient un problème.

5voto

A. S. Ranjan Points 11

L'ajout de quelques lignes les endroits suivants (indiqués en caractères gras **) en fonction rendu de la selectDirective dans angular.js a bien fonctionné pour moi. Je suis à la recherche si il n'y a aucune autre solution possible, d'autres de le corriger 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);**

La question était de l'attribut label de HTMLOptionElement n'est pas le même que le texte de l'attribut si l'étiquette est vide dans IE.

Ceci peut être vu vérifié en ajoutant le code suivant après l'écran de chargement et de la recherche à la console web de FF et IE pour voir la différence. Si vous supprimez la dernière ligne de l'endroit où l'étiquette est définie au texte, il fonctionne très bien. Sinon le patch 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;
});

3voto

joakimbl Points 9081

Le problème semble être lié à l'ordre des options renvoyé par le filtre. Lorsque vous modifiez la dernière option pour A, les autres de sélectionner des options de change. Ce qui semble poser un problème pour IE, c'est que l'option sélectionnée changements de lieu. Dans la première zone de sélection d' C est sélectionné dans les options dans l'ordre suivant: A, B, C, D. L'option choisie est la troisième option. Lorsque vous modifiez la suite de sélectionner la zone de G de A, le filtre modifie les options dans la première zone de B, C, D, G. L'option sélectionnée est maintenant la deuxième option, et cela provoque un problème avec IE. Ce peut-être un bug dans Angulaire, ou il peut être un comportement étrange dans IE. J'ai créé une fourche qui travaille autour de cela, assurez-vous que l'élément sélectionné est toujours la première option de l'filtré 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/ (vieux)

Mise à jour:

J'ai fait un peu de débogage et trouvé la ligne qui provoque des problèmes dans IE, mais je ne comprends pas pourquoi. Il semble y avoir un rendu bug ou quelque chose. J'ai créé une autre solution qui ne nécessite pas de réarrangement des options - c'est une directive que les montres de changements sur l'élément select. Si un changement est détecté, il ajoute une option et le 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('<option></option>');
              element.append(tmp);
              tmp.remove();
            }
          })

        });
      }
    }
  }
});

Juste ajouter ie-sélectionnez-fix pour sélectionner des éléments à l'intérieur ng-répétitions:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X