Каков наилучший способ условного применения атрибутов в AngularJS?

296

Мне нужно иметь возможность добавить, например, "contenteditable" к элементам, основываясь на булевой переменной в области видимости.

Пример использования:

<h1 attrs="{'contenteditable=\"true\"': editMode}">{{content.title}}</h1>

Приведет к добавлению contenteditable = true к элементу, если для $scope.editModeнего установлено значение true. Есть ли какой-нибудь простой способ для реализации этого ng-класса, как поведение атрибутов? Я собираюсь написать директиву и поделиться, если нет.

Изменить: я вижу, что, кажется, есть некоторые сходства между моей предложенной директивой attrs и ng-bind-attrs, но она была удалена в 1.0.0.rc3 , почему так?

Кеннет Линн
источник
2
Я не встречал ничего подобного. Я голосую, сделай это! : D Может быть, представить его в угловой проект. Синтаксис, который лучше соответствует классу ng, был бы хорош. ng-attr="expression",
Xesued
Я определенно считаю, что да!
Кеннет Линн
3
На самом деле это не то же самое, что ngClass или ngStyle, потому что они управляют одним атрибутом, а вы хотите контролировать любой атрибут. Я думаю, что было бы лучше создать contentEditableдирективу.
Джош Дэвид Миллер
@JoshDavidMiller +1 на это. Я думаю, есть небольшая выгода, чтобы иметь возможность контролировать любой атрибут, особенно учитывая сложность. Вы можете иметь директивы, условно действующие на переменную.
Умур Kontacı
<h1 ng-attr-contenteditable="{{editMode && true : false}}">{{content.title}}</h1>
Миа

Ответы:

272

Я использую следующее, чтобы условно установить класс attr, когда нельзя использовать ng-класс (например, при стилизации SVG):

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

Тот же подход должен работать для других типов атрибутов.

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

Эшли Дэвис
источник
97
Просто чтобы прояснить этот ответ: если вы добавите к любому атрибуту префикс ng-attr-, то компилятор уберет префикс и добавит атрибут со значением, связанным с результатом углового выражения, из исходного значения атрибута.
Матиас
12
На мой взгляд, легче читать, если вы используете троичный оператор, для которого была добавлена ​​поддержка в 1.1.5. Это будет выглядеть так: {{someConditionalExpression? 'class-when-true': 'class-when-false'}}
dshap
129
проблема с этим подходом состоит в том, что атрибут создается независимо от результата. В идеале мы хотели бы контролировать управление или не создавать атрибут вообще.
Airtonix
24
Обратите внимание, что нг-атрибут был удален из Angular 1.2. Этот ответ больше не действителен.
Иуда Габриэль Химанго
2
Вы неправы. Этот проект github.com/codecapers/AngularJS-FlowChart использует Angular 1.2 и ng-attr-. Также последние документы (Angular 1.4) по-прежнему включают нг-attr-
Эшли Дэвис
120

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

<a ng-attr-href="{{value || undefined}}">Hello World</a>

Будет производить (когда значение ложно)

<a ng-attr-href="{{value || undefined}}" href>Hello World</a>

Так что не используйте, falseпотому что это даст слово «ложь» в качестве значения.

<a ng-attr-href="{{value || false}}" href="false">Hello World</a>

При использовании этого трюка в директиве. Атрибуты для директивы будут ложными, если в них отсутствует значение.

Например, приведенное выше будет ложным.

function post($scope, $el, $attr) {
      var url = $attr['href'] || false;
      alert(url === false);
}
Reactgular
источник
3
Мне нравится этот ответ. Тем не менее, я не думаю, что если значение не определено, он будет скрывать атрибут. Я могу что-то упустить, хотя. Таким образом, первым результатом будет <a ng-attr-href="‹ карманный уровень || undefined ultimatecasts" href> Hello World </a>
Роман К
13
@RomanK Привет, в руководстве говорится, что undefinedэто особый случай. «При использовании ngAttr используется флаг allOrNothing в $ interpolate, поэтому, если какое-либо выражение в интерполированной строке приводит к неопределенности, атрибут удаляется и не добавляется в элемент».
Reactgular
9
Просто примечание, чтобы помочь любым будущим читателям, «неопределенное» поведение, похоже, было добавлено в Angular 1.3. Я использую 1.2.27 и в настоящее время должен IE8.
Адам Маршалл
3
Чтобы подтвердить, что еще Angular 1.2.15 будет отображать href, даже если значение не определено, похоже, что неопределенное поведение начинается в Angular 1.3, как указано в приведенном выше комментарии.
Брайан Огден
Важно отметить, что директива по- ng-attr-fooпрежнему будет всегда вызывать fooдирективу, если она существует, и даже ng-attr-fooвычислять ее undefined. обсуждение
hughes
97

Я получил это работая жесткой настройкой атрибута. И управление применимостью атрибута с использованием логического значения для атрибута.

Вот фрагмент кода:

<div contenteditable="{{ condition ? 'true' : 'false'}}"></div>

Надеюсь, это поможет.

jsbisht
источник
Так как angular может анализировать выражение IIF, это идеально подходит для оценки состояния в текущей области и присвоения значений на основе этого состояния.
МакКайнц
22

В последней версии Angular (1.1.5) они включили условную директиву под названием ngIf. Он отличается от ngShowи ngHideв том , что элементы не скрыты, но не включены в DOM вообще. Они очень полезны для компонентов, которые стоят дорого, но не используются:

<h1 ng-if="editMode" contenteditable=true>{{content.title}}</h1>
Брайан Дженисио
источник
32
Я считаю, что ng-if работает только на уровне элемента, то есть вы не можете указать условие только для одного атрибута элемента.
Макс Стратер
3
Действительно, но вы можете сделать это<h1 ng-if="editMode" contenteditable="true"><h1 ng-if="!editMode">
ByScripts
5
остерегайтесь, однако, это ng-ifсоздает новую область.
Шимон Рахленко
1
@ShimonRachlenko Согласен! Это может быть большим источником путаницы и ошибок. ng-ifсоздает новую область, но ng-showне делает. Это несоответствие всегда было больным местом для меня. Реакция защитного программирования на это такова: «всегда связывайте что-то, что является точкой в ​​выражении», и это не будет проблемой.
Брайан Дженисио
Если вы хотите добавить атрибут, который на самом деле является директивой, это прекрасно работает. Позор о дублировании кода
Адам Маршалл
16

Чтобы получить атрибут, отображающий определенное значение на основе логической проверки, или быть полностью опущенным, если логическая проверка завершилась неудачно, я использовал следующее:

ng-attr-example="{{params.type == 'test' ? 'itWasTest' : undefined }}"

Пример использования:

<div ng-attr-class="{{params.type == 'test' ? 'itWasTest' : undefined }}">

Будет ли вывод <div class="itWasTest">или <div>на основе значенияparams.type

лощина
источник
9

<h1 ng-attr-contenteditable="{{isTrue || undefined }}">{{content.title}}</h1>

выдаст когда isTrue = true: <h1 contenteditable="true">{{content.title}}</h1>

и когда isTrue = false: <h1>{{content.title}}</h1>

Garfi
источник
5
Что
делать,
<h1 ng-attr-contenteditable="{{isTrue ? 'row' : undefined}}">{{content.title}} </h1>
PhatBuck
Это должен быть принятый ответ. Мой сценарий был<video ng-attr-autoplay="{{vm.autoplay || undefined}}" />
LucasM
6

Что касается принятого решения, опубликованного Эшли Дэвисом, описанный метод все еще печатает атрибут в DOM, независимо от того, что значение, которое ему было присвоено, не определено.

Например, при настройке поля ввода как с ng-моделью, так и с атрибутом value:

<input type="text" name="myInput" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />

Независимо от того, что стоит за myValue, атрибут value по- прежнему печатается в DOM, поэтому интерпретируется. Тогда Ng-модель переопределяется.

Немного неприятно, но использование ng-if делает свое дело:

<input type="text" name="myInput" data-ng-if="value" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />
<input type="text" name="myInput" data-ng-if="!value" data-ng-model="myModel" />

Я бы порекомендовал использовать более детальную проверку внутри директив ng-if :)

alexc
источник
При таком подходе вы будете повторять один и тот же код.
Калян
Верно, но это сохраняет декларацию модели в безопасности. Моя проблема с использованием принятого решения состояла в том, что атрибут value оказался в DOM, имея приоритет над объявлением модели. Таким образом, если атрибут значения пуст, а модель - нет, модель будет переопределена, чтобы принять пустое значение.
alexc
6

Также вы можете использовать такое выражение:

<h1 ng-attr-contenteditable="{{ editMode ? true : false }}"></h1>
Камуран Сёнечек
источник
5

Я на самом деле написал патч для этого несколько месяцев назад (после того, как кто-то спросил об этом в #angularjs на freenode).

Вероятно, он не будет объединен, но он очень похож на ngClass: https://github.com/angular/angular.js/pull/4269

Независимо от того, объединены они или нет, существующий материал ng-attr- *, вероятно, подойдет для ваших нужд (как уже упоминали другие), хотя он может быть немного более грубым, чем предлагаемые вами функции в стиле ngClass.

chronicsalsa
источник
2

Для проверки поля ввода вы можете сделать:

<input ng-model="discount" type="number" ng-attr-max="{{discountType == '%' ? 100 : undefined}}">

Это будет применяться атрибут maxк 100только , если discountTypeопределяется как%

Нестор Бритез
источник
1

Изменить : Этот ответ относится к Angular2 +! Извините, я пропустил тег!

Оригинальный ответ:

Что касается очень простого случая, когда вы хотите применить (или установить) атрибут, только если было задано определенное входное значение, это так же просто, как

<my-element [conditionalAttr]="optionalValue || false">

Это так же, как:

<my-element [conditionalAttr]="optionalValue ? optionalValue : false">

(Таким образом, optionValue применяется, если задано, иначе выражение ложно, а атрибут не применяется.)

Пример: у меня был случай, когда я позволил применить цвет, но также и произвольные стили, где атрибут цвета не работал, поскольку он уже был установлен (даже если цвет @Input () не был задан):

@Component({
  selector: "rb-icon",
  styleUrls: ["icon.component.scss"],
  template: "<span class="ic-{{icon}}" [style.color]="color==color" [ngStyle]="styleObj" ></span>",
})
export class IconComponent {
   @Input() icon: string;
   @Input() color: string;
   @Input() styles: string;

   private styleObj: object;
...
}

Таким образом, «style.color» был установлен только тогда, когда там присутствовал атрибут color, иначе можно было бы использовать атрибут color в строке «styles».

Конечно, это также может быть достигнуто с

[style.color]="color" 

и

@Input color: (string | boolean) = false;
Zaphoid
источник
Angular.JS - это Angular 1, который сильно отличается от Angular 2+. Ваше решение отвечает за Angular 2+, но запрашивается AngularJS (1).
ssc-hrep3
@ ssc-hrep3: Вы правы. Извините, что пропустил это! Спасибо. Я отредактировал ответ, чтобы указать на это. :-)
Zaphoid
angularjs не угловой, angularjs угловой 1
дгзорноза
0

На всякий случай, если вам нужно решение для Angular 2, тогда его просто, используйте привязку свойства, как показано ниже, например, вы хотите сделать входные данные только для чтения условно, а затем добавьте в квадратных скобках атрибут attrbute, за которым следует знак = и выражение.

<input [readonly]="mode=='VIEW'"> 
Санджай Сингх
источник
is angularjs (angular1) не угловой (angular2)
дгзорноза
Angular 2+ и Angular JS - это не одно и то же, они больше похожи на разные продукты.
Санджай Сингх
0

Был в состоянии заставить это работать:

ng-attr-aria-current="{{::item.isSelected==true ? 'page' : undefined}}"

Здесь хорошо то, что если item.isSelected равно false, атрибут просто не отображается.

Ричард Стрикленд
источник