Ich habe ein Problem mit dem Versuch, Angulars *ngFor
und *ngIf
für dasselbe Element zu verwenden.
Wenn Sie versuchen, die Auflistung in *ngFor
zu durchlaufen, wird die Auflistung als null
angesehen und schlägt daher fehl, wenn Sie versuchen, auf ihre Eigenschaften in der Vorlage zuzugreifen.
@Component({
selector: 'Shell',
template: `
<h3>Shell</h3><button (click)="toggle()">Toggle!</button>
<div *ngIf="show" *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
`
})
export class ShellComponent implements OnInit {
public stuff:any[] = [];
public show:boolean = false;
constructor() {}
ngOnInit() {
this.stuff = [
{ name: 'abc', id: 1 },
{ name: 'huo', id: 2 },
{ name: 'bar', id: 3 },
{ name: 'foo', id: 4 },
{ name: 'thing', id: 5 },
{ name: 'other', id: 6 },
]
}
toggle() {
this.show = !this.show;
}
log(thing) {
console.log(thing);
}
}
Ich weiß, dass die einfache Lösung darin besteht, den *ngIf
um eine Stufe nach oben zu verschieben, aber für Szenarien wie das Durchlaufen von Listenelementen in einer ul
würde ich entweder eine leere li
erhalten, wenn die Sammlung leer ist, oder meine li
s in redundanten Containerelementen.
Beispiel bei diesem plnkr .
Beachten Sie den Konsolenfehler:
EXCEPTION: TypeError: Cannot read property 'name' of null in [{{thing.name}} in [email protected]:12]
Mache ich etwas falsch oder ist das ein Fehler?
Angular v2 unterstützt nicht mehr als eine Strukturanweisung für dasselbe Element.
Verwenden Sie als Workaround das Element<ng-container>
, mit dem Sie separate Elemente für jede strukturelle Direktive verwenden können. Es ist jedoch nicht mit dem DOM versehen.
<ng-container *ngIf="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</ng-container>
<ng-template>
(<template>
vor Angular v4) erlaubt dasselbe, jedoch mit einer anderen Syntax, die verwirrend ist und nicht mehr empfohlen wird
<ng-template [ngIf]="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</ng-template>
Wie alle darauf hingewiesen haben, obwohl mehrere Template-Direktiven in einem einzigen Element in Winkel 1.x funktionieren, ist dies in Angular 2. Nicht zulässig. Weitere Informationen finden Sie hier: https://github.com/) Winkel/Winkel/Ausgaben/7315
die Lösung besteht darin, den <template>
als Platzhalter zu verwenden, so dass der Code so lautet
<template *ngFor="let nav_link of defaultLinks" >
<li *ngIf="nav_link.visible">
.....
</li>
</template>
aber aus irgendeinem Grund funktioniert 2.0.0-rc.4
in diesem Fall nicht. In diesem Fall können Sie dies verwenden
<template ngFor let-nav_link [ngForOf]="defaultLinks" >
<li *ngIf="nav_link.visible">
.....
</li>
</template>
Bei Aktualisierungen empfiehlt winke v6 jetzt, 2018 anstelle von <ng-container>
<template>
zu verwenden.
also hier ist die aktualisierte antwort.
<ng-container *ngFor="let nav_link of defaultLinks" >
<li *ngIf="nav_link.visible">
.....
</li>
</ng-container>
Wie @Zyzle und @ Günter in einem Kommentar ( https://github.com/angular/angular/issues/7315 ) erwähnt, wird dies nicht unterstützt.
Mit
<ul *ngIf="show">
<li *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</li>
</ul>
es gibt keine leeren <li>
-Elemente, wenn die Liste leer ist. Sogar das <ul>
-Element existiert nicht (wie erwartet).
Wenn die Liste gefüllt ist, sind keine redundanten Containerelemente vorhanden.
Die Diskussion " github" (4792) , die @Zyzle in seinem Kommentar erwähnte, stellt auch eine andere Lösung dar, die <template>
verwendet (unten verwende ich Ihr ursprüngliches Markup - mit <div>
s):
<template [ngIf]="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</template>
Diese Lösung führt auch keine zusätzlichen/redundanten Containerelemente ein.
Ich habe noch eine Lösung.
Verwenden Sie [hidden]
anstelle von *ngIf
<div [hidden]="!show" *ngFor="let thing of stuff">
Der Unterschied ist, dass *ngIf
das Element aus dem DOM entfernt, während [hidden]
tatsächlich mit dem CSS
-Stil abgespielt wird, indem die Anzeige eingestellt wird: none
Sie können nicht ngFor
und ngIf
für dasselbe Element verwenden. Sie könnten das Feld, das Sie in ngFor
verwenden, so lange ausfüllen, bis Sie auf den Schalter in Ihrem Beispiel klicken.
Hier ist eine grundlegende (nicht gute) Möglichkeit, wie Sie dies tun könnten: http://plnkr.co/edit/Pylx5HSWIZ7ahoC7wT6P
In der folgenden Tabelle sind nur Elemente aufgeführt, für die ein Anfängerwert festgelegt ist . Erfordert sowohl den *ngFor
als auch den *ngIf
, um unerwünschte Zeilen in HTML zu verhindern.
Ursprünglich hatten *ngIf
und *ngFor
das gleiche <tr>
-Tag, funktionieren jedoch nicht . Ein <div>
für die *ngFor
-Schleife wurde hinzugefügt und *ngIf
im <tr>
-Tag platziert.
<table class="table lessons-list card card-strong ">
<tbody>
<div *ngFor="let lesson of lessons" >
<tr *ngIf="lesson.isBeginner">
<!-- next line doesn't work -->
<!-- <tr *ngFor="let lesson of lessons" *ngIf="lesson.isBeginner"> -->
<td class="lesson-title">{{lesson.description}}</td>
<td class="duration">
<i class="fa fa-clock-o"></i>
<span>{{lesson.duration}}</span>
</td>
</tr>
</div>
</tbody>
</table>
Das wird funktionieren, aber das Element bleibt im DOM.
.hidden{
display: none;
}
<div [class.hidden]="!show" *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
Nun können Sie ab Version2 Beta 8 *ngIf
und *ngFor
für dieselbe Komponente verwenden, siehe hier .
Wechseln:
Manchmal können wir HTML-Tags nicht in einem anderen verwenden, wie in tr
, th
(table
) oder in li
(ul
). Wir können kein anderes HTML-Tag verwenden, aber wir müssen in derselben Situation etwas tun, damit wir das HTML5-Feature-Tag <template>
auf diese Weise verwenden können.
<template ngFor #abc [ngForOf]="someArray">
code here....
</template>
<template [ngIf]="show">
code here....
</template>
Weitere Informationen zu Strukturrichtlinien in angle2 finden Sie hier .
Sie können nicht mehr als einen Structural Directive
in Angular für dasselbe Element verwenden. Dies führt zu einer schlechten Verwirrung und Struktur. Sie müssen sie also in zwei separaten verschachtelten Elementen anwenden (oder Sie können ng-container
verwenden).
Eine strukturelle Anweisung pro Hostelement
Eines Tages möchten Sie einen HTML-Block wiederholen, jedoch nur, wenn eine besondere Bedingung ist wahr. Sie werden versuchen, sowohl * ngFor als auch .__ einzugeben. ein * ngIf im selben Host-Element. Angular lässt dich nicht. Du darfst nur eine strukturelle Direktive auf ein Element anwenden.
Der Grund ist die Einfachheit. Strukturelle Direktiven können komplexe Aufgaben erledigen. mit dem Host-Element und seinen Nachkommen. Wenn zwei Richtlinien lagen. Anspruch auf das gleiche Host-Element, welches hat Vorrang? Welche sollte zuerst die NgIf oder die NgFor gehen? Kann der NgIf den Effekt abbrechen der NgFor? Wenn ja (und es scheint so zu sein), wie sollte Winkel verallgemeinern die Möglichkeit, andere strukturelle Strukturen abzubrechen richtlinien
Auf diese Fragen gibt es keine einfachen Antworten. Mehrfachverbot strukturelle Richtlinien machen sie irrelevant. Es gibt eine einfache Lösung für In diesem Anwendungsfall gilt: Platzieren Sie die * ngIf auf einem Containerelement, das die. * ngFür -Element. Ein oder beide Elemente können ein ng-container sein, sodass Sie keine zusätzlichen HTML-Ebenen einführen müssen.
Sie können also ng-container
(Angular4) als Wrapper (wird aus dem Dom gelöscht) oder ein div oder span verwenden, wenn Sie über Klasse oder andere Attribute verfügen:
<div class="right" *ngIf="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</div>
<div *ngFor="let thing of show ? stuff : []">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
<!-- Since angular2 stable release multiple directives are not supported on a single element(from the docs) still you can use it like below -->
<ul class="list-group">
<template ngFor let-item [ngForOf]="stuff" [ngForTrackBy]="trackBy_stuff">
<li *ngIf="item.name" class="list-group-item">{{item.name}}</li>
</template>
</ul>
in html:
<div [ngClass]="{'disabled-field': !show}" *ngFor="let thing of stuff">
{{thing.name}}
</div>
in CSS:
.disabled-field {
pointer-events: none;
display: none;
}
Sie können nicht mehrere Strukturanweisungen für dasselbe Element verwenden. Wickeln Sie Ihr Element in ng-template
ein und verwenden Sie dort eine Strukturanweisung
Sie können auchng-template
(anstelle von template. Beachten Sie den Hinweis zur Verwendung des template-Tags), um * ngFor und ngIf auf dasselbe HTML-Element anzuwenden. Hier ist ein Beispiel, wo Sie sowohl * ngIf als auch * ngFor für dasselbe tr Element in der eckigen Tabelle verwenden können.
<tr *ngFor = "let fruit of fruiArray">
<ng-template [ngIf] = "fruit=='Apple'>
<td> I love apples!</td>
</ng-template>
</tr>
wo fruiArray = ['Apple', 'banana', 'mango', 'pineapple']
.
Hinweis:
Der Nachteil der Verwendung nur des template
-Tags anstelle desng-template
- Tags besteht darin, dass an einigen Stellen StaticInjectionError
ausgelöst wird.