Was ist der beste Weg, um Attribute in AngularJS bedingt anzuwenden?

296

Ich muss in der Lage sein, beispielsweise "contenteditable" zu Elementen hinzuzufügen, basierend auf einer booleschen Variablen für den Bereich.

Anwendungsbeispiel:

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

Würde dazu führen, dass contenteditable = true zum Element hinzugefügt wird, wenn $scope.editModeauf gesetzt wurde true. Gibt es eine einfache Möglichkeit, dieses Attributverhalten wie bei einer ng-Klasse zu implementieren? Ich denke darüber nach, eine Richtlinie zu schreiben und zu teilen, wenn nicht.

Bearbeiten: Ich kann sehen, dass es einige Ähnlichkeiten zwischen meiner vorgeschlagenen attrs-Direktive und ng-bind-attrs zu geben scheint, aber es wurde in 1.0.0.rc3 entfernt , warum so?

Kenneth Lynne
quelle
2
Ich bin auf so etwas nicht gestoßen. Ich stimme dafür! : D Vielleicht senden Sie es an das Winkelprojekt. Eine Syntax, die besser zur ng-Klasse passt, wäre schön. ng-attr="expression".
Xesued
Ich denke definitiv darüber nach, ja!
Kenneth Lynne
3
Dies ist wirklich nicht dasselbe wie ngClass oder ngStyle, da sie ein einzelnes Attribut steuern und Sie jedes Attribut steuern möchten . Ich denke, es wäre besser, eine contentEditableRichtlinie zu erstellen .
Josh David Miller
@JoshDavidMiller +1 dazu. Ich denke, es ist ein kleiner Vorteil, jedes Attribut steuern zu können, insbesondere angesichts der Komplexität. Sie können Anweisungen haben, die bedingt auf eine Variable wirken.
Umur Kontacı
<h1 ng-attr-contenteditable="{{editMode && true : false}}">{{content.title}}</h1>
Mia

Antworten:

272

Ich verwende Folgendes, um die Klasse attr bedingt festzulegen, wenn ng-class nicht verwendet werden kann (zum Beispiel beim Stylen von SVG):

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

Der gleiche Ansatz sollte für andere Attributtypen funktionieren.

(Ich denke, Sie müssen auf dem neuesten instabilen Angular sein, um ng-attr- verwenden zu können. Ich bin derzeit auf 1.1.4)

Ashley Davis
quelle
97
Nur um diese Antwort zu verdeutlichen: Wenn Sie einem Attribut ein Präfix voranstellen ng-attr-, entfernt der Compiler das Präfix und fügt das Attribut hinzu, dessen Wert an das Ergebnis des Winkelausdrucks aus dem ursprünglichen Attributwert gebunden ist.
Matthias
12
Meiner Meinung nach ist es einfacher zu lesen, wenn Sie einen ternären Operator verwenden, für den in 1.1.5 Unterstützung hinzugefügt wurde. Das würde so aussehen: {{someConditionalExpression? 'class-when-true': 'class-when-false'}}
dshap
129
Das Problem bei diesem Ansatz ist, dass das Attribut unabhängig vom Ergebnis erstellt wird. Idealerweise möchten wir steuern, ob das Attribut überhaupt erstellt wird oder nicht.
Airtonix
24
Beachten Sie, dass das ng-attr-Material aus Angular 1.2 entfernt wurde. Diese Antwort ist nicht mehr gültig.
Judah Gabriel Himango
2
Sie liegen falsch. Dieses Projekt github.com/codecapers/AngularJS-FlowChart verwendet Angular 1.2 und ng-attr-. Auch die neuesten Dokumente (Angular 1.4) enthalten noch ng-attr-
Ashley Davis
120

Sie können Attributen ng-attrein Präfix voranstellen, um einen Winkelausdruck auszuwerten. Wenn das Ergebnis der Ausdrücke undefiniert ist, wird der Wert aus dem Attribut entfernt.

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

Wird produzieren (wenn der Wert falsch ist)

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

Verwenden Sie es also nicht, falseda dies das Wort "false" als Wert ergibt.

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

Wenn Sie diesen Trick in einer Direktive verwenden. Die Attribute für die Direktive sind falsch, wenn ihnen ein Wert fehlt.

Zum Beispiel wäre das Obige falsch.

function post($scope, $el, $attr) {
      var url = $attr['href'] || false;
      alert(url === false);
}
Reactgular
quelle
3
Ich mag diese Antwort. Ich glaube jedoch nicht, dass das Attribut ausgeblendet wird, wenn der Wert undefiniert ist. Möglicherweise fehlt mir jedoch etwas. Das erste Ergebnis wäre also <a ng-attr-href="{{value || undefined}}" href> Hallo Welt </a>
Roman K
13
@ RomanK Hallo, das Handbuch besagt, dass dies undefinedein Sonderfall ist. "Bei Verwendung von ngAttr wird das allOrNothing-Flag von $ interpolate verwendet. Wenn also ein Ausdruck in der interpolierten Zeichenfolge zu undefiniert führt, wird das Attribut entfernt und nicht zum Element hinzugefügt."
Reactgular
9
Nur ein Hinweis, um zukünftigen Lesern zu helfen, das "undefinierte" Verhalten scheint in Angular 1.3 hinzugefügt worden zu sein. Ich benutze 1.2.27 und muss derzeit IE8.
Adam Marshall
3
Um zu bestätigen, dass Angular 1.2.15 href anzeigt, auch wenn der Wert undefiniert ist, sieht es so aus, als würde das undefinierte Verhalten in Angular 1.3 beginnen, wie im obigen Kommentar angegeben.
Brian Ogden
Es ist wichtig zu beachten , dass ng-attr-foonoch immer berufen sich auf die fooRichtlinie , wenn es vorhanden ist , auch ng-attr-foozu auswertet undefined. Diskussion
Hughes
97

Ich habe das funktioniert, indem ich das Attribut hart eingestellt habe. Steuern der Anwendbarkeit von Attributen mithilfe des Booleschen Werts für das Attribut.

Hier ist das Code-Snippet:

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

Ich hoffe das hilft.

jsbisht
quelle
Da Angular den IIF-Ausdruck analysieren kann, funktioniert dies perfekt, um den Status im aktuellen Bereich zu bewerten und Werte basierend auf diesem Status zuzuweisen.
McCainz
22

In der neuesten Version von Angular (1.1.5) haben sie eine bedingte Direktive namens aufgerufen ngIf. Es unterscheidet sich von ngShowund ngHidedarin, dass die Elemente nicht ausgeblendet, aber überhaupt nicht im DOM enthalten sind. Sie sind sehr nützlich für Komponenten, deren Erstellung teuer ist, die aber nicht verwendet werden:

<h1 ng-if="editMode" contenteditable=true>{{content.title}}</h1>
Brian Genisio
quelle
32
Ich glaube, ng-if funktioniert nur auf Elementebene, das heißt, Sie können keine Bedingung für nur ein Attribut eines Elements angeben.
Max Strater
3
In der Tat, aber Sie können dann tun<h1 ng-if="editMode" contenteditable="true"><h1 ng-if="!editMode">
ByScripts
5
Beachten Sie jedoch, dass dadurch ng-ifein neuer Bereich entsteht.
Shimon Rachlenko
1
@ ShimonRachlenko Einverstanden! Dies kann eine große Quelle für Verwirrung und Fehler sein. ng-iferstellt einen neuen Bereich, ng-showtut dies aber nicht. Diese Inkonsistenz war für mich immer ein wunder Punkt. Die defensive Programmierreaktion darauf lautet: "Binden Sie immer an etwas, das ein Punkt im Ausdruck ist", und es wird kein Problem sein.
Brian Genisio
Wenn Sie ein Attribut hinzufügen möchten, das eigentlich eine Direktive ist, funktioniert dies hervorragend. Schade um die Codeduplizierung
Adam Marshall
16

Um ein Attribut zu erhalten, das einen bestimmten Wert basierend auf einer booleschen Prüfung anzeigt oder vollständig weggelassen wird, wenn die boolesche Prüfung fehlgeschlagen ist, habe ich Folgendes verwendet:

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

Anwendungsbeispiel:

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

Würde ausgeben <div class="itWasTest">oder <div>basierend auf dem Wert vonparams.type

Tal
quelle
9

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

wird produzieren, wenn isTrue = true: <h1 contenteditable="true">{{content.title}}</h1>

und wenn isTrue = false: <h1>{{content.title}}</h1>

Garfi
quelle
5
Was ist, wenn ich etwas wie <h1
contenteditable
<h1 ng-attr-contenteditable="{{isTrue ? 'row' : undefined}}">{{content.title}} </h1>
PhatBuck
Dies sollte mir die akzeptierte Antwort sein. Mein Szenario war<video ng-attr-autoplay="{{vm.autoplay || undefined}}" />
LucasM
6

In Bezug auf die akzeptierte Lösung, die von Ashley Davis veröffentlicht wurde, druckt die beschriebene Methode das Attribut weiterhin im DOM, unabhängig davon, dass der ihm zugewiesene Wert undefiniert ist.

Beispiel: Bei einem Eingabefeld-Setup mit einem ng-Modell und einem Wertattribut:

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

Unabhängig davon, was hinter myValue steckt, wird das value- Attribut immer noch im DOM gedruckt und somit interpretiert. Das Ng-Modell wird dann überschrieben.

Ein bisschen unangenehm, aber ng-if macht den Trick:

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

Ich würde empfehlen, eine detailliertere Prüfung in den ng-if-Anweisungen durchzuführen :)

alexc
quelle
Mit diesem Ansatz wiederholen Sie jedoch denselben Code.
Kalyan
Stimmt, aber es schützt die Modelldeklaration. Mein Problem bei der Verwendung der akzeptierten Lösung bestand darin, dass das Wertattribut im DOM landete und Vorrang vor der Modelldeklaration hatte. Wenn das Wertattribut leer ist, das Modell jedoch nicht, wird das Modell überschrieben, um einen leeren Wert anzunehmen.
Alexc
6

Sie können auch einen Ausdruck wie diesen verwenden:

<h1 ng-attr-contenteditable="{{ editMode ? true : false }}"></h1>
Kamuran Sönecek
quelle
5

Ich habe tatsächlich vor ein paar Monaten einen Patch dazu geschrieben (nachdem jemand in #angularjs auf freenode danach gefragt hat).

Es wird wahrscheinlich nicht zusammengeführt, ist aber ngClass sehr ähnlich: https://github.com/angular/angular.js/pull/4269

Unabhängig davon, ob es zusammengeführt wird oder nicht, ist das vorhandene ng-attr- * -Material wahrscheinlich für Ihre Anforderungen geeignet (wie andere bereits erwähnt haben), obwohl es möglicherweise etwas klobiger ist als die von Ihnen vorgeschlagene ngClass-ähnliche Funktionalität.

Chronicsalsa
quelle
2

Für die Eingabefeldvalidierung können Sie Folgendes tun:

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

Dadurch wird das Attribut nur angewendet max, 100wenn discountTypedefiniert ist als%

Nestor Britez
quelle
1

Bearbeiten : Diese Antwort bezieht sich auf Angular2 +! Entschuldigung, ich habe den Tag verpasst!

Ursprüngliche Antwort:

Der sehr einfache Fall, in dem Sie ein Attribut nur anwenden (oder festlegen) möchten, wenn ein bestimmter Eingabewert festgelegt wurde, ist so einfach wie

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

Es ist das gleiche wie:

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

(OptionalValue wird also angewendet, wenn der Ausdruck falsch ist und das Attribut nicht angewendet wird.)

Beispiel: Ich hatte den Fall, dass ich eine Farbe anwenden ließ, aber auch beliebige Stile, bei denen das Farbattribut nicht funktionierte, da es bereits festgelegt war (auch wenn die Farbe @Input () nicht angegeben wurde):

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

Daher wurde "style.color" nur festgelegt, wenn das Farbattribut vorhanden war. Andernfalls konnte das Farbattribut in der Zeichenfolge "styles" verwendet werden.

Dies könnte natürlich auch mit erreicht werden

[style.color]="color" 

und

@Input color: (string | boolean) = false;
Zaphoid
quelle
Angular.JS ist Angular 1, das sich stark von Angular 2+ unterscheidet. Ihre Lösung antwortet auf Angular 2+, aber AngularJS (1) wurde angefordert.
ssc-hrep3
@ ssc-hrep3: Du hast recht. Entschuldigung, das habe ich nicht verstanden! Vielen Dank. Ich habe die Antwort bearbeitet, um darauf hinzuweisen. :-)
Zaphoid
ist eckigjs nicht eckig, eckigjs ist eckig 1
dgzornoza
0

Nur für den Fall, dass Sie eine Lösung für Angular 2 benötigen, verwenden Sie einfach die unten stehende Eigenschaftsbindung, z. B. möchten Sie die Eingabe nur bedingt schreibgeschützt machen und dann in attrigen Klammern das Attribut gefolgt von = Zeichen und Ausdruck einfügen.

<input [readonly]="mode=='VIEW'"> 
Sanjay Singh
quelle
ist eckigjs (eckig1) nicht eckig (eckig2)
dgzornoza
Angular 2+ und Angular JS sind nicht gleich, sie ähneln eher verschiedenen Produkten.
Sanjay Singh
0

Konnte dies zum Laufen bringen:

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

Das Schöne dabei ist, dass wenn item.isSelected false ist, das Attribut einfach nicht gerendert wird.

Richard Strickland
quelle