2017-10-08 2 views
2

Ich habe zwei Listen von Komponenten, die Daten, die von zwei verschiedenen Diensten nutzen:ngFor hängt von einem anderen ngFor Rendering zu beenden - immer ExpressionChangedAfterItHasBeenCheckedError [Angular 2]

  • die erste Liste einiger Komponenten mit zufälligen Höhen enthält (I kenne ihre Höhen nicht, bis sie gerendert werden)
  • Die Komponenten in der zweiten Liste müssen ihre Höhen basierend auf den Höhen der ersten Liste berechnet haben.

Beiden Listen werden von der gleichen Komponente erzeugt unter Verwendung von zwei * ngFor Schleifen und die Dienste Daten von einer anderen Kind Komponente verändert.

Das Problem ist, dass, wenn sich die Modelldaten ändern, beide ngFor-Schleifen versuchen, die Vorlage zu aktualisieren, aber die zweite fehlschlägt, weil sie von der ersten ngFor abhängig ist, die noch nicht bereit ist.

Ich habe versucht, ChangeDetectorRef.detectChanges() zu verwenden oder auf die Änderungen zu warten, die von der QueryList ausgegeben werden, die die Komponenten der ersten Liste enthält, aber ich bekomme immer noch ExpressionChangedAfterItHasBeenCheckedError.

Das eigentliche Szenario ein bisschen komplizierter ist, aber hier ist eine vereinfachte Version von dem, was der Code wie folgt aussieht:

https://embed.plnkr.co/sr9k0wLQtyWSATiZuqaK/

Vielen Dank im Voraus, dann ist dies meine erste Frage auf Stackoverflow :)

+0

könnten Sie diesen Artikel nützlich [Alles, was Sie über die 'ExpressionChangedAfterItHasBeenCheckedError' Fehler wissen müssen] finden (https: // blog. angularindepth.com/everything-you-not-to-know-about-the-expressionchangedatahaboutcheckderror-error-e3fd9ce7dbb4) –

Antwort

2

Ich würde vermeiden, Methoden zu verwenden, die Höhe innerhalb der Vorlage berechnen. Stattdessen würde ich Daten für Ansicht vorbereiten:

<second-cmp 
    *ngFor="let cmp of generatedData" 
[model]="cmp" 
[height]="cmp.height"> <------------ already calculated value 

Dann würde ich zu QueryList.changes abonnieren Änderungen der erzeugten Elemente zu verfolgen und height dort berechnen:

constructor(
    ..., 
    private cdRef: ChangeDetectorRef) {} 

ngAfterViewInit() { 
    this.components.changes.subscribe(components => { 
     const renderedCmps = components.toArray(); 
     this.generatedData.forEach((x, index) => { 
     switch (index) { 
      case 0: // first 
      x.height = renderedCmps[0].height/2; 
      break; 
      case this.modelData.length: // last 
      x.height = (renderedCmps[renderedCmps.length - 1].height/2); 
      break; 
      default: // in-between 
      x.height = (renderedCmps[index - 1].height + renderedCmps[index].height)/2 
     } 
     }); 
     this.cdRef.detectChanges(); 
    }); 
} 

+ 'px' überflüssig ist, weil wir können, spezifizieren Sie es innerhalb der Artbindung:

[style.height.px]="height" 

Plunker Example

1

Ausgezeichnete Reaktion @yurzui, wirkt wie ein Zauber!

Wenn Sie die Eigenschaft height für die Modelldaten festlegen, entfällt auch die Notwendigkeit, sie separat zu binden, da ich die Referenz des gesamten Modells bereits an die Komponente im * ngFor übergebe.

<second-cmp 
    *ngFor="let cmp of generatedData" 
[model]="cmp"> <!-- the height doesn't need to be binded separately anymore --> 

@Component({ 
selector: 'second-cmp', 
template: ` 
    <li> 
    <div class="item" [style.height.px]="model.height">Calculated height</div> 
    </li>` 
)} 
export class Second { 
    @Input('model') model; 
    // @Input('height') height; <-- removed 
} 

Final solution

+0

Gute Verbesserung) – yurzui