Comment appliquer conditionnellement des styles CSS dans AngularJS?


309

Q1. Supposons que je veuille modifier l'apparence de chaque "élément" qu'un utilisateur marque pour suppression avant d'appuyer sur le bouton principal "supprimer". (Cette rétroaction visuelle immédiate devrait éliminer la nécessité de la boîte de dialogue proverbiale «Êtes-vous sûr?».) L'utilisateur cochera les cases pour indiquer les éléments à supprimer. Si une case n'est pas cochée, cet élément devrait revenir à son aspect normal.

Quelle est la meilleure façon d'appliquer ou de supprimer le style CSS?

Q2. Supposons que je veuille permettre à chaque utilisateur de personnaliser la présentation de mon site. Par exemple, sélectionnez parmi un ensemble fixe de tailles de police, autorisez des couleurs de premier plan et d'arrière-plan définissables par l'utilisateur, etc.

Quelle est la meilleure façon d'appliquer le style CSS que l'utilisateur sélectionne / saisit?


Réponses:


485

Angular fournit un certain nombre de directives intégrées pour manipuler le style CSS de manière conditionnelle / dynamique:

  • ng-class - à utiliser lorsque l'ensemble des styles CSS est statique / connu à l'avance
  • ng-style - à utiliser lorsque vous ne pouvez pas définir une classe CSS car les valeurs de style peuvent changer dynamiquement. Pensez au contrôle programmable des valeurs de style.
  • ng-show et ng-hide - à utiliser si vous avez seulement besoin d'afficher ou de masquer quelque chose (modifie CSS)
  • ng-if - nouveau dans la version 1.1.5, utilisez à la place du ng-switch plus verbeux si vous avez seulement besoin de vérifier une seule condition (modifie DOM)
  • ng-switch - utilise au lieu d'utiliser plusieurs ng-shows mutuellement exclusifs (modifie DOM)
  • ng-disabled et ng-readonly - à utiliser pour restreindre le comportement des éléments de formulaire
  • ng-animate - nouveau dans la version 1.1.4, permet d'ajouter des transitions / animations CSS3

La "voie angulaire" normale implique de lier une propriété modèle / portée à un élément d'interface utilisateur qui acceptera les entrées / manipulations de l'utilisateur (c'est-à-dire, utiliser ng-modèle), puis d'associer cette propriété de modèle à l'une des directives intégrées mentionnées ci-dessus.

Lorsque l'utilisateur modifie l'interface utilisateur, Angular mettra automatiquement à jour les éléments associés sur la page.


Q1 ressemble à un bon cas pour ng-class - le style CSS peut être capturé dans une classe.

ng-class accepte une "expression" qui doit correspondre à l'une des valeurs suivantes:

  1. une chaîne de noms de classe délimités par des espaces
  2. un tableau de noms de classe
  3. un mappage / objet de noms de classe aux valeurs booléennes

En supposant que vos éléments sont affichés en utilisant ng-repeat sur un modèle de tableau, et que lorsque la case à cocher d'un élément est cochée, vous souhaitez appliquer 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>

Ci-dessus, nous avons utilisé le type d'expression ng-class # 3 - une carte / un objet de noms de classe aux valeurs booléennes.


Q2 ressemble à un bon cas pour le style ng - le style CSS est dynamique, nous ne pouvons donc pas définir de classe pour cela.

ng-style accepte une "expression" qui doit être évaluée comme:

  1. une carte / un objet des noms de style CSS aux valeurs CSS

Pour un exemple artificiel, supposons que l'utilisateur puisse taper un nom de couleur dans une texbox pour la couleur d'arrière-plan (un sélecteur de couleur jQuery serait beaucoup plus agréable):

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


Violon pour les deux ci-dessus.

Le violon contient également un exemple de ng-show et ng-hide . Si une case est cochée, en plus de la couleur d'arrière-plan qui devient rose, du texte est affiché. Si «rouge» est entré dans la zone de texte, un div devient masqué.


Cette réponse est formidable! Seriez-vous prêt à me montrer via jsfiddle quelle serait la différence si l'événement click changeait / ajoutait une classe sur une zone qui n'était pas l'élément cliqué? Dites un div ailleurs sur la page.
tehaaron


Grande réponse. Btw, avez-vous déjà essayé d'appliquer un filtre angulaire au style ng?
Evi Song

Je suggère d'ajouter une option supplémentaire liée au T2 que je viens d'ajouter dans ma réponse récente à cette question.
Gavin Palmer du

105

J'ai rencontré des problèmes lors de l'application de classes à l'intérieur des éléments de table lorsque j'avais déjà appliqué une classe à l'ensemble de la table (par exemple, une couleur appliquée aux lignes impaires <myClass tbody tr:nth-child(even) td>). Il semble que lorsque vous inspectez l'élément avec les outils de développement , element.styleaucun style ne soit attribué. Donc, au lieu d'utiliser ng-class, j'ai essayé d'utiliser ng-style, et dans ce cas, le nouvel attribut CSS apparaît à l'intérieur element.style. Ce code fonctionne très bien pour moi:

<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 est ce que j'évalue , et dans chaque cas, j'applique un style à chacun en <td>fonction de la valeur de myvar , qui écrase le style actuel appliqué par la classe CSS pour la table entière.

METTRE À JOUR

Si vous souhaitez appliquer une classe à la table par exemple, lorsque vous visitez une page ou dans d'autres cas, vous pouvez utiliser cette structure:

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

Fondamentalement, ce dont nous avons besoin pour activer une classe ng, c'est la classe à appliquer et une déclaration vraie ou fausse. True applique la classe et false non. Nous avons donc ici deux vérifications de l'itinéraire de la page et un OU entre eux, donc si nous sommes dans /route_a OU nous sommes dans route_b, la classe active sera appliquée.

Cela fonctionne simplement avec une fonction logique à droite qui renvoie vrai ou faux.

Ainsi, dans le premier exemple, le style ng est conditionné par trois instructions. Si tous sont faux, aucun style n'est appliqué, mais selon notre logique, au moins un va être appliqué, donc, l'expression logique vérifiera quelle comparaison de variable est vraie et parce qu'un tableau non vide est toujours vrai, cela laissé un tableau en retour et avec un seul vrai, étant donné que nous utilisons OU pour toute la réponse, le style restant sera appliqué.

Au fait, j'ai oublié de vous donner la fonction isActive ():

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

NOUVELLE MISE À JOUR

Voici quelque chose que je trouve vraiment utile. Lorsque vous devez appliquer une classe en fonction de la valeur d'une variable, par exemple, une icône en fonction du contenu de la div, vous pouvez utiliser le code suivant (très utile dans ng-repeat):

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

Icônes de Font Awesome


quelle étrange syntaxe, && devrait signifier ET, comme dans tout autre langage inspiré de c
Pizzaiola Gorgonzola

3
@PizzaiolaGorgonzola && signifie ET et || signifie OU. C'est un hack intelligent utilisant la logique de court-circuit presque comme une déclaration de cas / commutateur ...
Stein G. Strindhaug

Merci mit. Je ne me suis pas rendu compte de ce détail.
Timbergus

La nouvelle section de mise à jour a fonctionné comme un charme! +1 pour cela!
Matias

utilisé l'exemple de la classe ng comme mentionné dans la nouvelle mise à jour, a très bien fonctionné pour moi. Assez élégant
Acewin

34

Cela fonctionne bien lorsque la classe ng ne peut pas être utilisée (par exemple lors du style SVG):

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

(Je pense que vous devez être sur le dernier Angular instable pour utiliser ng-attr-, je suis actuellement sur 1.1.4)

J'ai publié un article sur le travail avec AngularJS + SVG. Il parle de cette question et de bien d'autres. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS


Je ne vois aucune mention de ng-attr dans la documentation 1.1.4 - avez-vous un lien?
Mark Rajcok

Désolé, je n'ai pas de lien. Je l'ai découvert en suivant les forums Angular, bien que je ne me souvienne pas de la page exacte désolée.
Ashley Davis

1
Les derniers documents (v1.2) décrivent ng-attr-sur la page des directives , section Liaisons d'attributs ngAttr .
Mark Rajcok

Avec 1.2, cela devient une excellente réponse. ng-classne vous laisse pas exécuter la logique, mais le ng-attr-classfait. Ils ont tous deux leur utilité, mais je peux parier que beaucoup de développeurs seront à la recherche ng-attr-class.
Hylianpuffball

J'ai réussi à bien fonctionner lorsque d'autres solutions fournies ici ont échoué. Je vous remercie.
dps

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

et code

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

Évitez toujours le mot iF
LastT Tribunal

Je veux encourager à éviter d'utiliser directement l'attribut class. Cela écrasera les modifications apportées par d'autres plugins sur cet élément.
SimonSimCity

10

Cette solution a fait l'affaire pour moi

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

8

Vous pouvez utiliser l'expression ternaire. Il y a deux façons de faire ça:

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

ou...

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

1
Peut-être que vous le trouverez mieux: <div ng-style = "{'color': (myVariable> 100)? 'Red': 'blue'}"> </div>
Dudi

Dudi, sinon mieux, tout aussi utile, alors je l'ai ajouté à la réponse "expression ternaire" de @ maykel. Merci à vous deux!
jbobbins

7

Une autre option lorsque vous avez besoin d'un style CSS simple d'une ou deux propriétés:

Vue:

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

Manette:

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

6

Voir l'exemple suivant

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

Depuis AngularJS v1.2.0rc, ng-classet ng-attr-classéchouent même avec les éléments SVG (Ils ont fonctionné plus tôt, même avec une liaison normale à l'intérieur de l'attribut de classe)

Plus précisément, aucun de ces travaux maintenant:

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

Pour contourner ce problème, je dois utiliser

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

puis le style en utilisant

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

1

Une autre façon (à l'avenir) d'appliquer le style de manière conditionnelle consiste à créer un style de portée conditionnelle

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

</style>

Mais de nos jours, seul FireFox prend en charge les styles étendus.


1

Il y a une autre option que j'ai récemment découverte que certaines personnes peuvent trouver utile car elle vous permet de modifier une règle CSS dans un élément de style - évitant ainsi la nécessité d'une utilisation répétée d'une directive angulaire telle que ng-style, ng-class, ng-show, ng-hide, ng-animate et autres.

Cette option utilise un service avec des variables de service qui sont définies par un contrôleur et surveillées par une directive d'attribut que j'appelle "style personnalisé". Cette stratégie pourrait être utilisée de différentes manières, et j'ai essayé de fournir des conseils généraux avec ce violon .

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

eh bien je vous suggère de vérifier l'état de votre contrôleur avec une fonction retournant vrai ou faux .

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

et dans votre contrôleur vérifiez l'état

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

0

Une chose à surveiller est - si le style CSS a des tirets - vous devez les supprimer. Donc, si vous souhaitez définir background-color, la bonne façon est:

ng-style="{backgroundColor:myColor}" 

5
Non, tu n'es pas obligé. ng-style = "{'background-color': myColor}" fonctionne parfaitement bien.
gerasalus

0

Voici comment j'ai appliqué le style de texte gris de façon conditionnelle sur un bouton désactivé

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

Voici un exemple de travail:
https://stackblitz.com/edit/example-conditional-disable-button?file=src%2Fapp%2Fapp.component.html

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.