it-swarm.com.de

* ngIf und * ngFor für dasselbe Element, das Fehler verursacht

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 lis 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?

299
garethdn

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

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

2016 Winkel 2 Beta

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>

Aktualisierte Antwort 2018

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

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.

27
Mark Rajcok

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

27
Ajmal sha

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

4
Zyzle

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>
3
charliebear240

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>
3
ronald8192

Aufwinkeln zu Beta2 Beta2

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.

ngFür Vorlage verwenden:

<template ngFor #abc [ngForOf]="someArray">
    code here....
</template>

ngIf mit Vorlage:

<template [ngIf]="show">
    code here....
</template>    

Weitere Informationen zu Strukturrichtlinien in angle2 finden Sie hier .

2
Pardeep Jain

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>
2
Alireza
<div *ngFor="let thing of show ? stuff : []">
  {{log(thing)}}
  <span>{{thing.name}}</span>
</div>
1
Prashant Borde

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

0
Rajiv

in html:

<div [ngClass]="{'disabled-field': !show}" *ngFor="let thing of stuff">
    {{thing.name}}
</div>

in CSS:

.disabled-field {
    pointer-events: none;
    display: none;
}
0

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

0
Pradip Patil

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.

0