如何在带有 ng-options 的 select 中使用 ng-class

Posted

技术标签:

【中文标题】如何在带有 ng-options 的 select 中使用 ng-class【英文标题】:How to use ng-class in select with ng-options 【发布时间】:2013-02-22 05:31:08 【问题描述】:

我有一个 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 ng-model="Blah" ng-options="person.Name for person in persons"></select>

我想以红色颜色显示具有Eligible:false的记录。 所以问题是我如何在select 中使用ng-class 来实现这一点?由于我们没有使用任何option 标签,因此如果我只是在select 元素本身中添加ng-class,它将无法工作。

【问题讨论】:

使用指令循环选项并将类应用于满足条件的选项标签 是的,我可以做到这一点,但没有办法直接做到吗?我的意思是这里必须有一种使用 ng-class 的方法。 仅供参考:我已经更新了我的答案,因为其中有一些错误。不确定这是否会影响您当前代码库中的任何内容,但如果您使用的是我之前发布的内容,您可能想看看。 【参考方案1】:

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

更新:旧代码有一些错误,自从我回答这个问题以来,我学到了一些东西。 Here is a Plunk that was redone in 1.2.2 (but should work in 1.0.X as well)

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

【讨论】:

这是一个很好的解决方案。总有拯救这一天的指令!! :D +1 弄清楚这件事很有趣。我喜欢在我创建一个新范围的地方分开并与我正在检查的孩子一起扩展它,这样我就可以 $eval 它!如此有棱角,非常有棱角。让我想在编码时发出激光噪音...... pew pew pew。 @CloudRide,别大喊大叫了。 :P ... 什么版本的 Angular? @FlorenceFoo 绝对是,但您需要选择选项标签并循环检查每个标签的值,如下所示:jsbin.com/jejim/1/edit?html,css,js,output 此代码在 angularjs 1.4 及更高版本中中断,但在以前的版本中运行良好。【参考方案2】:

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

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

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

Plunker.

【讨论】:

这可行,但我想与 ng-options 一起使用,因为一旦我将它保存在我的数据库中并刷新它,它就不会让任何值被选中。你知道如何保持我的记录被选中吗?我已经为此使用了 ng-selected 但这也行不通 这不是问题。我将 Plunker 链接附加到答案中。 谢谢哥们!!我用的是同样的东西。唯一不同的是我使用的是 jquery 版本 -1.7,因此它不支持 ng-selected。更改了版本参考,效果很好!! 很抱歉将您的答案取消标记为正确答案。您的解决方案工作正常,但它仍然不能解决我的问题的基本需求,即使用 ng-class 和 select 具有 ng-options。请不要介意 这不是问题,但在任何情况下,您都无法指示 Angular 将 ng-class 与 ng-options 一起使用,以便将自定义类应用于生成的选项标签。【参考方案3】:

我想评论接受的答案,但因为我没有足够的声望点,我必须添加一个答案。 我知道这是一个老问题,但最近将 cmets 添加到接受的答案中。

对于 angularjs 1.4.x,必须调整建议的指令以使其再次工作。 由于 ngOptions 的重大变化,选项的值不再是索引,所以行

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

不会再工作了。

如果您将 plunker 中的代码更改为

<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是item对象的id)

将指令更改为

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

让它再次工作。

当然,这不是一个通用的解决方案,因为如果您的对象中没有 id 怎么办? 然后你会在你的选项标签中找到value="object:y",其中y是angularjs生成的一个数字,但是使用这个y你不能映射到你的项目。

希望这有助于一些人在将 angularjs 更新到 1.4.x 后让他们的代码再次工作

我也尝试在ng-options 中使用track by,但没有成功。 也许在 angularjs 方面比我有更多经验的人(= 我在 angularjs 中的第一个项目)?

【讨论】:

【参考方案4】:

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

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

你可以在这里see it work。

【讨论】:

实际上只是取消将项目集合发送到过滤器(通过您的范围对象)。使用这样的索引 是的,你是对的,谢谢你的建议。当我提出这个建议时,我并不知道,过滤器一般来说有多昂贵,通过参数注入作用域并不是最佳实践的一部分。 我不会为此使用过滤器。通常过滤器也需要在服务和控制器中可用。做 DOM 操作打破了这一点。指令就是为此而设计的。【参考方案5】:

接受的答案对我不起作用,因此我使用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;

【讨论】:

这不会触发重复项目错误,因为合格需要是唯一的吗?所以这将不适用于布尔值以外的数据(是/否选择)。 对于某些数据类型来说是一个不错的简单解决方案。【参考方案6】:

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

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

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

【讨论】:

【参考方案7】:

由于声誉问题,我无法将其写为评论,但我已经更新了 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

【讨论】:

【参考方案8】:

我知道我参加聚会有点晚了,但对于那些想用纯 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 的选项,例如:

label disable when disable for value in strong> array track by trackexpr

我会在你的情况下留下如何使用它,让你找出来;-)

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

我希望这对那里的人有所帮助。 :-)

【讨论】:

【参考方案9】:

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

angular.element('select.styled').focus( function() 
  angular.element(this).find('option').addClass('myStyle');
);

【讨论】:

以上是关于如何在带有 ng-options 的 select 中使用 ng-class的主要内容,如果未能解决你的问题,请参考以下文章

angularjs的ng-options时如何设置默认值(初始值)

Angularjs:使用ng-option时如何在选择中包含空选项

关于ng-option

ng-options用法详解

如何使用$ scope变量在ng-options中预先选择默认选项

angularjs: ng-select和ng-options