web-dev-qa-db-fra.com

Comment appliquer de manière conditionnelle les styles CSS dans AngularJS?

Q1. Supposons que je veuille modifier l'apparence de chaque "élément" qu'un utilisateur sélectionne pour suppression avant d'appuyer sur le bouton principal "Supprimer". (Ce retour visuel immédiat devrait éliminer le besoin 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 à cocher 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, choisissez parmi un ensemble fixe de tailles de police, autorisez les couleurs de premier plan et d'arrière-plan, etc.

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

301
Mark Rajcok

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

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

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

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


Q1 semble être un bon exemple pour ng-class - le style CSS peut être capturé dans une classe.

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

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

En supposant que vos éléments sont affichés à l'aide de ng-repeat sur un modèle de tableau, et que, lorsque la case à cocher correspondant à un élément est cochée, vous souhaitez appliquer la classe pending-delete:

<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/objet de noms de classes en valeurs booléennes.


Q2 semble être un bon exemple pour ng-style - le style CSS est dynamique, nous ne pouvons donc pas définir de classe pour cela.

ng-style accepte une "expression" qui doit avoir pour résultat:

  1. une carte/objet de noms de style CSS en 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">


Fiddle pour les deux précédents.

Le violon contient également un exemple de ng-show et ng-hide. Si une case à cocher est cochée, du texte s'affiche, en plus de la couleur d'arrière-plan virant au rose. Si 'rouge' est entré dans la zone de texte, un div devient caché.

476
Mark Rajcok

J'ai rencontré des problèmes lors de l'application de classes à l'intérieur d'éléments table alors qu'une classe était déjà appliquée à l'ensemble du tableau (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 Developer Tools, aucun style n'est attribué au element.style. Ainsi, au lieu d’utiliser ng-class, j’ai essayé d’utiliser ng-style et, dans ce cas, le nouvel attribut CSS apparaît dans 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>

J'évalue Myvar et, dans chaque cas, j'applique un style à chaque <td> en fonction de la valeur myvar, qui écrase le style actuel appliqué par la classe CSS pour l'ensemble du tableau.

METTRE &AGRAVE; JOUR

Si vous souhaitez appliquer une classe à la table, par exemple, lors de la visite d'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 est la classe à appliquer et une déclaration vraie ou fausse. True applique la classe et false ne l'applique pas. Nous avons donc ici deux contrôles de la route de la page et un OU entre eux, donc si nous sommes dans /route_aOU nous sommes dans route_b, la classe active sera sois appliqué.

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

Ainsi, dans le premier exemple, ng-style est conditionné par trois instructions. Si tous sont faux, aucun style n'est appliqué, mais suivant notre logique, au moins un va être appliqué, ainsi, l'expression logique va vérifier quelle comparaison de variable est vraie et comme un tableau non vide est toujours vrai, laissé un tableau comme 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

Ici, vous avez 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

105
Timbergus

Cela fonctionne bien lorsque ng-class ne peut pas être utilisé (par exemple lors du stylage de SVG):

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

(Je pense que vous devez être sur la dernière angulaire instable pour utiliser ng-attr-, je suis actuellement sur la 1.1.4)

J'ai publié un article sur le travail avec AngularJS + SVG. Il parle de ce problème et de nombreux autres. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS

34
Ashley Davis
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);
}
12
Nenad Jesic

Cette solution a fait le tour pour moi

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

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';
    }
};
7
Dudi

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

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>
6
Ranga Reddy

À partir de AngularJS v1.2.0rc, ng-class et même ng-attr-class échouent avec les éléments SVG (ils fonctionnaient auparavant, même avec une liaison normale dans l'attribut de classe)

Plus précisément, aucun de ceux-ci ne fonctionne maintenant:

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

Pour contourner le problème, je dois utiliser 

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

puis coiffez avec

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

eh bien, je vous suggère de vérifier la condition 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érifier l'état 

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

Une autre manière (à l’avenir) d’appliquer du style de manière conditionnelle consiste à créer conditionnellement un style

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

</style>

Mais à présent, seul FireFox prend en charge les styles étendus.

1
Pavel Voronin

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 l'utilisation répétée d'une directive angulaire comme ng-style, ng-class ng-show, ng-hide, ng-animate et autres.

Cette option utilise un service avec des variables de service 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 nombreuses manières différentes, et j’ai essayé de fournir quelques indications générales 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
Gavin Palmer

Une chose à regarder est - si le style CSS a des tirets - vous devez les supprimer. Donc, si vous voulez définir background-color, la manière correcte est:

ng-style="{backgroundColor:myColor}" 
0
Neil Munro

Voici comment j'ai appliqué conditionnellement le style de texte gris 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

0
BraveNewMath