Come posso applicare in modo condizionale gli stili CSS in AngularJS?


309

Q1. Supponiamo di voler modificare l'aspetto di ogni "elemento" che un utente contrassegna per l'eliminazione prima che venga premuto il pulsante principale "elimina". (Questo immediato riscontro visivo dovrebbe eliminare la necessità della proverbiale finestra di dialogo "Sei sicuro?"). L'utente controllerà le caselle di controllo per indicare quali elementi devono essere eliminati. Se una casella è deselezionata, quell'elemento dovrebbe tornare al suo aspetto normale.

Qual è il modo migliore per applicare o rimuovere lo stile CSS?

Q2. Supponiamo di voler consentire a ciascun utente di personalizzare la modalità di presentazione del mio sito. Ad esempio, selezionare da un set fisso di dimensioni dei caratteri, consentire colori di primo piano e di sfondo definibili dall'utente, ecc.

Qual è il modo migliore per applicare lo stile CSS che l'utente seleziona / immette?


Risposte:


485

Angular fornisce una serie di direttive integrate per manipolare lo stile CSS in modo condizionale / dinamico:

  • ng-class - usare quando l'insieme di stili CSS è statico / conosciuto in anticipo
  • ng-style : utilizzare quando non è possibile definire una classe CSS perché i valori di stile possono cambiare in modo dinamico. Pensa al controllo programmabile dei valori di stile.
  • ng-show e ng-hide - usa se hai solo bisogno di mostrare o nascondere qualcosa (modifica CSS)
  • ng-if - nuovo nella versione 1.1.5, utilizzare al posto del ng-switch più dettagliato se è necessario solo verificare una singola condizione (modifica DOM)
  • ng-switch - usa invece di usare diversi ng-show reciprocamente esclusivi (modifica DOM)
  • ng-disabled e ng-readonly : utilizzare per limitare il comportamento degli elementi del modulo
  • ng-animate - nuovo nella versione 1.1.4, usare per aggiungere transizioni / animazioni CSS3

Il normale "modo angolare" implica il collegamento di una proprietà modello / ambito a un elemento dell'interfaccia utente che accetti l'input / manipolazione dell'utente (ovvero, utilizza ng-modello) e quindi l'associazione di tale proprietà del modello a una delle direttive integrate sopra menzionate.

Quando l'utente cambia l'interfaccia utente, Angular aggiornerà automaticamente gli elementi associati nella pagina.


Q1 sembra un buon caso per la classe ng - lo stile CSS può essere catturato in una classe.

ng-class accetta una "espressione" che deve valutare una delle seguenti:

  1. una stringa di nomi di classe delimitati da spazi
  2. una matrice di nomi di classe
  3. una mappa / oggetto di nomi di classe per valori booleani

Supponendo che i tuoi articoli vengano visualizzati usando ng-repeat su alcuni modelli di array e che quando la casella di controllo per un articolo è selezionata vuoi applicare la 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>

Sopra, abbiamo usato l'espressione ng-class type # 3 - una mappa / oggetto di nomi di classe per valori booleani.


Q2 sembra un buon caso per ng-style: lo stile CSS è dinamico, quindi non possiamo definire una classe per questo.

ng-style accetta una "espressione" che deve valutare a:

  1. una mappa / oggetto di nomi di stile CSS su valori CSS

Per un esempio inventato, supponiamo che l'utente possa digitare un nome di colore in una casella di testo per il colore di sfondo (un selettore di colori jQuery sarebbe molto più bello):

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


Violino per entrambi i precedenti.

Il violino contiene anche un esempio di ng-show e ng-hide . Se una casella è selezionata, oltre al colore di sfondo che diventa rosa, viene mostrato del testo. Se 'red' è inserito nella casella di testo, un div diventa nascosto.


Questa risposta è fantastica! Saresti disposto a mostrarmi tramite jsfiddle quale sarebbe la differenza se l'evento click stesse cambiando / aggiungendo una classe su un'area che non era l'elemento cliccato? Dì un div altrove sulla pagina.
Tehaaron,


Grande risposta. A proposito, hai mai provato ad applicare il filtro angolare in stile ng?
Evi Song,

Suggerisco di aggiungere un'opzione aggiuntiva relativa al Q2 che ho appena aggiunto nella mia recente risposta a questa domanda.
Gavin Palmer,

105

Ho riscontrato problemi durante l'applicazione delle classi all'interno degli elementi della tabella quando avevo già una classe applicata all'intera tabella (ad esempio, un colore applicato alle righe dispari <myClass tbody tr:nth-child(even) td>). Sembra che quando si ispeziona l'elemento con Strumenti per gli sviluppatori , element.stylenon è stato assegnato alcuno stile. Quindi, invece di usare ng-class, ho provato a usare ng-style, e in questo caso, il nuovo attributo CSS appare all'interno element.style. Questo codice funziona alla grande per me:

<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 è ciò che sto valutando, e in ogni caso applico uno stile a ciascuno a <td>seconda del valore myvar , che sovrascrive lo stile corrente applicato dalla classe CSS per l'intera tabella.

AGGIORNARE

Se si desidera applicare una classe alla tabella, ad esempio, quando si visita una pagina o in altri casi, è possibile utilizzare questa struttura:

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

Fondamentalmente, ciò di cui abbiamo bisogno per attivare una classe ng è la classe da applicare e un'istruzione vera o falsa. True applica la classe e false no. Quindi qui abbiamo due controlli del percorso della pagina e un OR tra di loro, quindi se siamo in /route_a OR siamo in route_b, la classe attiva verrà applicata.

Funziona semplicemente con una funzione logica sulla destra che restituisce vero o falso.

Quindi nel primo esempio, ng-style è condizionato da tre affermazioni. Se tutti sono falsi, nessuno stile viene applicato, ma seguendo la nostra logica, almeno uno verrà applicato, quindi, l'espressione logica controllerà quale confronto di variabili è vero e poiché un array non vuoto è sempre vero, quello sarà ha lasciato un array come return e con un solo true, considerando che stiamo usando OR per l'intera risposta, verrà applicato lo stile rimanente.

A proposito, ho dimenticato di darti la funzione isActive ():

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

NUOVO AGGIORNAMENTO

Qui hai qualcosa che trovo davvero utile. Quando è necessario applicare una classe in base al valore di una variabile, ad esempio un'icona in base al contenuto di div, è possibile utilizzare il seguente codice (molto utile in ng-repeat):

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

Icone da Font Awesome


che strana sintassi, && dovrebbe significare E, come in qualsiasi altra lingua ispirata al c
Pizzaiola Gorgonzola,

3
@PizzaiolaGorgonzola && significa AND e || significa OR. È un trucco intelligente che usa la logica del corto circuito quasi come un'istruzione case / switch ...
Stein G. Strindhaug

Grazie mit. Non mi ero reso conto di quel dettaglio.
Timbergus,

La nuova sezione di aggiornamento ha funzionato come un fascino! +1 per questo!
Matias,

ho usato l'esempio di ng-class come menzionato in New Update, ha funzionato abbastanza bene per me. Abbastanza elegante
Acewin

34

Funziona bene quando non è possibile utilizzare la classe ng (ad esempio durante lo styling di SVG):

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

(Penso che devi essere sull'ultimo Angolare instabile per usare ng-attr-, al momento sono su 1.1.4)

Ho pubblicato un articolo su come lavorare con AngularJS + SVG. Parla di questo problema e di numerosi altri. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS


Non vedo alcuna menzione di ng-attr nei documenti 1.1.4 - hai un link?
Mark Rajcok,

Siamo spiacenti, non ho un link. L'ho scoperto seguendo i forum angolari, anche se non ricordo la scusa della pagina esatta.
Ashley Davis,

1
Gli ultimi documenti (v1.2) descrivono ng-attr-nella pagina delle direttive , sezione bind degli attributi ngAttr .
Mark Rajcok,

Con 1.2, questa diventa un'ottima risposta. ng-classnon ti consente di eseguire la logica, ma lo ng-attr-classfa. Entrambi hanno i loro usi, ma posso scommettere che molti sviluppatori cercheranno ng-attr-class.
Hylianpuffball,

Ho capito che funziona bene quando altre soluzioni fornite qui falliscono. Grazie.
dps,

13
span class="circle circle-{{selectcss(document.Extension)}}">

e codice

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

Evita sempre la parola iF
LastTribunal,

Voglio incoraggiare ad evitare di usare direttamente l'attributo class. Questo sovrascriverà le modifiche apportate da altri plugin su questo elemento.
SimonSimCity,

10

Questa soluzione ha fatto il trucco per me

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

8

Puoi usare l'espressione ternaria. Esistono due modi per farlo:

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

o...

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

1
Forse lo troverai meglio: <div ng-style = "{'color': (myVariable> 100)? 'Red': 'blue'}"> </div>
Dudi

Dudi, se non meglio, altrettanto utile, quindi l'ho aggiunto alla risposta "espressione ternaria" di @ maykel. Grazie a tutti e due!
jbobbins

7

Un'altra opzione quando è necessario un semplice stile CSS di una o due proprietà:

Visualizza:

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

controller:

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

6

Vedi il seguente esempio

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

2

A partire da AngularJS v1.2.0rc, ng-classe addirittura ng-attr-classfalliscono con gli elementi SVG (hanno funzionato prima, anche con un normale legame all'interno dell'attributo class)

In particolare, nessuno di questi funziona ora:

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

Come soluzione alternativa, devo usare

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

e poi lo stile usando

[otherAttr='active'] {
   ... styles ...
}

1

Un altro modo (in futuro) per applicare condizionalmente lo stile consiste nel creare condizionalmente uno stile con ambito

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

</style>

Ma al giorno d'oggi solo FireFox supporta stili con ambito.


1

C'è un'altra opzione che ho scoperto di recente che alcune persone potrebbero trovare utile perché ti consente di modificare una regola CSS all'interno di un elemento di stile, evitando così la necessità di un uso ripetuto di una direttiva angolare come ng-style, ng-class, ng-show, ng-hide, ng-animate e altri.

Questa opzione fa uso di un servizio con variabili di servizio che sono impostate da un controller e controllate da una direttiva di attributo che chiamo "stile personalizzato". Questa strategia potrebbe essere utilizzata in molti modi diversi e ho tentato di fornire una guida generale con questo 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);
        }
    };
});

1

bene ti suggerirei di controllare le condizioni nel tuo controller con una funzione che ritorna vera o falsa .

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

e nel controller controlla le condizioni

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

0

Una cosa da guardare è - se lo stile CSS ha trattini - è necessario rimuoverli. Quindi, se si desidera impostare background-color, il modo corretto è:

ng-style="{backgroundColor:myColor}" 

5
No, non è necessario. ng-style = "{'background-color': myColor}" funziona perfettamente.
gerasalus,

0

Ecco come ho applicato condizionalmente lo stile di testo grigio su un pulsante disabilitato

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

Ecco un esempio funzionante:
https://stackblitz.com/edit/example-conditional-disable-button?file=src%2Fapp%2Fapp.component.html

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.