Qual è il modo migliore per applicare condizionalmente gli attributi in AngularJS?


296

Devo poter aggiungere ad esempio "contenteditable" agli elementi, basato su una variabile booleana nell'ambito.

Esempio di utilizzo:

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

Si tradurrebbe in contenteditable = true aggiunto all'elemento se $scope.editModeimpostato su true. C'è un modo semplice per implementare questo comportamento di attributo simile alla classe ng? Sto pensando di scrivere una direttiva e condividerla in caso contrario.

Modifica: vedo che sembrano esserci delle somiglianze tra la mia proposta attrs direttiva e ng-bind-attrs, ma è stata rimossa in 1.0.0.rc3 , perché?


2
Non ho mai trovato nulla del genere. Io voto fallo! : D Forse lo sottopongo al progetto angolare. Una sintassi che corrisponda meglio alla classe ng sarebbe piacevole. ng-attr="expression".
Xesued

Sto sicuramente considerando che sì!
Kenneth Lynne,

3
Questo in realtà non è lo stesso di ngClass o ngStyle perché controllano un singolo attributo e tu vuoi controllare qualsiasi attributo. Penso che sarebbe meglio creare una contentEditabledirettiva.
Josh David Miller,

@JoshDavidMiller +1 su questo. Penso che ci sia un piccolo vantaggio per essere in grado di controllare qualsiasi attributo, soprattutto considerando la complessità. Puoi avere direttive che agiscono condizionatamente su una variabile.
Umur Kontacı

<h1 ng-attr-contenteditable="{{editMode && true : false}}">{{content.title}}</h1>
mia

Risposte:


272

Sto usando quanto segue per impostare condizionatamente la classe attr quando ng-class non può essere usata (ad esempio quando si disegna lo SVG):

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

Lo stesso approccio dovrebbe funzionare per altri tipi di attributi.

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


97
Giusto per chiarire questa risposta: se si applica un prefisso a qualsiasi attributo ng-attr-, il compilatore eliminerà il prefisso e aggiungerà l'attributo con il suo valore associato al risultato dell'espressione angolare dal valore dell'attributo originale.
Matthias,

12
Secondo me è più facile da leggere se si utilizza un operatore ternario, per il quale è stato aggiunto il supporto in 1.1.5. Sembrerebbe: {{someConditionalExpression? 'class-when-true': 'class-when-false'}}
dshap,

129
il problema con questo approccio è che l'attributo viene creato indipendentemente dal risultato. Idealmente vorremmo controllare se l'attributo viene creato o meno.
airtonix,

24
Si noti che ng-attr-stuff è stato rimosso da Angular 1.2. Questa risposta non è più valida.
Judah Gabriel Himango,

2
Tui hai torto. Questo progetto github.com/codecapers/AngularJS-FlowChart utilizza Angular 1.2 e ng-attr-. Anche gli ultimi documenti (Angular 1.4) includono ancora ng-attr-
Ashley Davis

120

È possibile ng-attraggiungere un prefisso agli attributi per valutare un'espressione angolare. Quando il risultato delle espressioni non definito, questo rimuove il valore dall'attributo.

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

Produrrà (quando il valore è falso)

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

Quindi non usare falseperché questo produrrà la parola "falso" come valore.

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

Quando si utilizza questo trucco in una direttiva. Gli attributi per la direttiva saranno falsi se mancano di un valore.

Ad esempio, quanto sopra sarebbe falso.

function post($scope, $el, $attr) {
      var url = $attr['href'] || false;
      alert(url === false);
}

3
Mi piace questa risposta. Tuttavia, non penso che se il valore non è definito, nasconderà l'attributo. Potrei mancare qualcosa, però. Quindi il primo risultato sarebbe <a ng-attr-href="{{value || undefined}}" href> Hello World </a>
Roman K

13
@RomanK ciao, il manuale afferma che undefinedè un caso speciale. "Quando si utilizza ngAttr, viene utilizzato il flag allOrNothing di $ interpolate, quindi se qualsiasi espressione nella stringa interpolata risulta indefinita, l'attributo viene rimosso e non aggiunto all'elemento."
Reactgular,

9
Solo una nota per aiutare i futuri lettori, il comportamento "indefinito" sembra essere stato aggiunto in Angular 1.3. Sto usando 1.2.27 e attualmente devo IE8.
Adam Marshall,

3
Per confermare ancora un po 'di Angular 1.2.15 visualizzerà href anche se il valore non è definito, sembra che il comportamento indefinito inizi in Angular 1.3 come afferma il commento sopra.
Brian Ogden,

È importante notare che ng-attr-foocontinuerà sempre a invocare la foodirettiva se esiste, anche a ng-attr-foovalutare undefined. discussione
hughes

97

Ho funzionato impostando duramente l'attributo. E controllando l'applicabilità dell'attributo usando il valore booleano per l'attributo.

Ecco il frammento di codice:

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

Spero che aiuti.


Poiché angolare può analizzare l'espressione IIF, questo funziona perfettamente per la valutazione dello stato nell'ambito corrente e l'assegnazione di valori basati su quello stato.
McCainz,

22

Nell'ultima versione di Angular (1.1.5), hanno incluso una direttiva condizionale chiamata ngIf. È diverso da ngShowe ngHidein quanto gli elementi non sono nascosti, ma non sono affatto inclusi nel DOM. Sono molto utili per i componenti che sono costosi da creare ma non utilizzati:

<h1 ng-if="editMode" contenteditable=true>{{content.title}}</h1>

32
Credo che ng-se funziona solo a livello di elemento, cioè non è possibile specificare un condizionale per un solo attributo di un elemento.
Max Strater,

3
Anzi, ma puoi farlo<h1 ng-if="editMode" contenteditable="true"><h1 ng-if="!editMode">
ByScripts il

5
attenzione, tuttavia, che ng-ifcrea un nuovo ambito.
Shimon Rachlenko,

1
@ShimonRachlenko Concordato! Questo può essere una grande fonte di confusione e bug. ng-ifcrea un nuovo ambito ma ng-shownon lo fa. Questa incoerenza è sempre stata un punto dolente per me. La reazione di programmazione difensiva a questo è: "si legano sempre a qualcosa che un punto nell'espressione" e non sarà un problema.
Brian Genisio,

Se vuoi aggiungere un attributo che è in realtà una direttiva, funziona benissimo. Peccato per la duplicazione del codice
Adam Marshall,

16

Per ottenere un attributo per mostrare un valore specifico basato su un controllo booleano o essere omesso del tutto se il controllo booleano falliva, ho usato quanto segue:

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

Esempio di utilizzo:

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

Output <div class="itWasTest">o <div>basato sul valore diparams.type


9

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

produrrà quando isTrue = true: <h1 contenteditable="true">{{content.title}}</h1>

e quando isTrue = false: <h1>{{content.title}}</h1>


5
e se volessi qualcosa come <h1 contenteditable = "row">
SuperUberDuper

<h1 ng-attr-contenteditable="{{isTrue ? 'row' : undefined}}">{{content.title}} </h1>
PhatBuck,

Questa dovrebbe essere la risposta accettata. Il mio scenario era<video ng-attr-autoplay="{{vm.autoplay || undefined}}" />
LucasM,

6

Per quanto riguarda la soluzione accettata, quella pubblicata da Ashley Davis, il metodo descritto stampa ancora l'attributo nel DOM, indipendentemente dal fatto che il valore che è stato assegnato non sia definito.

Ad esempio, su un'impostazione del campo di input con un modello ng e un attributo value:

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

Indipendentemente da ciò che sta dietro myValue, il valore attributo viene comunque stampato nel DOM, quindi interpretato. Ng-model quindi, viene sostituito.

Un po 'spiacevole, ma usando ng-if il trucco:

<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" />

Consiglierei di utilizzare un controllo più dettagliato all'interno delle direttive ng-if :)


Con questo approccio, dovrai ripetere lo stesso codice.
Kalyan,

Vero, ma mantiene sicura la dichiarazione del modello. Il mio problema con l'utilizzo della soluzione accettata era che l'attributo value era finito nel DOM, avendo la precedenza sulla dichiarazione del modello. Pertanto, se l'attributo value è vuoto ma il modello non lo è, il modello verrà sostituito per assumere un valore vuoto.
alexc,

6

Inoltre puoi usare un'espressione come questa:

<h1 ng-attr-contenteditable="{{ editMode ? true : false }}"></h1>

5

In realtà ho scritto una patch per farlo alcuni mesi fa (dopo che qualcuno l'ha chiesto in #angularjs su freenode).

Probabilmente non verrà unito, ma è molto simile a ngClass: https://github.com/angular/angular.js/pull/4269

Indipendentemente dal fatto che venga unito o meno, la roba esistente di ng-attr- * è probabilmente adatta alle tue esigenze (come altri hanno già detto), anche se potrebbe essere un po 'più clunk della funzionalità in stile ngClass che stai suggerendo.


2

Per la convalida del campo di input è possibile eseguire:

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

Ciò si applica l'attributo maxdi 100solo se discountTypeè definito come%


1

Modifica : questa risposta è correlata ad Angular2 +! Scusa, ho perso il tag!

Risposta originale:

Per quanto riguarda il caso molto semplice in cui si desidera applicare (o impostare) un attributo solo se è stato impostato un determinato valore di Input, è facile come

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

È lo stesso di:

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

(Quindi optionalValue viene applicato se indicato altrimenti l'espressione è falsa e l'attributo non viene applicato.)

Esempio: ho avuto il caso, in cui ho lasciato applicare un colore ma anche stili arbitrari, in cui l'attributo color non funzionava come era già impostato (anche se il colore @Input () non è stato fornito):

@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;
...
}

Pertanto, "style.color" è stato impostato solo quando era presente l'attributo color, altrimenti è stato possibile utilizzare l'attributo color nella stringa "styles".

Certamente, questo potrebbe anche essere raggiunto con

[style.color]="color" 

e

@Input color: (string | boolean) = false;

Angular.JS è Angular 1, che è molto diverso da Angular 2+. La tua soluzione risponde per Angular 2+, ma è stato richiesto AngularJS (1).
ssc-hrep3

@ ssc-hrep3: hai ragione. Scusa, mi sono perso! Grazie. Ho modificato la risposta per evidenziarlo. :-)
Zaphoid,

è angularjs non angolare, angularjs è angolare 1
dgzornoza il

0

Nel caso in cui tu abbia bisogno di una soluzione per Angular 2, allora è semplice, usa il binding di proprietà come di seguito, ad esempio vuoi fare in modo che l'input venga letto solo in modo condizionale, quindi aggiungi tra parentesi quadre l'attrazione seguita da = segno ed espressione.

<input [readonly]="mode=='VIEW'"> 

è angularjs (angular1) non angolare (angular2)
dgzornoza il

angular 2+ e Angular JS non sono uguali, sono più simili a prodotti diversi del tutto.
Sanjay Singh,

0

È stato in grado di farlo funzionare:

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

La cosa bella qui è che se item.isSelected è falso, l'attributo semplicemente non viene visualizzato.

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.