Eu tenho um componente pai ( CategoryComponent ), um componente filho ( videoListComponent ) e um ApiService.
Eu tenho a maior parte deste trabalho bem, ou seja, cada componente pode acessar o json api e obter seus dados relevantes através de observáveis.
Atualmente, o componente da lista de vídeos obtém todos os vídeos. Gostaria de filtrar isso apenas para vídeos em uma categoria específica. Consegui isso passando o categoryId para a criança via @Input()
.
CategoryComponent.html
<video-list *ngIf="category" [categoryId]="category.id"></video-list>
Isso funciona e quando a categoria pai CategoryComponent muda, o valor categoryId é passado através, @Input()
mas preciso detectá-lo no VideoListComponent e solicitar novamente a matriz de vídeos via APIService (com o novo categoryId).
No AngularJS, eu teria feito um $watch
sobre a variável. Qual a melhor forma de lidar com isto?
fonte
Respostas:
Na verdade, existem duas maneiras de detectar e agir quando uma entrada é alterada no componente filho em angular2 +:
Links da documentação: ngOnChanges, SimpleChanges, SimpleChange
Demo Exemplo: Veja este desentupidor
Link da documentação: veja aqui .
Exemplo de demonstração: olhe para este afunilador .
QUE ABORDAGEM DEVE USAR?
Se o seu componente tiver várias entradas, se você usar ngOnChanges (), todas as alterações serão obtidas de todas as entradas de uma vez dentro de ngOnChanges (). Usando essa abordagem, você também pode comparar os valores atuais e anteriores da entrada que foi alterada e executar as ações adequadamente.
No entanto, se você quiser fazer algo quando apenas uma única entrada específica for alterada (e você não se importa com as outras entradas), pode ser mais simples usar um configurador de propriedades de entrada. No entanto, essa abordagem não fornece uma maneira integrada de comparar valores anteriores e atuais da entrada alterada (o que você pode fazer facilmente com o método do ciclo de vida ngOnChanges).
EDIT 2017-07-25: A DETECÇÃO DAS MUDANÇAS ANGULARES PODE AINDA NÃO FOGO SOB ALGUMAS CIRCUNSTÂNCIAS
Normalmente, a detecção de alterações para o setter e ngOnChanges será acionada sempre que o componente pai alterar os dados que passa para o filho, desde que os dados sejam um tipo de dados primitivo JS (string, número, booleano) . No entanto, nos seguintes cenários, ele não será acionado e você precisará executar ações extras para fazê-lo funcionar.
Se você estiver usando um objeto ou matriz aninhada (em vez de um tipo de dados primitivo JS) para passar dados de Pai para Filho, a detecção de alterações (usando o setter ou ngchanges) poderá não ser acionada, como também mencionado na resposta do usuário: muetzerich. Para soluções, veja aqui .
Se você estiver modificando dados fora do contexto angular (ou seja, externamente), o angular não saberá das alterações. Pode ser necessário usar o ChangeDetectorRef ou o NgZone em seu componente para conscientizar angularmente as alterações externas e, assim, acionar a detecção de alterações. Consulte isso .
fonte
doSomething
método e usar 2 argumentos como valores novos e antigos antes de realmente definir o novo valor, de outra maneira seria armazenar o valor antigo antes de definir e chamar o método depois disso.Use o
ngOnChanges()
método do ciclo de vida em seu componente.Aqui estão os documentos .
fonte
MyComponent.myArray = []
, por exemplo , mas se um valor de entrada for alteradoMyComponent.myArray.push(newValue)
, por exemplo ,ngOnChanges()
não é acionado. Alguma idéia de como capturar essa alteração?ngOnChanges()
não é chamado quando um objeto aninhado é alterado. Talvez você encontre uma solução aquiEu estava recebendo erros no console, assim como no compilador e no IDE ao usar o
SimpleChanges
tipo na assinatura da função. Para evitar os erros, use aany
palavra - chave na assinatura.EDITAR:
Como Jon apontou abaixo, você pode usar a
SimpleChanges
assinatura ao usar a notação de colchete em vez da notação de ponto.fonte
SimpleChanges
interface na parte superior do seu arquivo?<my-user-details [user]="selectedUser"></my-user-details>
). Essa propriedade é acessada da classe SimpleChanges chamandochanges.user.currentValue
. Avisouser
está ligada em tempo de execução e não parte do objeto SimpleChangesngOnChanges(changes: {[propName: string]: SimpleChange}) { console.log('onChanges - myProp = ' + changes['myProp'].currentValue); }
A aposta mais segura é usar um serviço compartilhado em vez de um
@Input
parâmetro. Além disso, o@Input
parâmetro não detecta alterações no tipo de objeto aninhado complexo.Um exemplo simples de serviço é o seguinte:
Você pode usar uma implementação semelhante em outros componentes e todos os seus componentes compartilharão os mesmos valores compartilhados.
fonte
@Input
parâmetro @JoshuaKemmerer não detecta alterações no tipo de objeto aninhado complexo, mas em objetos nativos simples.Eu só quero acrescentar que existe outro gancho de ciclo de vida chamado
DoCheck
que é útil se o@Input
valor não for um valor primitivo.Eu tenho uma matriz como uma,
Input
para que isso não acione oOnChanges
evento quando o conteúdo for alterado (porque a verificação feita pelo Angular é 'simples' e não profunda, portanto a matriz ainda é uma matriz, mesmo que o conteúdo da matriz tenha sido alterado).Em seguida, implemento um código de verificação personalizado para decidir se quero atualizar minha exibição com a matriz alterada.
fonte
por favor, tente usar este método. Espero que isto ajude
fonte
Você também pode ter um observável que aciona alterações no componente pai (CategoryComponent) e fazer o que você deseja fazer na assinatura no componente filho. (videoListComponent)
fonte
Aqui o ngOnChanges será acionado sempre que sua propriedade de entrada for alterada:
fonte
Esta solução usa uma classe proxy e oferece as seguintes vantagens:
ngOnChanges()
Exemplo de uso:
Função útil:
fonte
Se você não quiser usar o método ngOnChange implementar o método onChange (), também poderá se inscrever nas alterações de um item específico pelo evento valueChanges , ETC.
});
o markForCheck () escrito por causa do uso nesta declaração:
fonte
Você também pode simplesmente passar um EventEmitter como Input. Não tenho certeza se essa é a melhor prática ...
CategoryComponent.ts:
CategoryComponent.html:
E em VideoListComponent.ts:
fonte