web-dev-qa-db-ja.com

ng-optionsを使用してselectでng-classを使用する方法

Personオブジェクトの配列があります

var persons = [
{Name:'John',Eligible:true},
{Name:'Mark',Eligible:true},
{Name:'Sam',Eligible:false},
{Name:'Edward',Eligible:false},
{Name:'Michael',Eligible:true}
];

私はこのようなng-optionsでselectを使用しています:

<select ng-model="Blah" ng-options="person.Name for person in persons"></select>

Eligible:false in red colorでレコードを表示したい。問題は、これを達成するためにselectng-classをどのように使用するかです。 optionタグを使用していないため、select要素自体にng-classを追加するだけでは機能しません。

36

適切なクラスでオプションを更新するngOptionsディレクティブが処理された後に、オプションを処理するディレクティブを作成できます。

Update:古いコードにはいくつかのバグがあり、この質問に答えてから少し学びました。 これは1.2.2でやり直されたPlunkです(ただし、1.0.Xでも動作するはずです)

コードはupdatedです:

app.directive('optionsClass', function ($parse) {
  return {
    require: 'select',
    link: function(scope, elem, attrs, ngSelect) {
      // get the source for the items array that populates the select.
      var optionsSourceStr = attrs.ngOptions.split(' ').pop(),
      // use $parse to get a function from the options-class attribute
      // that you can use to evaluate later.
          getOptionsClass = $parse(attrs.optionsClass);

      scope.$watch(optionsSourceStr, function(items) {
        // when the options source changes loop through its items.
        angular.forEach(items, function(item, index) {
          // evaluate against the item to get a mapping object for
          // for your classes.
          var classes = getOptionsClass(item),
          // also get the option you're going to need. This can be found
          // by looking for the option with the appropriate index in the
          // value attribute.
              option = elem.find('option[value=' + index + ']');

          // now loop through the key/value pairs in the mapping object
          // and apply the classes that evaluated to be truthy.
          angular.forEach(classes, function(add, className) {
            if(add) {
              angular.element(option).addClass(className);
            }
          });
        });
      });
    }
  };
});

マークアップでの使用方法は次のとおりです。

<select ng-model="foo" ng-options="x.name for x in items" 
   options-class="{ 'is-eligible' : eligible, 'not-eligible': !eligible }"></select>

Ng-classのように機能しますが、コレクション内のアイテムごとに基づいている点が異なります。

33
Ben Lesh

このシナリオでは、オプションタグでng-repeatを使用する場合にのみ、ngクラスを適用できます。

<select ng-model="Blah">
  <option ng-repeat="person in persons" ng-class="{red: person.Eligible}">{{person.Name}}</option>  
</select>

これにより、「適格」な人にカスタムクラスが提供されますが、CSSはバウザー間で一貫して機能しません。

Plunker

13
Stewie

受け入れられた回答についてコメントしたかったのですが、評判ポイントが足りないため、回答を追加する必要があります。これは古い質問であることは知っていますが、最近受け入れられた回答にコメントが追加されました。

Anglejs 1.4.xの場合、提案されたディレクティブは、再び機能するように適合させる必要があります。 ngOptionsの重大な変更により、オプションの値はインデックスではなくなったため、次の行

option = elem.find('option[value=' + index + ']');

もう機能しません。

プランカーのコードを

_<select ng-model="foo" ng-options="x.id as x.name for x in items" options-class="{ 'is-eligible' : eligible, 'not-eligible': !eligible }"></select>_

その結果、オプションタグの値は次のようになります。

_value="number:x"_(xはアイテムオブジェクトのID)

ディレクティブを変更します

option = elem.find('option[value=\'number:' + item.id + '\']');

再び動作するようにします。

もちろん、これは一般的な解決策ではありません。オブジェクトにidがない場合はどうでしょうか。次に、オプションタグで_value="object:y"_を見つけます。yは、angularjsによって生成された数値ですが、このyを使用すると、アイテムにマッピングできません。

これが、angularjsを1.4.xに更新した後、一部の人々が再びコードを動作させるのに役立つことを願っています

_track by_ in ng-optionsも使用しようとしましたが、機能しませんでした。たぶん、angularjsの経験が豊富な人は私(= angularjsでの私の最初のプロジェクト)でしょうか?

4
evb

赤色で表示するだけでなく、ユーザーがオプションを選択できないようにする場合は、disable when

<select 
    ng-model="Blah"
    ng-options="person.Name disable when !person.Eligible for person in persons">
</select>

その後、CSSを使用して、無効なオプションの色を設定できます。

3
lex82

ディレクティブは1つの方法ですが、カスタムフィルターを使用しました。要素の選択方法がわかっている場合は、ここで問題ありません。課題は、select内で現在のオプション要素を見つけることでした。 「含む」セレクターを使用することもできましたが、オプションのテキストはアイテムごとに一意ではない場合があります。値でオプションを見つけるために、スコープとアイテム自体を挿入しました。

<select ng-model="foo" ng-options="item.name|addClass:{eligible:item.eligible,className:'eligible',scope:this,item:item} for item in items"></select>

そしてjsで:

var app = angular.module('test', []);

app.filter('addClass', function() {
  return function(text, opt) {
    var i;
    $.each(opt.scope.items,function(index,item) {
      if (item.id === opt.item.id) {
        i = index;
        return false;
      }
    });
    var elem = angular.element("select > option[value='" + i + "']");
    var classTail = opt.className;
    if (opt.eligible) {
      elem.addClass('is-' + classTail);
      elem.removeClass('not-' + classTail);
    } else {
      elem.addClass('not-' + classTail);
      elem.removeClass('is-' + classTail);
    }
    return text;
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.items = [
    { name: 'foo',id: 'x1',eligible: true},
    { name: 'bar',id: 'x2',eligible: false}, 
    { name: 'test',id: 'x3',eligible: true}
  ];
 });

ここで 動作を確認 ができます。

3
westor

受け入れられた答えは私にはうまくいきませんでしたので、track byを使用するカスタムディレクティブのない代替を見つけました。

<select ng-model="foo" ng-options="x.name for x in items track by x.eligible"></select>

各オプションは値x.eligibleを取得します。 CSSでは、value = trueでオプションのスタイルを設定できます(trueは文字列でなければなりません)。 CSS:

option[value="true"]{
    color: red;
}
3
chriscross

私はパーティーに少し遅れていることは知っていますが、純粋なCSSでこれを解決したい人は、ディレクティブを使用せずに次のようなcssクラスを作成できます:

    select.blueSelect option[value="false"]{
    color:#01aac7;
}

このcssルールは次のとおりです。クラス「blueSelect」を持つすべての「select」内でタグ名「option」を持つvalue = falseのすべての要素を検索し、テキストの色を#01aac7にします。 (青の色合い)

あなたの場合、HTMLは次のようになります。

   <select class="form-control blueSelect" name="persons" id="persons1"
                ng-options="person as person.name for person in $ctrl.persons track by person.Eligible"
                ng-model="$ctrl.selectedPerson" required>
            <option disabled selected value="">Default value</option>
   </select>

Ng-options内の追跡は、オプションを追跡する対象、または各オプションの「値」フィールドを保持します。プロジェクトのニーズに応じて、要件に応じてこの作業を調整するには調整が必要になる場合があります。

しかし、Eligibleフィールドに同じ値を持つ複数のオプションがある場合、それは正しく機能しません。したがって、これを機能させるために、追跡する複合式を作成します。これにより、各オプションで追跡する一意の値を持つことができます。この場合、フィールドNameとEligibleの両方を組み合わせます

これで、htmlは次のようになります。

<select class="form-control blueSelect" name="persons" id="persons2"
                ng-options="person as person.name for person in $ctrl.persons track by (person.name + person.Eligible)"
                ng-model="$ctrl.selectedPerson" required>
            <option disabled selected value="">Default value</option>
   </select>

そして私たちのCSS:

    select.blueSelect option[value*="False"]{
     color:#01aac7;
 }

値の横にある*に注意してください。これは、オプション要素の値フィールドのどこかで「False」という単語を見つけることを意味する正規表現です。

クイック編集 ng-options式の "disable when"を使用して、Eligible = Falseのオプションを無効にすることもできます。例:

labelwhen whendisableforvalueinarrayトラックバイtrackexpr

あなたがあなたのケースでそれを使用する方法をあなたが見つけるために残します;-)

これは、単純なcssの変更、より複雑なもの、ディレクティブまたは他のメソッドが必要な場合に機能します。クロムでテスト済み。

私はこれがそこに誰かを助けることを願っています。 :-)

2
RGonzalez

評判のため、これをコメントとして書くことはできませんが、受け入れられた回答のプランカーをAngular 1.4.8。元の回答をありがとう、Ben Leshに感謝します。違いは、新しいAngularが次のようなオプションを生成することです。

<option class="is-eligible" label="foo" value="object:1">foo</option>

だからコード

option = elem.find('option[value=' + index + ']');

オプションを見つけることができません。私の変更はngOptionsを解析し、ラベルに使用されたアイテムのフィールドを決定し、値ではなくそれに基づいてオプションを見つけます。見る:

http://plnkr.co/edit/MMZfuNZyouaNGulfJn41

2