¿Cómo aplico condicionalmente los estilos CSS en AngularJS?

309

Q1. Supongamos que quiero alterar el aspecto de cada "elemento" que un usuario marca para su eliminación antes de presionar el botón principal "eliminar". (Esta retroalimentación visual inmediata debería eliminar la necesidad del proverbial cuadro de diálogo "¿estás seguro?"). El usuario marcará las casillas de verificación para indicar qué elementos se deben eliminar. Si una casilla de verificación no está marcada, ese elemento debería volver a su aspecto normal.

¿Cuál es la mejor manera de aplicar o eliminar el estilo CSS?

Q2 Supongamos que quiero permitir que cada usuario personalice cómo se presenta mi sitio. Por ejemplo, seleccione de un conjunto fijo de tamaños de fuente, permita colores de primer plano y fondo definibles por el usuario, etc.

¿Cuál es la mejor manera de aplicar el estilo CSS que el usuario selecciona / ingresa?

Mark Rajcok
fuente
artículo útil tech-blog.maddyzone.com/javascript/…
Rituraj ratan

Respuestas:

485

Angular proporciona una serie de directivas integradas para manipular el estilo CSS de forma condicional / dinámica:

  • ng-class : se usa cuando el conjunto de estilos CSS es estático / conocido de antemano
  • ng-style : utilícelo cuando no pueda definir una clase CSS porque los valores de estilo pueden cambiar dinámicamente. Piense en el control programable de los valores de estilo.
  • ng-show y ng-hide : utilícelo si solo necesita mostrar u ocultar algo (modifica CSS)
  • ng-if : nuevo en la versión 1.1.5, use en lugar del ng-switch más detallado si solo necesita verificar una sola condición (modifica DOM)
  • ng-switch : use en lugar de usar varios ng-shows mutuamente excluyentes (modifica DOM)
  • ng-disabled y ng-readonly : se usa para restringir el comportamiento del elemento de formulario
  • ng-animate : nuevo en la versión 1.1.4, se usa para agregar transiciones / animaciones CSS3

La "forma angular" normal implica vincular una propiedad de modelo / alcance a un elemento de la interfaz de usuario que acepte la entrada / manipulación del usuario (es decir, usar ng-model), y luego asociar esa propiedad de modelo a una de las directivas incorporadas mencionadas anteriormente.

Cuando el usuario cambia la IU, Angular actualizará automáticamente los elementos asociados en la página.


Q1 suena como un buen caso para ng-class: el estilo CSS se puede capturar en una clase.

ng-class acepta una "expresión" que debe evaluar uno de los siguientes:

  1. una cadena de nombres de clase delimitados por espacios
  2. una matriz de nombres de clase
  3. un mapa / objeto de nombres de clase a valores booleanos

Suponiendo que sus elementos se muestran usando ng-repeat sobre algún modelo de matriz, y que cuando se marca la casilla de verificación de un elemento, desea aplicar la pending-deleteclase:

<div ng-repeat="item in items" ng-class="{'pending-delete': item.checked}">
   ... HTML to display the item ...
   <input type="checkbox" ng-model="item.checked">
</div>

Arriba, utilizamos el tipo de expresión ng-class # 3 - un mapa / objeto de nombres de clase a valores booleanos.


Q2 parece un buen caso para ng-style: el estilo CSS es dinámico, por lo que no podemos definir una clase para esto.

ng-style acepta una "expresión" que debe evaluar para:

  1. un mapa / objeto de nombres de estilo CSS a valores CSS

Para un ejemplo artificial, suponga que el usuario puede escribir un nombre de color en un cuadro de texto para el color de fondo (un selector de color jQuery sería mucho mejor):

<div class="main-body" ng-style="{color: myColor}">
   ...
   <input type="text" ng-model="myColor" placeholder="enter a color name">


Violín para los dos anteriores.

El violín también contiene un ejemplo de ng-show y ng-hide . Si se marca una casilla de verificación, además del color de fondo que se vuelve rosa, se muestra algo de texto. Si se ingresa 'rojo' en el cuadro de texto, se oculta un div.

Mark Rajcok
fuente
¡Esta respuesta es excelente! ¿Estaría dispuesto a mostrarme a través de jsfiddle cuál sería la diferencia si el evento click estuviera cambiando / agregando una clase en un área que no era el elemento cliqueado? Diga un div en otra parte de la página.
tehaaron
es útil artículo tech-blog.maddyzone.com/javascript/…
Rituraj ratan
Gran respuesta. Por cierto, ¿alguna vez has intentado aplicar un filtro angular a ng-style?
Evi Song
Sugiero agregar una opción adicional relacionada con Q2 que acabo de agregar en mi respuesta reciente a esta pregunta.
Gavin Palmer el
105

He encontrado problemas al aplicar clases dentro de elementos de tabla cuando ya tenía una clase aplicada a toda la tabla (por ejemplo, un color aplicado a las filas impares <myClass tbody tr:nth-child(even) td>). Parece que cuando inspecciona el elemento con Developer Tools , element.styleno tiene estilo asignado. Entonces, en lugar de usar ng-class, he intentado usar ng-style, y en este caso, el nuevo atributo CSS aparece dentro element.style. Este código funciona muy bien para mí:

<tr ng-repeat="element in collection">

    [...amazing code...]

    <td ng-style="myvar === 0 && {'background-color': 'red'} ||
                  myvar === 1 && {'background-color': 'green'} ||
                  myvar === 2 && {'background-color': 'yellow'}">{{ myvar }}</td>

    [...more amazing code...]

</tr>

Myvar es lo que estoy evaluando, y en cada caso aplico un estilo a cada uno <td>según el valor de myvar , que sobrescribe el estilo actual aplicado por la clase CSS para toda la tabla.

ACTUALIZAR

Si desea aplicar una clase a la tabla, por ejemplo, al visitar una página o en otros casos, puede usar esta estructura:

<li ng-class="{ active: isActive('/route_a') || isActive('/route_b')}">

Básicamente, lo que necesitamos para activar una clase ng es la clase a aplicar y una declaración verdadera o falsa. Verdadero aplica la clase y falso no. Así que aquí tenemos dos verificaciones de la ruta de la página y un OR entre ellas, por lo que si estamos en /route_a OR estamos en route_b, se aplicará la clase activa .

Esto funciona simplemente teniendo una función lógica a la derecha que devuelve verdadero o falso.

Entonces, en el primer ejemplo, ng-style está condicionado por tres declaraciones. Si todos son falsos, no se aplica ningún estilo, pero siguiendo nuestra lógica, se aplicará al menos uno, por lo tanto, la expresión lógica verificará qué comparación de variables es verdadera y porque una matriz no vacía siempre es verdadera, eso será dejó una matriz como retorno y con solo un verdadero, considerando que estamos usando OR para toda la respuesta, se aplicará el estilo restante.

Por cierto, olvidé darle la función isActive ():

$rootScope.isActive = function(viewLocation) {
    return viewLocation === $location.path();
};

NUEVA ACTUALIZACIÓN

Aquí tienes algo que encuentro realmente útil. Cuando necesite aplicar una clase según el valor de una variable, por ejemplo, un icono según el contenido de la misma div, puede usar el siguiente código (muy útil en ng-repeat):

<i class="fa" ng-class="{ 'fa-github'   : type === 0,
                          'fa-linkedin' : type === 1,
                          'fa-skype'    : type === 2,
                          'fa-google'   : type === 3 }"></i>

Iconos de Font Awesome

Timbergus
fuente
qué extraña sintaxis, && debería significar Y, como en cualquier otro lenguaje inspirado en c
Pizzaiola Gorgonzola
3
@PizzaiolaGorgonzola && significa AND y || significa OR. Es un truco inteligente que utiliza la lógica de cortocircuito casi como una declaración de caso / interruptor ...
Stein G. Strindhaug
Gracias mit. No me di cuenta de ese detalle.
Timbergus 01 de
¡La nueva sección de actualización funcionó de maravilla! +1 por ello!
Matias
Utilicé el ejemplo de ng-class como se menciona en Nueva actualización, funcionó bastante bien para mí. Bastante elegante
Acewin
34

Esto funciona bien cuando no se puede usar ng-class (por ejemplo, al diseñar SVG):

ng-attr-class="{{someBoolean && 'class-when-true' || 'class-when-false' }}"

(Creo que necesitas estar en el último Angular inestable para usar ng-attr-, actualmente estoy en 1.1.4)

He publicado un artículo sobre cómo trabajar con AngularJS + SVG. Habla sobre este tema y muchos otros. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS

Ashley Davis
fuente
No veo ninguna mención de ng-attr en los documentos 1.1.4 . ¿Tiene un enlace?
Mark Rajcok
Lo siento, no tengo un enlace. Lo descubrí siguiendo los foros de Angular, aunque no recuerdo la página exacta, lo siento.
Ashley Davis
1
Los últimos documentos (v1.2) describen ng-attr-en la página de directivas , sección enlaces de atributos ngAttr .
Mark Rajcok
Con 1.2, esto se convierte en una gran respuesta. ng-classno te permite realizar la lógica, pero lo ng-attr-classhace. Ambos tienen sus usos, pero puedo apostar que muchos desarrolladores estarán buscando ng-attr-class.
Hylianpuffball
Conseguí que esto funcionara bien cuando fallaron otras soluciones proporcionadas aquí. Gracias.
dps
13
span class="circle circle-{{selectcss(document.Extension)}}">

y código

$scope.selectcss = function (data) {
    if (data == '.pdf')
        return 'circle circle-pdf';
    else
        return 'circle circle-small';
};

css

.circle-pdf {
    width: 24px;
    height: 24px;
    font-size: 16px;
    font-weight: 700;
    padding-top: 3px;
    -webkit-border-radius: 12px;
    -moz-border-radius: 12px;
    border-radius: 12px;
    background-image: url(images/pdf_icon32.png);
}
Nenad Jesic
fuente
Siempre evite la palabra de
FI
Quiero alentar a evitar usar directamente el atributo de clase. Esto sobrescribirá los cambios realizados por otros complementos en este elemento.
SimonSimCity
10

Esta solución me sirvió.

<a ng-style="{true: {paddingLeft: '25px'}, false: {}}[deleteTriggered]">...</a>
iamtankist
fuente
8

Puedes usar expresiones ternarias. Hay dos maneras de hacer esto:

<div ng-style="myVariable > 100 ? {'color': 'red'} : {'color': 'blue'}"></div>

o...

<div ng-style="{'color': (myVariable > 100) ? 'red' : 'blue' }"></div>
michal-michalak
fuente
1
Tal vez lo encuentre mejor: <div ng-style = "{'color': (myVariable> 100)? 'Rojo': 'azul'}"> </div>
Dudi
Dudi, si no mejor, igual de útil, así que lo agregué a la respuesta de "expresión ternaria" de @ maykel. ¡Gracias a los dos!
jbobbins
7

Otra opción cuando necesita un estilo CSS simple de una o dos propiedades:

Ver:

<tr ng-repeat="element in collection">
    [...amazing code...] 
    <td ng-style="{'background-color': getTrColor(element.myvar)}">
        {{ element.myvar }}
    </td>
    [...more amazing code...]
</tr>

Controlador:

$scope.getTrColor = function (colorIndex) {
    switch(colorIndex){
        case 0: return 'red';
        case 1: return 'green';
        default: return 'yellow';
    }
};
Dudi
fuente
6

Ver el siguiente ejemplo

<!DOCTYPE html>
    <html ng-app>
    <head>
    <title>Demo Changing CSS Classes Conditionally with Angular</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script src="res/js/controllers.js"></script>

    <style>

    .checkboxList {
        border:1px solid #000;
        background-color:#fff;
        color:#000;
        width:300px;
        height: 100px;
        overflow-y: scroll;
    }

    .uncheckedClass {
       background-color:#eeeeee;
       color:black;
    }
    .checkedClass {
        background-color:#3ab44a;
        color:white;
    }
    </style>

    </head>
    <body ng-controller="TeamListCtrl">
    <b>Teams</b>
    <div id="teamCheckboxList" class="checkboxList">

    <div class="uncheckedClass" ng-repeat="team in teams" ng-class="{'checkedClass': team.isChecked, 'uncheckedClass': !team.isChecked}">

    <label>
    <input type="checkbox" ng-model="team.isChecked" />
    <span>{{team.name}}</span>
    </label>
    </div>
    </div>
    </body>
    </html>
Ranga Reddy
fuente
2

A partir de AngularJS v1.2.0rc, ng-classe incluso ng-attr-classfallan con elementos SVG (funcionaron antes, incluso con un enlace normal dentro del atributo de clase)

Específicamente, ninguno de estos funciona ahora:

ng-class="current==this_element?'active':' ' "
ng-attr-class="{{current==this_element?'active':' '}}"
class="class1 class2 .... {{current==this_element?'active':''}}"

Como solución alternativa, tengo que usar

ng-attr-otherAttr="{{current==this_element?'active':''}}"

y luego estilo usando

[otherAttr='active'] {
   ... styles ...
}
kumarharsh
fuente
1

Una forma más (en el futuro) de aplicar estilo condicionalmente es creando un estilo con alcance

<style scoped type="text/css" ng-if="...">

</style>

Pero hoy en día solo FireFox admite estilos con ámbito.

Pavel Voronin
fuente
1

Hay una opción más que descubrí recientemente que algunas personas pueden encontrar útil porque le permite cambiar una regla CSS dentro de un elemento de estilo, evitando así la necesidad de uso repetido de una directiva angular como ng-style, ng-class, ng-show, ng-hide, ng-animate y otros.

Esta opción hace uso de un servicio con variables de servicio establecidas por un controlador y vigiladas por una directiva de atributos que llamo "estilo personalizado". Esta estrategia podría usarse de muchas maneras diferentes, e intenté proporcionar una guía general con este violín .

var app = angular.module('myApp', ['ui.bootstrap']);
app.service('MainService', function(){
    var vm = this;
});
app.controller('MainCtrl', function(MainService){
    var vm = this;
    vm.ms = MainService;
});
app.directive('customStyle', function(MainService){
    return {
        restrict : 'A',
        link : function(scope, element, attr){
            var style = angular.element('<style></style>');
            element.append(style);
            scope.$watch(function(){ return MainService.theme; },
                function(){
                    var css = '';
                    angular.forEach(MainService.theme, function(selector, key){
                        angular.forEach(MainService.theme[key], function(val, k){
                            css += key + ' { '+k+' : '+val+'} ';
                        });                        
                    });
                    style.html(css);
                }, true);
        }
    };
});
Gavin Palmer
fuente
1

bueno, le sugiero que verifique la condición en su controlador con una función que devuelva verdadero o falso .

<div class="week-wrap" ng-class="{today: getTodayForHighLight(todayDate, day.date)}">{{day.date}}</div>

y en su controlador verifique la condición

$scope.getTodayForHighLight = function(today, date){
    return (today == date);
}
sheelpriy
fuente
0

Una cosa a tener en cuenta es que, si el estilo CSS tiene guiones, debe eliminarlos. Entonces, si desea configurar background-color, la forma correcta es:

ng-style="{backgroundColor:myColor}" 
Neil Munro
fuente
55
No, no tienes que hacerlo. ng-style = "{'background-color': myColor}" funciona perfectamente bien.
gerasalus
0

Así es como apliqué con estilo el estilo de texto gris en un botón deshabilitado

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  styleUrls: [ './app.component.css' ],
  template: `
  <button 
    (click)='buttonClick1()' 
    [disabled] = "btnDisabled"
    [ngStyle]="{'color': (btnDisabled)? 'gray': 'black'}">
    {{btnText}}
  </button>`
})
export class AppComponent  {
  name = 'Angular';
  btnText = 'Click me';
  btnDisabled = false;
  buttonClick1() {
    this.btnDisabled = true;
    this.btnText = 'you clicked me';
    setTimeout(() => {
      this.btnText = 'click me again';
      this.btnDisabled = false
      }, 5000);
  }
}

Aquí hay un ejemplo de trabajo:
https://stackblitz.com/edit/example-conditional-disable-button?file=src%2Fapp%2Fapp.component.html

BraveNewMath
fuente