¿Cómo debo usar la nueva opción estática para @ViewChild en Angular 8?

204

¿Cómo debo configurar el nuevo Angular 8 view child?

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

vs

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

¿Cual es mejor? ¿Cuándo debo usar static:truevs static:false?

Patrik Laszlo
fuente

Respuestas:

237

En la mayoría de los casos querrás usar {static: false}. Si se configura de esta manera, se garantizará que se encuentren coincidencias de consulta que dependen de la resolución de enlace (como las directivas estructurales *ngIf, etc...).

Ejemplo de cuándo usar 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;
}

El static: falseva a ser el comportamiento de reserva por defecto en angular 9. Lea más aquí y aquí

La { static: true }opción se introdujo para admitir la creación de vistas integradas sobre la marcha. Cuando crea una vista dinámicamente y desea acceder a ella TemplateRef, no podrá hacerlo, ngAfterViewInitya que provocará un ExpressionHasChangedAfterCheckederror. Establecer el indicador estático en verdadero creará su vista en ngOnInit.

Sin embargo:

En la mayoría de los otros casos, la mejor práctica es usar {static: false}.

Sin embargo, tenga en cuenta que la { static: false }opción se hará predeterminada en Angular 9. Lo que significa que ya no es necesario configurar el indicador estático, a menos que desee utilizar la static: trueopción.

Puede usar el ng updatecomando angular cli para actualizar automáticamente su base de código actual.

Para obtener una guía de migración e incluso más información sobre esto, puede consultar aquí y aquí

¿Cuál es la diferencia entre consultas estáticas y dinámicas?

La opción estática para consultas @ViewChild () y @ContentChild () determina cuándo estarán disponibles los resultados de la consulta.

Con consultas estáticas (static: true), la consulta se resuelve una vez que se ha creado la vista, pero antes de que se ejecute la detección de cambios. Sin embargo, el resultado nunca se actualizará para reflejar los cambios en su vista, como los cambios en los bloques ngIf y ngFor.

Con consultas dinámicas (static: false), la consulta se resuelve después de ngAfterViewInit () o ngAfterContentInit () para @ViewChild () y @ContentChild () respectivamente. El resultado se actualizará para los cambios en su vista, como los cambios en los bloques ngIf y ngFor.

Poul Kruijt
fuente
Actualice
Sachin Gupta
2
No puedo acceder a la instancia de childView. Dice indefinido todo el tiempo.
Nesan Mano
¿Puede proporcionar un enlace sobre esa información para eliminar la opción estática en Angular 9?
Alex Marinov
@AlexMarinov He actualizado mi respuesta para dejar más claro lo que sucederá en el ángulo 9. El enlace sobre esto está en la guía de migración
Poul Kruijt
1
@ MinhNghĩa si anida todo el componente fuera de la plantilla del componente, puede usarlo { static: true }, pero si no hay una necesidad directa de tener acceso al ViewChild en el interior ngOnInit, solo debe usar el { static: false }.
Poul Kruijt
88

Entonces, como regla general, puede optar por lo siguiente:

  • { static: true }debe establecerse cuando se desea acceder al ViewChilden ngOnInit.

  • { static: false } solo se puede acceder en ngAfterViewInit . Esto también es lo que quiere hacer cuando tiene una directiva estructural (es decir *ngIf) en su elemento en su plantilla.

dave0688
fuente
2
Nota: en Angular 9, el indicador estático tiene el valor predeterminado falso, por lo que "cualquier indicador {static: false} se puede eliminar de forma segura". Documentación: angular.io/guide/static-query-migration
Stevethemacguy
17

De los documentos angulares

estática : si se resuelven o no los resultados de la consulta antes de que se ejecute la detección de cambios (es decir, solo se devuelven resultados estáticos). Si no se proporciona esta opción, el compilador recurrirá a su comportamiento predeterminado, que es utilizar los resultados de la consulta para determinar el momento de la resolución de la consulta. Si los resultados de alguna consulta están dentro de una vista anidada (por ejemplo, * ngIf), la consulta se resolverá después de que se ejecute la detección de cambios. De lo contrario, se resolverá antes de que se ejecute la detección de cambios.

Puede ser una mejor idea usar static:truesi el niño no depende de ninguna condición. Si la visibilidad del elemento cambia, static:falsepuede dar mejores resultados.

PD: Dado que es una característica nueva, es posible que debamos ejecutar puntos de referencia para el rendimiento.

Editar

Como lo mencionó @Massimiliano Sartoretto, github commit puede darle más información.

Sachin Gupta
fuente
3
Agregaría
Massimiliano Sartoretto
2

Vine aquí porque un ViewChild era nulo en ngOnInit después de actualizar a Angular 8.

Las consultas estáticas se completan antes de ngOnInit, mientras que las consultas dinámicas (estáticas: falsas) se completan después. En otras palabras, si un viewchild ahora es nulo en ngOnInit después de establecer static: false, debería considerar cambiar a static: true o mover el código a ngAfterViewInit.

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

Las otras respuestas son correctas y explican por qué este es el caso: las consultas que dependen de directivas estructurales, por ejemplo, una referencia ViewChild dentro de un ngIf, deben ejecutarse después de que se haya resuelto el condicional de esta directiva, es decir, después de la detección de cambios. Sin embargo, uno puede usar static: true de forma segura y así resolver las consultas antes de ngOnInit para referencias no verificadas. En mi opinión, este caso en particular se menciona como una excepción nula, probablemente podría ser la primera forma en que se encuentre con esta particularidad, como lo fue para mí.

corola
fuente
1

ver hijo @angular 5+ token dos argumentos ('nombre de referencia local', estático: falso | verdadero)

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

para saber la diferencia entre verdadero y falso verifica esto

estática: si se resuelven o no los resultados de la consulta antes de que se ejecute la detección de cambios (es decir, solo se devuelven resultados estáticos). Si no se proporciona esta opción, el compilador recurrirá a su comportamiento predeterminado, que es utilizar los resultados de la consulta para determinar el momento de la resolución de la consulta. Si los resultados de alguna consulta están dentro de una vista anidada (por ejemplo, * ngIf), la consulta se resolverá después de que se ejecute la detección de cambios. De lo contrario, se resolverá antes de que se ejecute la detección de cambios.

Samar Abdallah
fuente
0

En ng8, puede establecer manualmente cuándo acceder al componente secundario en el componente primario. Cuando establece static en true, significa que el componente principal solo obtiene la definición del componente en el onInitgancho: por ejemplo:

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

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

Si static es falso, solo obtienes la definición en ngAfterViewInit (), en ngOnInit (), obtendrás indefinición.

Tethys Zhang
fuente