Como aplico condicionalmente estilos CSS no AngularJS?

309

Q1 Suponha que eu queira alterar a aparência de cada "item" que um usuário marca para exclusão antes que o botão principal "excluir" seja pressionado. (Esse feedback visual imediato deve eliminar a necessidade da proverbial caixa de diálogo "você tem certeza?".) O usuário marcará as caixas de seleção para indicar quais itens devem ser excluídos. Se uma caixa de seleção estiver desmarcada, esse item deve voltar à sua aparência normal.

Qual é a melhor maneira de aplicar ou remover o estilo CSS?

Q2 Suponha que eu queira permitir que cada usuário personalize como meu site é apresentado. Por exemplo, selecione a partir de um conjunto fixo de tamanhos de fonte, permita cores de primeiro plano e plano de fundo definidas pelo usuário, etc.

Qual é a melhor maneira de aplicar o estilo CSS que o usuário seleciona / insere?

Mark Rajcok
fonte
artigo útil tech-blog.maddyzone.com/javascript/…
Resolvido em 17/09/14

Respostas:

485

Angular fornece várias diretivas internas para manipular o estilo CSS condicional / dinamicamente:

  • classe ng - use quando o conjunto de estilos CSS for estático / conhecido com antecedência
  • ng-style - use quando você não puder definir uma classe CSS, pois os valores do estilo podem mudar dinamicamente. Pense no controle programável dos valores do estilo.
  • ng-show e ng-hide - use se você só precisa mostrar ou ocultar algo (modifica CSS)
  • ng-if - novo na versão 1.1.5, use em vez do comutador ng mais detalhado se você precisar apenas verificar uma única condição (modifica o DOM)
  • ng-switch - use em vez de usar vários ng-shows mutuamente exclusivos (modifica o DOM)
  • ng-disabled e ng-readonly - use para restringir o comportamento do elemento do formulário
  • ng-animate - novo na versão 1.1.4, use para adicionar transições / animações CSS3

A "maneira angular" normal envolve vincular uma propriedade de modelo / escopo a um elemento da interface do usuário que aceite entrada / manipulação do usuário (por exemplo, use o modelo ng) e, em seguida, associe essa propriedade de modelo a uma das diretivas internas mencionadas acima.

Quando o usuário altera a interface do usuário, o Angular atualiza automaticamente os elementos associados na página.


Q1 parece um bom argumento para a classe ng - o estilo CSS pode ser capturado em uma classe.

A classe ng aceita uma "expressão" que deve ser avaliada para um dos seguintes:

  1. uma sequência de nomes de classe delimitados por espaço
  2. uma matriz de nomes de classe
  3. um mapa / objeto de nomes de classe para valores booleanos

Supondo que seus itens sejam exibidos usando ng-repeat em algum modelo de matriz e que, quando a caixa de seleção de um item estiver marcada, você deseja aplicar a pending-deleteclasse:

<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>

Acima, usamos a expressão de classe ng tipo 3 - um mapa / objeto de nomes de classe para valores booleanos.


O Q2 parece ser um bom argumento para o estilo ng - o estilo CSS é dinâmico, portanto não podemos definir uma classe para isso.

ng-style aceita uma "expressão" que deve ser avaliada para:

  1. um mapa / objeto de nomes de estilo CSS para valores CSS

Para um exemplo artificial, suponha que o usuário possa digitar um nome de cor em uma caixa de texto para a cor de fundo (um seletor de cores do jQuery seria muito melhor):

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


Violino para ambos os itens acima.

O violino também contém um exemplo de ng-show e ng-hide . Se uma caixa de seleção estiver marcada, além da cor de fundo ficar rosa, algum texto será mostrado. Se 'vermelho' for inserido na caixa de texto, uma div ficará oculta.

Mark Rajcok
fonte
Esta resposta é fantástica! Você gostaria de me mostrar via jsfiddle qual seria a diferença se o evento click estivesse mudando / adicionando uma classe em uma área que não era o elemento clicado? Diga uma div em outro lugar da página.
Tehaaron 10/10
é útil artigo tech-blog.maddyzone.com/javascript/...
Rituraj ratan
Grande resposta. Btw, você já tentou aplicar filtro angular ao estilo ng?
Evi Song
Sugiro adicionar uma opção adicional relacionada ao Q2 que acabei de adicionar na minha resposta recente a esta pergunta.
Gavin Palmer
105

Encontrei problemas ao aplicar classes dentro dos elementos da tabela quando já havia uma classe aplicada a toda a tabela (por exemplo, uma cor aplicada às linhas ímpares <myClass tbody tr:nth-child(even) td>). Parece que, quando você inspeciona o elemento com as Ferramentas do desenvolvedor , o element.styleestilo não é atribuído. Então, em vez de usar ng-class, tentei usar ng-stylee, nesse caso, o novo atributo CSS aparece dentro element.style. Este código funciona muito bem para mim:

<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 é o que estou avaliando e, em cada caso, aplico um estilo a cada um, <td>dependendo do valor myvar , que substitui o estilo atual aplicado pela classe CSS para toda a tabela.

ATUALIZAR

Se você deseja aplicar uma classe à tabela, por exemplo, ao visitar uma página ou em outros casos, você pode usar esta estrutura:

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

Basicamente, o que precisamos para ativar uma classe ng é a classe a ser aplicada e uma declaração verdadeira ou falsa. True aplica a classe e false não. Portanto, temos aqui dois cheques da rota da página e um OR entre eles, por isso, se estamos em /route_a OR estamos route_b, o ativo será aplicado classe.

Isso funciona apenas com uma função lógica à direita que retorna verdadeiro ou falso.

Portanto, no primeiro exemplo, o estilo ng é condicionado por três instruções. Se todos eles forem falsos, nenhum estilo será aplicado, mas, seguindo a nossa lógica, pelo menos um será aplicado; portanto, a expressão lógica verificará qual comparação de variáveis ​​é verdadeira e, como uma matriz não vazia é sempre verdadeira, deixou uma matriz como retorno e com apenas uma verdadeira, considerando que estamos usando OR para toda a resposta, o estilo restante será aplicado.

A propósito, esqueci de fornecer a função isActive ():

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

NOVA ATUALIZAÇÃO

Aqui você tem algo que acho realmente útil. Quando você precisa aplicar uma classe dependendo do valor de uma variável, por exemplo, um ícone dependendo do conteúdo da div, você pode usar o seguinte código (muito útil em ng-repeat):

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

Ícones do Font Awesome

Timbergus
fonte
o que é uma sintaxe estranha, && deve significar E, como em qualquer outro c inspirado linguagem
Pizzaiola Gorgonzola
3
@PizzaiolaGorgonzola && significa AND e || significa OR. É um truque inteligente usando a lógica de curto-circuito quase como uma declaração de caso / chave ...
Stein G. Strindhaug
Graças mit. Eu não percebi esse detalhe.
Timbergus
A nova seção de atualização funcionou como um encanto! +1 por isso!
Matias
usado o exemplo da classe ng, conforme mencionado em Nova atualização, funcionou muito bem para mim. Muito elegante
Acewin
34

Isso funciona bem quando a classe ng não pode ser usada (por exemplo, ao estilizar SVG):

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

(Eu acho que você precisa estar no mais recente Angular instável para usar ng-attr-, atualmente estou no 1.1.4)

Eu publiquei um artigo sobre como trabalhar com o AngularJS + SVG. Ele fala sobre esse assunto e vários outros. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS

Ashley Davis
fonte
Não vejo menção de ng-attr nos documentos 1.1.4 - você tem um link?
Mark-Rajcok
Desculpe, não tenho um link. Eu descobri isso seguindo os fóruns do Angular, embora não me lembre da página exata.
Ashley Davis
1
Os documentos mais recentes (v1.2) descrevem ng-attr-na página de diretivas , seção ngAttr atributo bindings .
Mark Rajcok
Com o 1.2, isso se torna uma ótima resposta. ng-classnão permite executar lógica, mas ng-attr-classsim. Ambos têm seus usos, mas posso apostar que muitos desenvolvedores estarão procurando ng-attr-class.
Hylianpuffball
Consegui que isso funcionasse bem quando outras soluções fornecidas aqui falharam. Obrigado.
dps 21/02
13
span class="circle circle-{{selectcss(document.Extension)}}">

e 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
fonte
Sempre evite a palavra iF
LastTribunal 27/15/15
Quero incentivar a evitar diretamente o uso do atributo de classe. Isso substituirá as alterações feitas por outros plugins neste elemento.
precisa saber é o seguinte
10

Esta solução fez o truque para mim

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

Você pode usar expressão ternária. Existem duas maneiras de fazer isso:

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

ou...

<div ng-style="{'color': (myVariable > 100) ? 'red' : 'blue' }"></div>
michal-michalak
fonte
1
Talvez você o encontre melhor: <div ng-style = "{'color': (myVariable> 100)? 'Red': 'blue'}"> </div> #
31418 Dudi
Dudi, se não melhor, tão útil quanto, então eu a adicionei à resposta de "expressão ternária" de @ maykel. Graças a vocês dois!
Jbobbins 19/05/19
7

Outra opção quando você precisa de um estilo css simples de uma ou duas propriedades:

Visão:

<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
fonte
6

Veja o exemplo a seguir

<!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
fonte
2

A partir do AngularJS v1.2.0rc, ng-classe até ng-attr-classfalham com elementos SVG (eles funcionavam anteriormente, mesmo com ligação normal dentro do atributo de classe)

Especificamente, nada disso funciona agora:

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

Como solução alternativa, eu tenho que usar

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

e depois estilize usando

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

Uma maneira mais (no futuro) de aplicar condicionalmente o estilo é criar condicionalmente o estilo com escopo

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

</style>

Atualmente, porém, apenas o FireFox suporta estilos de escopo.

Pavel Voronin
fonte
1

Há mais uma opção que descobri recentemente que algumas pessoas podem achar úteis porque permite alterar uma regra CSS dentro de um elemento de estilo - evitando assim a necessidade de uso repetido de uma diretiva angular como ng-style, ng-class, ng-show, ng-hide, ng-animate e outros.

Esta opção faz uso de um serviço com variáveis ​​de serviço que são definidas por um controlador e assistidas por uma diretiva de atributo que eu chamo de "estilo personalizado". Essa estratégia poderia ser usada de várias maneiras diferentes, e tentei fornecer algumas orientações gerais para esse violino .

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
fonte
1

Bem, eu sugiro que você verifique a condição no seu controlador com uma função retornando true ou false .

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

e no seu controlador verifique a condição

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

Uma coisa a observar é - se o estilo CSS tiver traços - você deve removê-los. Então, se você deseja definirbackground-color , a maneira correta é:

ng-style="{backgroundColor:myColor}" 
Neil Munro
fonte
5
Não, você não precisa. ng-style = "{'background-color': myColor}" funciona perfeitamente bem.
Gerasalus 7/07
0

Veja como eu apliquei condicionalmente o estilo de texto cinza em um botão desativado

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

Aqui está um exemplo de trabalho:
https://stackblitz.com/edit/example-conditional-disable-button?file=src%2Fapp%2Fapp.component.html

BraveNewMath
fonte