41

我有一个 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来实现这一点?由于我们没有使用任何标签,因此如果我只是添加元素本身,它将无法工作。ng-classselectoptionng-classselect

4

9 回答 9

36

您可以创建一个在处理 ngOptions 指令后处理选项的指令,该指令使用适当的类更新它们。

更新:旧代码有一些错误,自从我回答了这个问题后,我学到了一些东西。这是一个在 1.2.2 中重做的 Plunk(但也应该在 1.0.X 中工作)

此处更新(2013 年 11 月 30 日 3:17)代码:

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 类似,不同之处在于它是基于集合中的每个项目。

于 2013-03-07T18:03:16.543 回答
15

ng-repeat在这种情况下,只有在使用选项标签时才能应用 ng-class :

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

这将为您的“合格”人员提供自定义类,但 CSS 不会在浏览器中始终如一地工作。

笨蛋

于 2013-03-07T10:12:17.900 回答
4

I wanted to comment on the accepted answer, but because I don't have enough reputation points, I must add an answer. I know that this is an old question, but comments where recently added to the accepted answer.

For angularjs 1.4.x the proposed directive must be adapted to get it working again. Because of the breaking change in ngOptions, the value of the option isn't anymore the index, so the line

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

won't work anymore.

If you change the code in the plunker to

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

As result the value of the option tag will now be

value="number:x" (x is the id of the item object)

Change the directive to

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

to get it working again.

Of course this isn't a generic solution, because what if you have not an id in your object? Then you will find value="object:y" in your option tag where y is a number generated by angularjs, but with this y you can't map to your items.

Hopes this helps some people to get their code again working after the update of angularjs to 1.4.x

I tried also to use the track by in ng-options, but didn't get it to work. Maybe people with more experience in angularjs then me (= my first project in angularjs)?

于 2015-12-11T12:35:25.283 回答
3

接受的答案对我不起作用,所以我找到了一个没有自定义指令的替代方法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;
}
于 2014-09-23T08:25:37.460 回答
3

该指令是一种方式,但我使用了自定义过滤器。如果你知道如何选择你的元素,你应该没问题。挑战是在选择中找到当前的选项元素。我本可以使用“包含”选择器,但选项中的文本对于项目可能不是唯一的。为了按值查找选项,我注入了范围和项目本身。

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

在这里你可以看到它的工作

于 2013-11-22T09:37:26.887 回答
3

如果您不仅想以红色显示它们,还想阻止用户选择选项,您可以使用disable when

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

然后,您可以使用 CSS 设置禁用选项的颜色。

于 2016-04-12T14:27:31.813 回答
2

我知道我参加聚会有点晚了,但对于那些想用纯 CSS 解决这个问题的人,不使用指令你可以像这样创建一个 css 类:

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

这个 css 规则说:在每个具有类“blueSelect”的“select”中查找 value = false 和标签名称“option”的所有元素,并使文本颜色 #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 中的 track by 将保存跟踪选项的内容,或每个选项的“值”字段。请注意,根据您的项目需求,您可能需要进行一些调整才能根据您的要求进行这项工作。

但是,当 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;
}

注意 value 旁边的 *,这是一个正则表达式,意思是在 option 元素的 value 字段中的某处找到单词“False”。

快速编辑 您还可以使用 ng-options 表达式中的“disable when”来选择禁用 Eligible = False 的选项,例如:

通过trackexpr禁用数组轨道中的标签禁用

我将在您的情况下留下如何使用它,让您了解;-)

这适用于简单的 css 修改,对于更复杂的东西,您可能需要指令或其他方法。经过铬测试。

我希望这可以帮助那里的人。:-)

于 2016-05-24T05:12:54.240 回答
2

由于声誉问题,我无法将其写为评论,但我已经更新了 plunker 以获得可接受的答案以与 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 并确定用于标签的 item 字段,并根据该字段而不是 value 找到选项。看:

http://plnkr.co/edit/MMZfuNZyouaNGulfJn41

于 2016-02-04T06:16:20.043 回答
-1

我发现了另一种比添加指令或过滤器更容易的解决方法,即为应用样式的 onfocus 事件添加处理程序。

angular.element('select.styled').focus( function() {
  angular.element(this).find('option').addClass('myStyle');
});
于 2018-04-09T13:42:12.093 回答