Как я могу условно применять стили CSS в AngularJS?


309

Q1. Предположим, я хочу изменить внешний вид каждого «элемента», который пользователь помечает для удаления до нажатия основной кнопки «Удалить». (Эта немедленная визуальная обратная связь должна устранить необходимость в общеизвестном диалоговом окне «Вы уверены?».) Пользователь установит флажки, чтобы указать, какие элементы следует удалить. Если флажок снят, этот элемент должен вернуться к своему обычному виду.

Каков наилучший способ применить или удалить стиль CSS?

Q2. Предположим, я хочу позволить каждому пользователю персонализировать представление моего сайта. Например, выберите из фиксированного набора размеров шрифта, разрешите определяемые пользователем цвета переднего плана и фона и т. Д.

Какой лучший способ применить стиль CSS, который пользователь выбирает / вводит?


Ответы:


485

Angular предоставляет ряд встроенных директив для условного / динамического управления стилями CSS:

  • ng-class - использовать, когда набор стилей CSS статичен / известен заранее
  • ng-style - используйте, когда вы не можете определить класс CSS, потому что значения стиля могут изменяться динамически. Подумайте, программируемое управление значениями стиля.
  • нг-шоу и нг-скрыть - используйте, если вам нужно только что-то показать или скрыть (модифицирует CSS)
  • ng-if - новое в версии 1.1.5, используйте вместо более подробного ng-switch, если вам нужно проверить только одно условие (изменяет DOM)
  • ng-switch - используйте вместо нескольких взаимоисключающих ng-шоу (модифицирует DOM)
  • ng-disabled и ng-readonly - используется для ограничения поведения элементов формы
  • ng-animate - новое в версии 1.1.4, используется для добавления переходов / анимации CSS3

Обычный «угловой путь» включает в себя привязку свойства модели / области к элементу пользовательского интерфейса, который будет принимать пользовательский ввод / манипулирование (т. Е. Использование ng-модели), а затем связывание этого свойства модели с одной из упомянутых выше встроенных директив.

Когда пользователь изменяет пользовательский интерфейс, Angular автоматически обновляет связанные элементы на странице.


Q1 звучит как хороший пример для ng-класса - стиль CSS может быть записан в классе.

ng-class принимает "выражение", которое должно соответствовать одному из следующих:

  1. строка имен классов, разделенных пробелами
  2. массив имен классов
  3. карта / объект с именами классов для логических значений

Предполагая, что ваши элементы отображаются с использованием ng-repeat на некоторой модели массива, и что когда флажок для элемента установлен, вы хотите применить 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>

Выше мы использовали тип выражения ng-класса # 3 - карту / объект с именами классов для логических значений.


Q2 звучит как хороший пример для стиля ng - стиль CSS динамический, поэтому мы не можем определить класс для этого.

ng-style принимает "выражение", которое должно вычисляться так:

  1. карта / объект имен стилей CSS для значений CSS

Для надуманного примера, предположим, что пользователь может ввести имя цвета в текстовое поле для цвета фона (выбор цвета jQuery был бы намного лучше):

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


Скрипка для обоих вышеперечисленных.

Скрипка также содержит пример ng-show и ng-hide . Если флажок установлен, в дополнение к цвету фона, который становится розовым, отображается некоторый текст. Если в текстовое поле введен «красный», div становится скрытым.


Этот ответ потрясающий! Хотели бы вы показать мне через jsfiddle, в чем разница, если событие click изменялось / добавляло класс в область, которая не была элементом clicked? Скажите div в другом месте на странице.
tehaaron


Отличный ответ. Кстати, вы когда-нибудь пытались применить угловой фильтр в стиле нг?
Эви Сонг

Я предлагаю добавить дополнительную опцию, связанную с Q2, которую я только что добавил в своем недавнем ответе на этот вопрос.
Гэвин Палмер

105

Я обнаружил проблемы при применении классов внутри элементов таблицы, когда один класс уже был применен ко всей таблице (например, цвет, примененный к нечетным строкам <myClass tbody tr:nth-child(even) td>). Кажется , что , когда вы проверяете элемент с Инструментами разработчика , то element.styleне имеет никакого стиля назначенный. Поэтому вместо использования ng-classя попытался использовать ng-style, и в этом случае новый атрибут CSS появляется внутри element.style. Этот код прекрасно работает для меня:

<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 - это то, что я оцениваю, и в каждом случае я применяю стиль к каждому в <td>зависимости от myvar значения , который переписывает текущий стиль, применяемый классом CSS для всей таблицы.

ОБНОВИТЬ

Если вы хотите применить класс к таблице, например, при посещении страницы или в других случаях, вы можете использовать эту структуру:

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

По сути, нам нужно активировать ng-класс - это класс для применения и операторы true или false. True применяет класс, а false - нет. Итак, здесь у нас есть две проверки маршрута страницы и ИЛИ между ними, поэтому, если мы находимся в /route_a ИЛИ, мы находимся route_b, активный класс будет применен.

Это работает просто имея логическую функцию справа, которая возвращает истину или ложь.

Итак, в первом примере стиль ng обусловлен тремя утверждениями. Если все они ложны, стиль не применяется, но, следуя нашей логике, будет применен, по крайней мере, один, поэтому логическое выражение проверит, какое сравнение переменных является истинным, и поскольку непустой массив всегда истинен, это будет оставил массив в качестве возврата и только с одним значением true, учитывая, что мы используем OR для всего ответа, оставшийся стиль будет применен.

Кстати, я забыл дать вам функцию isActive ():

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

НОВОЕ ОБНОВЛЕНИЕ

Вот вам кое-что, что я считаю действительно полезным. Когда вам нужно применить класс в зависимости от значения переменной, например, значок в зависимости от содержимого div, вы можете использовать следующий код (очень полезно в ng-repeat):

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

Иконки от Font Awesome


какой странный синтаксис, && должен означать И, как и в любом другом языке, вдохновленном c
Pizzaiola Gorgonzola

3
@PizzaiolaGorgonzola && означает И и || значит ИЛИ. Это умный взлом, использующий логику короткого замыкания почти как оператор case / switch ...
Stein G. Strindhaug

Спасибо, Мит. Я не понял этой детали.
Тимбергус

Новый раздел обновлений работал как шарм! +1 за это!
Матиас

Использовал пример класса ng, упомянутый в «Новом обновлении», у меня все получилось. Довольно гладкий
Acewin

34

Это хорошо работает, когда нельзя использовать ng-класс (например, при стилизации SVG):

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

(Я думаю, что вы должны быть на последнем нестабильном Angular, чтобы использовать ng-attr-, я сейчас на 1.1.4)

Я опубликовал статью о работе с AngularJS + SVG. Он говорит об этой проблеме и многих других. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS


Я не вижу упоминаний о ng-attr в документах 1.1.4. У вас есть ссылка?
Марк Райкок

Извините, нет ссылки. Я узнал об этом, следя за форумами Angular, хотя не могу вспомнить точную страницу извините.
Эшли Дэвис

1
Самые последние документы (v1.2) описывают ng-attr-на странице директив раздел привязок атрибутов ngAttr .
Марк Райкок

С 1.2 это становится отличным ответом. ng-classне позволяет вам выполнять логику, но ng-attr-classделает. Они оба имеют свое применение, но я могу поспорить, что многие разработчики будут искать ng-attr-class.
Hylianpuffball

Я получил это работать хорошо, когда другие решения, представленные здесь не удалось. Спасибо.
дпс

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

и код

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

Всегда избегайте слова iF
LastTribunal

Я хочу призвать избегать прямого использования атрибута класса. Это перезапишет изменения, сделанные другими плагинами на этом элементе.
SimonSimCity

10

Это решение помогло мне

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

8

Вы можете использовать троичное выражение. Есть два способа сделать это:

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

или...

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

1
Может быть, вы найдете это лучше: <div ng-style = "{'color': (myVariable> 100)? 'Red': 'blue'}"> </ div>
Dudi

Дуди, если не лучше, не менее полезен, поэтому я добавил его в ответ @ maykel на «троичное выражение». Спасибо вам обоим!
Джобобинс

7

Другой вариант, когда вам нужен простой стиль CSS одного или двух свойств:

Посмотреть:

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

контроллер:

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

6

Смотрите следующий пример

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

Начиная с AngularJS v1.2.0rc ng-classи дажеng-attr-class не работает с элементами SVG (раньше они работали, даже с нормальной привязкой внутри атрибута класса)

В частности, ни один из них не работает сейчас:

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

В качестве обходного пути, я должен использовать

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

а затем стиль с помощью

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

1

Еще один (в будущем) способ условного применения стиля - создание условного стиля

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

</style>

Но в настоящее время только FireFox поддерживает стили с заданной областью.


1

Недавно я обнаружил еще одну опцию, которая может оказаться полезной для некоторых людей, поскольку она позволяет изменять правило CSS внутри элемента стиля, что позволяет избежать повторного использования угловой директивы, такой как ng-style, ng-class, нг-шоу, нг-скрыть, нг-анимация и другие.

Эта опция использует сервис с сервисными переменными, которые устанавливаются контроллером и отслеживаются директивой атрибута, которую я называю "custom-style". Эту стратегию можно использовать по-разному, и я попытался дать общее руководство по этой скрипке .

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

ну, я бы посоветовал вам проверить состояние вашего контроллера с помощью функции, возвращающей true или false .

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

и в вашем контроллере проверьте состояние

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

0

Следует обратить внимание на то, что - если у стиля CSS есть тире - вы должны удалить их. Так что если вы хотите установить background-color, правильный путь:

ng-style="{backgroundColor:myColor}" 

5
Нет, ты не обязан. ng-style = "{'background-color': myColor}" работает отлично.
Герасал

0

Вот как я условно применил серый текстовый стиль к отключенной кнопке

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

Вот рабочий пример:
https://stackblitz.com/edit/example-conditional-disable-button?file=src%2Fapp%2Fapp.component.html

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.