Como devo usar a nova opção estática para o @ViewChild no Angular 8?

204

Como devo configurar o novo filho da visualização Angular 8?

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

vs

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

Qual é melhor? Quando devo usar static:truevs static:false?

Patrik Laszlo
fonte

Respostas:

237

Na maioria dos casos, você vai querer usar {static: false}. A configuração dessa maneira garantirá que sejam encontradas correspondências de consulta dependentes da resolução de ligação (como diretivas estruturais *ngIf, etc...).

Exemplo de quando 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;
}

O static: falseque vai ser o comportamento fallback padrão no Angular 9. Leia mais aqui e aqui

o { static: true } opção foi introduzida para oferecer suporte à criação de visualizações incorporadas em tempo real. Quando você cria uma visualização dinamicamente e deseja acessar TemplateRef, não poderá fazer isso, ngAfterViewInitpois isso causará um ExpressionHasChangedAfterCheckederro. Definir o sinalizador estático como true criará sua visualização no ngOnInit.

Mesmo assim:

Na maioria dos outros casos, a melhor prática é usar {static: false} .

Esteja ciente de que o { static: false } opção será padronizada no Angular 9. O que significa que a configuração do sinalizador estático não é mais necessária, a menos que você queira usar a static: trueopção.

Você pode usar o ng updatecomando angular cli para atualizar automaticamente sua base de código atual.

Para um guia de migração e ainda mais informações sobre isso, você pode conferir aqui e aqui

Qual é a diferença entre consultas estáticas e dinâmicas?

A opção estática para as consultas @ViewChild () e @ContentChild () determina quando os resultados da consulta ficam disponíveis.

Com consultas estáticas (static: true), a consulta é resolvida assim que a exibição é criada, mas antes da execução da detecção de alterações. O resultado, no entanto, nunca será atualizado para refletir alterações na sua exibição, como alterações nos blocos ngIf e ngFor.

Com consultas dinâmicas (static: false), a consulta é resolvida após ngAfterViewInit () ou ngAfterContentInit () para @ViewChild () e @ContentChild (), respectivamente. O resultado será atualizado para alterações em sua visualização, como alterações nos blocos ngIf e ngFor.

Poul Kruijt
fonte
Atualize o link para os documentos angulares (alterados após o lançamento) angular.io/api/core/ViewChild#description
Sachin Gupta
2
Não consigo acessar a instância do childView. Diz indefinido o tempo todo.
Nesan Mano
Você pode fornecer um link sobre essas informações para remover a opção estática no Angular 9?
Alex Marinov
@AlexMarinov Atualizei minha resposta para deixar mais claro o que vai acontecer no angular 9. O link sobre isso está no guia de migração
Poul Kruijt 4/19
1
@ MinhNghĩa se você aninhar todo o componente fora do modelo do componente, poderá usá-lo { static: true }, mas se não houver necessidade direta de ter acesso ao ViewChild dentro ngOnInit, basta usar o { static: false }.
Poul Kruijt 21/10/19
88

Portanto, como regra geral, você pode fazer o seguinte:

  • { static: true }precisa ser definido quando você quiser acessar o ViewChildno ngOnInit.

  • { static: false }só pode ser acessado em ngAfterViewInit. Também é isso que você deseja buscar quando tiver uma diretiva estrutural (ou seja *ngIf) em seu elemento no seu modelo.

dave0688
fonte
2
Nota: No Angular 9, o sinalizador estático é padronizado como false, para que "qualquer sinalizador {static: false} possa ser removido com segurança". Documentação: angular.io/guide/static-query-migration
Stevethemacguy
17

Dos documentos angulares

static - se deve ou não resolver os resultados da consulta antes da execução da detecção de alterações (por exemplo, retornar apenas resultados estáticos). Se essa opção não for fornecida, o compilador retornará ao seu comportamento padrão, que é usar os resultados da consulta para determinar o tempo da resolução da consulta. Se algum resultado da consulta estiver dentro de uma visualização aninhada (por exemplo, * ngIf), a consulta será resolvida após a execução da detecção de alterações. Caso contrário, ele será resolvido antes da execução da detecção de alterações.

Pode ser uma idéia melhor usar static:truese a criança não depender de nenhuma condição. Se a visibilidade do elemento mudar, static:falsepoderá gerar melhores resultados.

PS: Como é um novo recurso, podemos precisar executar benchmarks para obter desempenho.

Editar

Conforme mencionado por @Massimiliano Sartoretto, o github commit pode fornecer mais informações.

Sachin Gupta
fonte
3
Eu adicionaria as motivações oficiais por trás desse recurso github.com/angular/angular/pull/28810
Massimiliano Sartoretto
2

Veio aqui porque um ViewChild era nulo no ngOnInit após a atualização para o Angular 8.

As consultas estáticas são preenchidas antes do ngOnInit, enquanto as consultas dinâmicas (static: false) são preenchidas depois. Em outras palavras, se um viewchild agora for nulo no ngOnInit depois de definir static: false, considere alterar para static: true ou mova o código para ngAfterViewInit.

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

As outras respostas estão corretas e explicam por que esse é o caso: As consultas dependentes de diretivas estruturais, por exemplo, uma referência do ViewChild dentro de um ngIf, devem ser executadas após a resolução do condicional desta diretiva, ou seja, após a detecção de alterações. No entanto, pode-se usar com segurança static: true e, assim, resolver as consultas antes de ngOnInit para referências não aninhadas. No entanto, nesse caso em particular, mencionar como uma exceção nula provavelmente pode ser a primeira maneira de você encontrar essa particularidade, como foi para mim.

corola
fonte
1

view child @angular 5+ token dois argumentos ('local reference name', static: false | true)

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

para saber a diferença entre verdadeiro e falso, verifique esta

static - se deve ou não resolver os resultados da consulta antes da execução da detecção de alterações (por exemplo, retornar apenas resultados estáticos). Se essa opção não for fornecida, o compilador retornará ao seu comportamento padrão, que é usar os resultados da consulta para determinar o tempo da resolução da consulta. Se algum resultado da consulta estiver dentro de uma visualização aninhada (por exemplo, * ngIf), a consulta será resolvida após a execução da detecção de alterações. Caso contrário, ele será resolvido antes da execução da detecção de alterações.

Samar Abdallah
fonte
0

No ng8, você pode definir manualmente quando acessar o componente filho no componente pai. Quando você define static como true, significa que o componente pai obtém apenas a definição do componente no onInitgancho: Por exemplo:

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

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

Se estático for falso, você só obtém a definição em ngAfterViewInit (), em ngOnInit (), ficará indefinido.

Tethys Zhang
fonte