Wie soll ich die neue statische Option für @ViewChild in Angular 8 verwenden?

204

Wie soll ich das neue Angular 8-Ansichtskind konfigurieren?

@ViewChild('searchText', {read: ElementRef, static: false})
public searchTextInput: ElementRef;

vs.

@ViewChild('searchText', {read: ElementRef, static: true})
public searchTextInput: ElementRef;

Welches ist besser? Wann sollte ich static:truevs verwenden static:false?

Patrik Laszlo
quelle

Antworten:

237

In den meisten Fällen möchten Sie verwenden {static: false}. Wenn Sie dies so einstellen, wird sichergestellt, dass Abfrageübereinstimmungen gefunden werden, die von der Bindungsauflösung abhängen (z. B. strukturelle Anweisungen *ngIf, etc...).

Beispiel für die Verwendung static: false:

@Component({
  template: `
    <div *ngIf="showMe" #viewMe>Am I here?</div>
    <button (click)="showMe = !showMe"></button>
  ` 
})
export class ExampleComponent {
  @ViewChild('viewMe', { static: false })
  viewMe?: ElementRef<HTMLElement>; 

  showMe = false;
}

Das static: falsewird die Standard - Ausweichverhalten in Angular 9. Lesen Sie mehr sein hier und hier

Die { static: true }Option wurde eingeführt, um das Erstellen eingebetteter Ansichten im laufenden Betrieb zu unterstützen. Wenn Sie eine Ansicht dynamisch erstellen und auf die zugreifen möchten TemplateRef, können Sie dies nicht tun, ngAfterViewInitda dies zu einem ExpressionHasChangedAfterCheckedFehler führt. Wenn Sie das statische Flag auf true setzen, wird Ihre Ansicht in ngOnInit erstellt.

Dennoch:

In den meisten anderen Fällen ist die beste Vorgehensweise die Verwendung {static: false}.

Beachten Sie jedoch, dass die { static: false }Option in Winkel 9 als Standard festgelegt wird. Dies bedeutet, dass das Setzen des statischen Flags nicht mehr erforderlich ist, es sei denn, Sie möchten die static: trueOption verwenden.

Mit dem ng updateBefehl angle cli können Sie Ihre aktuelle Codebasis automatisch aktualisieren.

Einen Migrationsleitfaden und noch mehr Informationen dazu finden Sie hier und hier

Was ist der Unterschied zwischen statischen und dynamischen Abfragen?

Die statische Option für @ ViewChild () - und @ ContentChild () -Abfragen bestimmt, wann die Abfrageergebnisse verfügbar werden.

Bei statischen Abfragen (static: true) wird die Abfrage aufgelöst, sobald die Ansicht erstellt wurde, jedoch bevor die Änderungserkennung ausgeführt wird. Das Ergebnis wird jedoch niemals aktualisiert, um Änderungen an Ihrer Ansicht widerzuspiegeln, z. B. Änderungen an den Blöcken ngIf und ngFor.

Bei dynamischen Abfragen (statisch: false) wird die Abfrage entweder nach ngAfterViewInit () oder ngAfterContentInit () für @ViewChild () bzw. @ContentChild () aufgelöst. Das Ergebnis wird aktualisiert, um Änderungen an Ihrer Ansicht vorzunehmen, z. B. Änderungen an den Blöcken ngIf und ngFor.

Poul Kruijt
quelle
Bitte aktualisieren Sie den Link für eckige Dokumente (geändert nach der Veröffentlichung) angular.io/api/core/ViewChild#description
Sachin Gupta
2
Ich kann nicht auf die Instanz von childView zugreifen. Es heißt die ganze Zeit undefiniert.
Nesan Mano
Können Sie bitte einen Link zu diesen Informationen zum Entfernen der statischen Option in Angular 9 bereitstellen?
Alex Marinov
@AlexMarinov Ich habe meine Antwort aktualisiert, um klarer zu machen, was in Winkel 9 passieren wird. Der Link dazu befindet sich im Migrationshandbuch
Poul Kruijt
1
@ MinhNghĩa Wenn Sie die gesamte Komponente außerhalb der Komponentenvorlage verschachteln, können Sie diese verwenden { static: true }. Wenn jedoch kein direkter Zugriff auf das darin enthaltene ViewChild erforderlich ist ngOnInit, sollten Sie nur die verwenden { static: false }.
Poul Kruijt
86

Als Faustregel können Sie also Folgendes wählen:

  • { static: true }muss festgelegt sein , wenn Sie die zugreifen möchten ViewChildin ngOnInit.

  • { static: false }kann nur in zugegriffen werden ngAfterViewInit. Dies ist auch das, was Sie tun möchten, wenn Sie eine strukturelle Direktive (dh *ngIf) für Ihr Element in Ihrer Vorlage haben.

dave0688
quelle
2
Hinweis: In Angular 9 ist das statische Flag standardmäßig false, sodass "alle {static: false} -Flags sicher entfernt werden können". Dokumentation: angle.io/guide/static-query-migration
Stevethemacguy
17

Aus den eckigen Dokumenten

statisch - Gibt an, ob Abfrageergebnisse aufgelöst werden sollen, bevor die Änderungserkennung ausgeführt wird (dh nur statische Ergebnisse zurückgeben). Wenn diese Option nicht bereitgestellt wird, greift der Compiler auf sein Standardverhalten zurück, bei dem Abfrageergebnisse verwendet werden, um den Zeitpunkt der Abfrageauflösung zu bestimmen. Wenn sich Abfrageergebnisse in einer verschachtelten Ansicht befinden (z. B. * ngIf), wird die Abfrage aufgelöst, nachdem die Änderungserkennung ausgeführt wurde. Andernfalls wird es behoben, bevor die Änderungserkennung ausgeführt wird.

Es kann eine bessere Idee sein, static:truewenn das Kind nicht von irgendwelchen Bedingungen abhängig ist. Wenn sich die Sichtbarkeit des Elements ändert, static:falsekann dies zu besseren Ergebnissen führen.

PS: Da es sich um eine neue Funktion handelt, müssen wir möglicherweise Benchmarks für die Leistung ausführen.

Bearbeiten

Wie von @Massimiliano Sartoretto erwähnt, kann Github Commit Ihnen weitere Einblicke geben.

Sachin Gupta
quelle
3
Ich würde die offiziellen Motivationen hinter dieser Funktion hinzufügen github.com/angular/angular/pull/28810
Massimiliano Sartoretto
2

Kam hierher, weil ein ViewChild in ngOnInit nach dem Upgrade auf Angular 8 null war.

Statische Abfragen werden vor ngOnInit gefüllt, während dynamische Abfragen (statisch: false) danach gefüllt werden. Mit anderen Worten, wenn ein Ansichtskind in ngOnInit jetzt null ist, nachdem Sie static: false festgelegt haben, sollten Sie in Betracht ziehen, in static: true zu wechseln oder Code nach ngAfterViewInit zu verschieben.

Siehe https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336

Die anderen Antworten sind korrekt und erklären, warum dies der Fall ist: Abfragen, die von strukturellen Anweisungen abhängen, z. B. eine ViewChild-Referenz in einer ngIf, sollten ausgeführt werden, nachdem die Bedingung dieser Anweisung gelöst wurde, dh nach der Erkennung von Änderungen. Man kann jedoch sicher static: true verwenden und so die Abfragen vor ngOnInit für nicht verschachtelte Referenzen auflösen. Imho dieser spezielle Fall zu erwähnen, als eine Null-Ausnahme könnte wahrscheinlich der erste Weg sein, wie Sie auf diese Besonderheit stoßen, wie es für mich war.

Blumenkrone
quelle
1

View Child @angular 5+ Token zwei Argumente ('lokaler Referenzname', statisch: false | true)

@ViewChild('nameInput', { static: false }) nameInputRef: ElementRef;

Um den Unterschied zwischen wahr und falsch zu erkennen, überprüfen Sie dies

statisch - Gibt an, ob Abfrageergebnisse aufgelöst werden sollen, bevor die Änderungserkennung ausgeführt wird (dh nur statische Ergebnisse zurückgeben). Wenn diese Option nicht bereitgestellt wird, greift der Compiler auf sein Standardverhalten zurück, bei dem Abfrageergebnisse verwendet werden, um den Zeitpunkt der Abfrageauflösung zu bestimmen. Wenn sich Abfrageergebnisse in einer verschachtelten Ansicht befinden (z. B. * ngIf), wird die Abfrage aufgelöst, nachdem die Änderungserkennung ausgeführt wurde. Andernfalls wird es behoben, bevor die Änderungserkennung ausgeführt wird.

Samar Abdallah
quelle
0

In ng8 können Sie manuell festlegen, wann auf die untergeordnete Komponente in der übergeordneten Komponente zugegriffen werden soll. Wenn Sie static auf true setzen, bedeutet dies, dass die übergeordnete Komponente nur die Definition der Komponente im onInitHook erhält : Beispiel:

 // You got a childComponent which has a ngIf/for tag
ngOnInit(){
  console.log(this.childComponent);
}

ngAfterViewInit(){
  console.log(this.childComponent);
}

Wenn static falsch ist, erhalten Sie die Definition nur in ngAfterViewInit (), in ngOnInit () werden Sie undefiniert.

Tethys Zhang
quelle