Cómo usar ng-class en select con ng-options

Tengo una matriz de objetos Person

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

y estoy usando select con ng-options como esta:

  

Quiero mostrar el registro con Elegible: falso en color rojo . Entonces, ¿el problema es cómo uso la ng-class en select inorder para lograr esto? Como no estamos usando ninguna etiqueta de option , no funcionará si simplemente agrego ng-class en el elemento de select .

Podría crear una directiva que procesara las opciones después de procesar la directiva ngOptions que las actualizó con las clases apropiadas.

Actualización : El código anterior tenía algunos errores, y aprendí un poco desde que contesté esta pregunta. Aquí hay un Plunk que se volvió a hacer en 1.2.2 (pero debería funcionar en 1.0.X también)

Aquí está actualizado el Código:

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

Así es como lo usarías en tu marcado:

  

Funciona como lo hace ng-class, con la excepción de que está basado en un elemento en la colección.

En este caso, solo puede aplicar ng-class si usa ng-repeat con tags de opción:

  

Esto le dará clases personalizadas a sus personas ‘Elegibles’, pero CSS no funcionará de manera consistente en todos los jugadores.

Plunker .

Quería comentar sobre la respuesta aceptada, pero como no tengo suficientes puntos de reputación, debo agregar una respuesta. Sé que esta es una pregunta antigua, pero los comentarios se agregaron recientemente a la respuesta aceptada.

Para angularjs 1.4.x, la directiva propuesta debe adaptarse para que vuelva a funcionar. Debido al cambio de ruptura en ngOptions, el valor de la opción ya no es el índice, por lo que la línea

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

ya no funcionará

Si cambia el código en el plunker a

Como resultado, el valor de la etiqueta de opción ahora será

value="number:x" (x es el id del objeto item)

Cambiar la directiva a

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

para que funcione de nuevo.

Por supuesto, esta no es una solución genérica, porque ¿qué pasa si no tiene una identificación en su objeto? Luego encontrará value="object:y" en su etiqueta de opción donde y es un número generado por angularjs, pero con este y no puede mapear a sus artículos.

Espera que esto ayude a algunas personas a obtener su código de nuevo funcionando después de la actualización de angularjs a 1.4.x.

Intenté también usar la track by en ng-options, pero no conseguí que funcionara. Tal vez las personas con más experiencia en angularjs luego yo (= mi primer proyecto en angularjs)?

La directiva es de una manera, pero utilicé un filtro personalizado. Si sabes cómo seleccionar tu elemento, deberías estar bien aquí. El desafío fue encontrar el elemento de opción actual dentro de la selección. Pude haber usado el selector “contiene” pero el texto en las opciones puede no ser exclusivo para los elementos. Para encontrar la opción por valor, inyecté el scope y el artículo en sí.

  

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

Aquí puedes verlo funcionar .

La respuesta aceptada no funcionó para mí, así que encontré una alternativa sin una directiva personalizada usando track by :

  

Cada opción ahora obtiene el valor x.eligible. En CSS puedes diseñar opciones con value = true (creo que cierto tiene que ser una cadena). CSS:

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

En caso de que no solo quiera mostrarlos en color rojo, sino que evite que el usuario seleccione las opciones, puede usar disable when :

  

A continuación, puede usar CSS para establecer el color de las opciones desactivadas.

No puedo escribir esto como un comentario, debido a la reputación, pero he actualizado el plunker para que la respuesta aceptada funcione con Angular 1.4.8. Gracias a Ben Lesh por la respuesta original, me ayudó mucho. La diferencia parece ser que Angular más nuevo genera opciones como esta:

  

entonces el código

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

no podría encontrar la opción. Mi cambio analiza ngOptions y determina qué campo de elemento se utilizó para la etiqueta, y encuentra la opción basada en eso en lugar de valor. Ver:

http://plnkr.co/edit/MMZfuNZyouaNGulfJn41

Sé que llego un poco tarde a la fiesta, pero para las personas que quieran resolver esto con CSS puro, sin usar una directiva, pueden hacer una clase de CSS así:

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

Esta regla de CSS dice: Encuentre todos los elementos con value = false con el nombre de etiqueta ‘option’ dentro de cada ‘select’ que tenga una clase “blueSelect” y haga que el color de texto sea # 01aac7; (un tono de azul)

En tu caso, tu HTML se verá así:

   

La pista dentro de las opciones ng es lo que mantendrá qué hacer un seguimiento de las opciones, o el campo “valor” de cada opción. Tenga en cuenta que, dependiendo de las necesidades de su proyecto, es posible que tenga que hacer algunas modificaciones para que esto funcione según sus requisitos.

Pero eso no va a funcionar bien cuando hay múltiples opciones con el mismo valor para el campo Elegible. Para que esto funcione, creamos una expresión compuesta para seguirla, de esa manera podemos tener valores únicos para seguir en cada opción. En este caso, combinamos ambos campos Nombre y Elegible

Así que ahora nuestro html se verá así

  

y nuestro css:

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

Observe el * al lado del valor, esta es una expresión regular que significa encontrar la palabra “False” en algún lugar del campo de valor del elemento de opción.

Edición rápida También puede optar por deshabilitar las opciones con Elegible = False usando “disable when” en la expresión ng-options, por ejemplo:

etiqueta deshabilitar cuando deshabilitar el valor en la pista de matriz por trackexpr

Dejaré cómo usar eso en tu caso para que lo averigües 😉

Esto funciona para modificaciones simples de CSS, para cosas más complejas puede necesitar una directiva u otros métodos. Probado en cromo.

Espero que esto ayude a alguien por ahí. 🙂

He encontrado otra solución que era más fácil que agregar una directiva o filtro, que es agregar un controlador para el evento en foco que aplica el estilo.

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