web-dev-qa-db-ja.com

修正方法IEオプションを動的に変更する場合の問題の選択

同じオプションを持つすべての選択セットがあります。次に、別の選択で選択されたオプションが選択に表示されないように、フィルターを介してこれらのオプションを実行します。 this jsFiddle (IE以外のブラウザー)を参照して、意味を確認してください。基本的に、同じオプションが複数回選択されるのを防ぎます

さて、私がやったことはIEに問題があります。そのフィドルをIEで開きます(IE9でしか試していませんが、以前のバージョンでも同じ問題があると推測しています)。最後の選択をAAAに変更します。それらのモデルは変更されませんでしたが、IEオプションが変更されたときに何らかの理由でチョークが発生します。

私の質問が最初です、私はこの機能全般で何か間違ったことをしていますか?この同じコードは、ChromeとFFで必要なことを正確に行いますが、私はすべきではないことをしていますか?次に、IEでこれを回避するにはどうすればよいですか?これにより、モデルがクリアされ、リセットされますが、目立ったものが飛び回りました。

どんな助けでも大歓迎です。ありがとう。

-UPDATE-

これは fixed in Angularと一緒に version 1.3. を使用して AS Ranjanのソリューション 以下。 1.3.3をいじる: http://jsfiddle.net/m2ytyapv/

//dummy code so I can post the edit
64
dnc253

私は最終的に自分のニーズに合ったソリューションを思いつきました。基本的に、発生しているように見えるのは、選択したインデックスのオプションのテキストが、その場所にあった古い文字列を指していることです。このテキストを変更すると、文字列や参照が更新されると思います。私はこのようなことをしました:

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

更新されたフィドルは次のとおりです。 http://jsfiddle.net/H48sP/35/

私のアプリには、これらの選択があるディレクティブがあるため、element.find("select")の代わりに$("select")を使用して、要素の選択範囲を制限します。テキストは強制的に更新されるため、すべてのダイジェストサイクルの実行後に正しく表示されます。

この同じ問題に遭遇した場合は、フィドルのように_$timeout_を追加する必要があります。問題が発生した場合は、オプションテキストに追加された余分なスペースを後で削除する必要があります。

12
dnc253

私は先日同じ問題を経験し、考えられるすべてを投げた後、IEは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>

現在、クラスとng-changeがあります。次に、コントローラーでこの楽しいコードを少し実行します。

$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から要素をリッピングし、それらを同じ場所に置き換えることです。作業用フィドルjsFiddle

JavaScriptを使用しなかった他の解決策のいくつかは、selectの表示/可視性の切り替えのようなものでした。 zIndexを移動します。確かに修正されたのは、このコードだけでした。

29
Mathew Berg

修正しました。

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

Angle.jsのselectDirectiveのレンダリング機能で、次の場所(**として太字でマークされている)に数行を追加すると、うまくいきました。次に、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のラベル属性がテキスト属性と同じではないことでした。

これは、画面が読み込まれた後に次のコードを追加し、FFとIEのWebコンソールを見て違いを確認することにより確認できます。ラベルが設定されている最後の行のコメントを外した場合または、上記のようにangle.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;
});
5
A. S. Ranjan

IE with select'sで同じバグを見つけました。このバグはDOMノードのクローン作成の結果です。

(jQueryスタイル)のようなSELECTをインスタンス化する場合:

$select = $template.clone();

してから:

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

上記のバグが発生します。

ただし、インスタンス化する場合

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

バグは発生しませんでした:)

3
enslaved

この問題は、フィルターによって返されるオプションの順序に関連しているようです。最後のオプションをAに変更すると、他の選択オプションが変更されます。 IEで問題を引き起こすと思われるのは、選択されたオプションが場所を変更することです。最初の選択ボックスで、Cがオプションから次の順序で選択されます:A, B, C, D。選択されたオプションは3番目のオプションです。4番目の選択ボックスをGからAに変更すると、フィルターは最初のボックスのオプションをB, C, D, Gに変更します。選択されたオプションは2番目のオプションになり、IEで問題が発生しますこれはAngularのバグかもしれませんし、IEの奇妙な振る舞いかもしれません。選択した要素が常にフィルターされたオプションの最初のオプションであることを確認することでこれを回避するフォークを作成しました:

   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/ (古い)

更新:

いくつかのデバッグを行い、IEで問題を引き起こす行を見つけましたが、その理由はわかりません。レンダリングのバグか何かのようです。オプションの再配置を必要としない別の回避策を作成しました。これは、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を追加して、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/ (新規)

3
joakimbl

ああ、私は次のアドバイスのために地獄に行くつもりです...!

これらの提案を試みましたが、うまくいきませんでした。

私は実際にAngularを使用して、それぞれに複数のオプションを持つ選択コントロールを設定していました。

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

時々、Angularがこれらのコントロールに入力され、新しいデータが表示されますが、IEでは、すべてのオプションを表示するために上下にスクロールできませんでした。

ただし、F12キーを押して幅を変更し、元の幅に戻すと、IEが再び元に戻り、値のリストを上下にスクロールできます。

だから、私の解決策は、これを呼び出すことでしたAngularがコントロールの移植を完了した後、数秒後に:

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

(これは危険な修正であると言いました。)

もう1つ:IE11では、navigator.appNameNETSCAPEMSIEまたはMicrosoft Internet Explorerではなく)を返すことに注意してください。コードはIEまたは適切なブラウザで実行されています。

あなたは警告された.. !!

2
Mike Gledhill

Mathew Berg answerの行で、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 version to set isIE9変数から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;
}
0
Pawan Pillai

Ie9はインデックスに問題があるようです。 2番目の例を取り上げ、それを次のコードに変更しました。

  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/

0
seoservice.ch

動的オプションが追加された後、コントロールの再レンダリングを実施する安価な方法があります。したがって、ダミー要素をドロップダウンに挿入/削除する代わりに、コントロールのレンダリングを引き起こすCSSスタイルをリセットできます。

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

何らかの属性を変更すると、レンダリングが更新され、同期されます。無害な変更は、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();
0
Luchostein

IE picklist issueの回避策があります

修正前: 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にダミーオプションを追加し、削除しました。それがあなたのために働くことを教えてください

0
apurba mandal

IE9で動作するように上記の@kkurniソリューションを作成するには、scope。$ watchをscope。$ watchCollectionに変更する必要がありました。 IE9で変更された選択オプションのレンダリングに関してまだ問題を抱えている他の人たちを助けたかっただけです。

0
bazzinga