* ngIf e * ngPer sullo stesso elemento che causa errore

Sto avendo un problema con il tentativo di usare Angular’s *ngFor e *ngIf sullo stesso elemento.

Quando si tenta di eseguire il ciclo attraverso la raccolta in *ngFor , la raccolta viene considerata null e di conseguenza non riesce quando si tenta di accedere alle sue proprietà nel modello.

 @Component({ selector: 'shell', template: ` 

Shell

{{log(thing)}} {{thing.name}}
` }) 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); } }

So che la soluzione facile è spostare il livello *ngIf su un livello, ma per scenari come il loop su elementi di lista in un ul , mi *ngIf con un li vuoto se la raccolta è vuota, o il mio si è avvolto in un contenitore ridondante elementi.

Esempio in questo plnkr .

Notare l’errore della console:

 EXCEPTION: TypeError: Cannot read property 'name' of null in [{{thing.name}} in [email protected]:12] 

Sto facendo qualcosa di sbagliato o si tratta di un bug?

Angular v2 non supporta più di una direttiva strutturale sullo stesso elemento.
Per ovviare al problema, utilizzare l’elemento che consente di utilizzare elementi separati per ogni direttiva strutturale, ma non viene stampato sul DOM .

  
{{log(thing)}} {{thing.name}}

( before Angular v4) permette di fare lo stesso ma con una syntax diversa che è confusa e non più consigliata

  
{{log(thing)}} {{thing.name}}

Come @Zyzle menzionato e @ Günter menzionato in un commento ( https://github.com/angular/angular/issues/7315 ), questo non è supportato.

Con

 
  • {{log(thing)}} {{thing.name}}

non ci sono elementi

  • vuoti quando la lista è vuota. Anche l’elemento

      non esiste (come previsto).

      Quando la lista è popolata, non ci sono elementi del contenitore ridondanti.

      La discussione github (4792) che @Zyzle ha menzionato nel suo commento presenta anche un’altra soluzione usando (qui sotto sto usando il tuo markup originale – usando

      s):

        

      Questa soluzione inoltre non introduce alcun elemento contenitore aggiuntivo / ridondante.

      Come tutti hanno sottolineato, anche se avere più direttive template in un singolo elemento funziona in 1.x angular, non è consentito in Angular 2. puoi trovare maggiori informazioni da qui: https://github.com/angular/angular/issues/ 7315

      2016 angular 2 beta

      la soluzione è usare come segnaposto, quindi il codice va così

        

      ma per qualche ragione sopra non funziona in 2.0.0-rc.4 in quel caso puoi usare questo

        

      Risposta aggiornata 2018

      Con gli aggiornamenti in questo momento nel 2018 angular v6 angular consiglia di utilizzare invece di

      quindi se qui è la risposta aggiornata per gli aggiornamenti angolari più recenti

        
    • .....
    • Ho un’altra soluzione.

      Usa [hidden] invece di *ngIf

       

      La differenza è che *ngIf rimuoverà l’elemento dal DOM, mentre [hidden] realtà gioca con lo stile CSS impostando display: none

      Non puoi avere ngFor e ngIf sullo stesso elemento. Quello che potresti fare è tenere a bada il popolamento dell’array che stai usando in ngFor fino a quando non viene cliccato il ngFor nel tuo esempio.

      Ecco un modo semplice (non eccezionale) per farlo: http://plnkr.co/edit/Pylx5HSWIZ7ahoC7wT6P

      Funzionerà ma l’elemento sarà ancora nel DOM.

       .hidden{ display: none; } 

       
      {{log(thing)}} {{thing.name}}

      La tabella seguente elenca solo gli elementi con un valore impostato come “principiante”. Richiede sia *ngFor che *ngIf per impedire le righe indesiderate in html.

      Originariamente aveva *ngIf e *ngFor sullo stesso tag

      , ma non funziona. Aggiunto un

      per il ciclo *ngFor e posizionato *ngIf nel tag

      , funziona come previsto.

       
      {{lesson.description}} {{lesson.duration}}

      Aggiornato a angular2 beta 8

      Ora come da angular2 beta 8 possiamo usare *ngIf e *ngFor sullo stesso componente, vedi qui .

      Alternato:

      A volte non possiamo usare tag HTML all’interno di un altro come in tr , th ( table ) o in li ( ul ). Non possiamo usare un altro tag HTML, ma dobbiamo eseguire alcune azioni nella stessa situazione in modo da poter utilizzare il tag in HTML5 in questo modo.

      ngPer utilizzare il modello:

        

      ngIf usando il modello:

        

      Per ulteriori informazioni sulle direttive strutturali in angular2, vedere qui .

      Non puoi usare più di una Structural Directive in Angolare sullo stesso elemento, crea una ctriggers confusione e struttura, quindi devi applicarli in 2 elementi nidificati separati (o puoi usare ng-container ), leggi questa dichiarazione da Angular squadra:

      Una direttiva strutturale per elemento host

      Un giorno vorrete ripetere un blocco di HTML ma solo quando una particolare condizione è vera. Proverai a mettere sia un * ngFor che un * ngIf sullo stesso elemento host. Angular non ti lascerà. È ansible applicare solo una direttiva strutturale a un elemento.

      La ragione è la semplicità. Le direttive strutturali possono fare cose complesse con l’elemento host e i suoi discendenti. Quando due direttive rivendicano lo stesso elemento host, quale ha la precedenza? Quale dovrebbe andare prima, il NgIf o il NgFor? NGF può cancellare l’effetto del NgFor? Se è così (e sembra che dovrebbe essere così), come dovrebbe Angular generalizzare la possibilità di annullare per altre direttive strutturali?

      Non ci sono risposte facili a queste domande. Proibire direttive strutturali multiple li rende discutibili. C’è una soluzione semplice per questo caso d’uso: metti * ngIf su un elemento contenitore che racchiude l’elemento * ngFor . Uno o entrambi gli elementi possono essere un ng-container in modo da non dover introdurre livelli extra di HTML.

      Quindi puoi usare ng-container (Angular4) come wrapper (sarà cancellato dal dom) o div o span se hai classi o altri attributi come di seguito:

       
      {{log(thing)}} {{thing.name}}
       
      {{log(thing)}} {{thing.name}}