Acionando a detecção de alterações manualmente no Angular

387

Estou escrevendo um componente Angular que tem uma propriedade Mode(): string.

Eu gostaria de poder definir esta propriedade programaticamente, não em resposta a nenhum evento.

O problema é que, na ausência de um evento do navegador, uma ligação de modelo {{Mode}}não é atualizada.

Existe uma maneira de acionar essa detecção de alteração manualmente?

jz87
fonte

Respostas:

640

Experimente um destes:

  • ApplicationRef.tick()- semelhante ao AngularJS $rootScope.$digest()- ou seja, verifique a árvore de componentes completa
  • NgZone.run(callback)- semelhante a $rootScope.$apply(callback)- ou seja, avalie a função de retorno de chamada dentro da zona Angular. Eu acho, mas não tenho certeza, que isso acaba verificando a árvore de componentes completa após a execução da função de retorno de chamada.
  • ChangeDetectorRef.detectChanges()- semelhante a $scope.$digest()- ou seja, verifique apenas este componente e seus filhos

Você pode injetar ApplicationRef, NgZoneou ChangeDetectorRefno seu componente.

Mark Rajcok
fonte
11
Obrigado, optei pela 3ª solução para não verificar tudo, pois as alterações são bastante localizadas. Devo investigar as outras opções quando tiver mais tempo. Existem implicações de desempenho em cada opção?
jz87
36
+1 para ChangeDetectorRef.detectChanges(). validadores estavam disparando antes que minha diretiva pudesse atualizar o valor de uma entrada.
Ps2goat
7
ApplicationRef.tick () e ChangeDetectorRef.detectChanges () ainda estão presentes na versão 2.0.0 final.
Max Mumford
51
Só pensei em mencionar isso. Estes não são métodos estáticos, são métodos de instância. Você precisará injetar essas classes como serviços.
Stephen Paul
11
ApplicationRef.tick () ajudou a resolver um problema com FireFox v17 (<20)
Dan J
124

Usei a referência de resposta aceita e gostaria de dar um exemplo, como a documentação do Angular 2 é muito difícil de ler, espero que seja mais fácil:

  1. Importar NgZone:

    import { Component, NgZone } from '@angular/core';
    
  2. Adicione-o ao seu construtor de classes

    constructor(public zone: NgZone, ...args){}
    
  3. Execute o código com zone.run:

    this.zone.run(() => this.donations = donations)
    
sites
fonte
6
onde você deve colocar o zone.runcódigo e o que exatamente é donations?
precisa saber é
11
@suku donations é qualquer propriedade que você queira atualizar, portanto pode ser this.foo = bar. O zone.run vai para onde você deseja atualizar as coisas.
Matthew Opcional Meehan
4
Eu usei esta solução para forçar uma actualização de vista quando se utiliza document.addEventListener ( "resumo", chamada de retorno)
marcovtwout
71

Consegui atualizá-lo com markForCheck ()

Importar ChangeDetectorRef

import { ChangeDetectorRef } from '@angular/core';

Injete e instancie

constructor(private ref: ChangeDetectorRef) { 
}

Por fim, marque a detecção de alterações a ser realizada

this.ref.markForCheck();

Aqui está um exemplo em que markForCheck () funciona e detectChanges () não.

https://plnkr.co/edit/RfJwHqEVJcMU9ku9XNE7?p=preview

EDIT: Este exemplo não mostra mais o problema :( Acredito que possa estar executando uma versão Angular mais recente, onde foi corrigida.

(Pressione STOP / RUN para executá-lo novamente)

Nuno Tomas
fonte
Goo point para detectChanges () não está funcionando. Percebi o mesmo problema e descobri que ele funciona se a detecção de alterações não for OnPush. Seria bom obter uma explicação para isso ... #
Christian
2
Parece que o detectChanges está realmente trabalhando neste plunker? Estou esquecendo de algo?
Jared_C
11
Você deve observar que ChangeDetectorRef só funciona em Componentes
kevinius
(!) Este é um mau exemplo, desculpe-me. O exemplo não mostra nada. O primeiro item é substituído. Basta ajustar temporizadores um pouco ...
Peter Stegnar
Este exemplo não retrata o problema mais :( Eu acredito que pode estar executando uma versão mais recente Angular, onde ele é fixo.
Nuno Tomas
7

No Angular 2+, tente o decorador @Input

Ele permite alguma ligação de propriedade interessante entre os componentes pai e filho.

Primeiro, crie uma variável global no pai para armazenar o objeto / propriedade que será passado ao filho.

Em seguida, crie uma variável global no filho para manter o objeto / propriedade transmitida do pai.

Em seguida, no html pai, onde o modelo filho é usado, adicione a notação de colchetes com o nome da variável filho e defina-o igual ao nome da variável pai. Exemplo:

<child-component-template [childVariable] = parentVariable>
</child-component-template>

Por fim, onde a propriedade filho é definida no componente filho, adicione o decorador de Entrada:

@Input()
public childVariable: any

Quando sua variável pai é atualizada, ela deve passar as atualizações para o componente filho, que atualizará seu html.

Além disso, para acionar uma função no componente filho, dê uma olhada em ngOnChanges.

Jeremy Swagger
fonte
2
NO ... isso é o problema ... se você atualizar no pai ... dizer para exmaple é atualizado "por referência" em um método estático a criança não vai buscá-lo como has not detecção de mudanças ocorreu
Bhail
Eu tenho o mesmo problema há dias. Eu tento recuperar dados do back-end do PHP e os dados não são atualizados. No Microsoft Edge funciona bem, mas em outro navegador, não. Recebo os dados comecei a trabalhar no início, mas se altera os dados não são atualizados em vista
el6976
1

ChangeDetectorRef.detectChanges () - semelhante ao $ scope. $ Digest () - ou seja, verifique apenas este componente e seus filhos

Chetann
fonte