Sei que não sou o primeiro a perguntar sobre isso, mas não consigo encontrar uma resposta nas perguntas anteriores. Eu tenho isso em um componente
<div class="col-sm-5">
<laps
[lapsData]="rawLapsData"
[selectedTps]="selectedTps"
(lapsHandler)="lapsHandler($event)">
</laps>
</div>
<map
[lapsData]="rawLapsData"
class="col-sm-7">
</map>
No controlador rawLapsdata
é alterado de tempos em tempos.
Em laps
, os dados são enviados como HTML em um formato tabular. Isso muda sempre que rawLapsdata
muda.
Meu map
componente precisa usar ngOnChanges
como gatilho para redesenhar marcadores em um mapa do Google. O problema é que o ngOnChanges não é acionado quando as rawLapsData
alterações no pai. O que eu posso fazer?
import {Component, Input, OnInit, OnChanges, SimpleChange} from 'angular2/core';
@Component({
selector: 'map',
templateUrl: './components/edMap/edMap.html',
styleUrls: ['./components/edMap/edMap.css']
})
export class MapCmp implements OnInit, OnChanges {
@Input() lapsData: any;
map: google.maps.Map;
ngOnInit() {
...
}
ngOnChanges(changes: { [propName: string]: SimpleChange }) {
console.log('ngOnChanges = ', changes['lapsData']);
if (this.map) this.drawMarkers();
}
Atualização: ngOnChanges não está funcionando, mas parece que lapsData está sendo atualizado. No ngInit, há um ouvinte de eventos para alterações de zoom que também chama this.drawmarkers
. Quando mudo o zoom, vejo de fato uma mudança nos marcadores. Portanto, o único problema é que não recebo a notificação no momento em que os dados de entrada são alterados.
No pai, eu tenho essa linha. (Lembre-se de que a mudança é refletida em voltas, mas não no mapa).
this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);
E observe que this.rawLapsData
ele próprio é um ponteiro para o meio de um objeto json grande
this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;
zone.run(...)
deve fazê-lo então.ngOnChanges()
não será chamada. Você pode usarngDoCheck()
e implementar sua própria lógica para determinar se o conteúdo da matriz foi alterado.lapsData
é atualizado porque possui / é uma referência à mesma matriz querawLapsData
.Respostas:
rawLapsData
continua a apontar para a mesma matriz, mesmo se você modificar o conteúdo da matriz (por exemplo, adicionar itens, remover itens, alterar um item).Durante a detecção de alterações, quando o Angular verifica as propriedades de entrada dos componentes em busca de alterações, ele usa (essencialmente)
===
uma verificação suja. Para matrizes, isso significa que as referências da matriz (apenas) estão marcadas suja. Como arawLapsData
referência da matriz não está mudando,ngOnChanges()
não será chamada.Posso pensar em duas soluções possíveis:
Implemente
ngDoCheck()
e execute sua própria lógica de detecção de alterações para determinar se o conteúdo da matriz foi alterado. (O documento Ganchos do ciclo de vida tem um exemplo .)Atribua uma nova matriz
rawLapsData
sempre que fizer alterações no conteúdo da matriz. Em seguidangOnChanges()
, será chamado porque o array (referência) aparecerá como uma alteração.Na sua resposta, você encontrou outra solução.
Repetindo alguns comentários aqui no OP:
laps
componente, seu código / modelo faz um loop sobre cada entrada nalapsData
matriz e exibe o conteúdo, para que haja ligações Angulares em cada parte dos dados que são exibidos.===
verificação), ele continua (por padrão) sujo verifica todas as ligações do modelo. Quando alguma dessas alterações for alterada, o Angular atualizará o DOM. É isso que você está vendo.maps
componente provavelmente não possui nenhuma ligação em seu modelo para sualapsData
propriedade de entrada, certo? Isso explicaria a diferença.Observe que,
lapsData
nos dois componentes erawLapsData
no componente pai, todos apontam para a mesma / uma matriz. Portanto, mesmo que o Angular não observe nenhuma alteração (de referência) naslapsData
propriedades de entrada, os componentes "obtêm" / veem qualquer alteração no conteúdo da matriz porque todos compartilham / referenciam essa matriz. Não precisamos do Angular para propagar essas alterações, como faria com um tipo primitivo (string, número, booleano). Mas com um tipo primitivo, qualquer alteração no valor sempre acionariangOnChanges()
- o que é algo que você explora em sua resposta / solução.Como você provavelmente já descobriu, as propriedades de entrada do objeto têm o mesmo comportamento das propriedades de entrada da matriz.
fonte
Não é a abordagem mais limpa, mas você pode clonar o objeto sempre que alterar o valor?
Acho que prefiro essa abordagem ao
ngDoCheck()
invés de implementar a sua própria, mas talvez alguém como a @ GünterZöchbauer possa entrar na conversa.fonte
No caso de matrizes, você pode fazer assim:
No
.ts
arquivo (componente pai) em que você está atualizando,rawLapsData
faça o seguinte:Solução:
e
ngOnChanges
será chamado no componente filhofonte
Como uma extensão da segunda solução de Mark Rajcok
você pode clonar o conteúdo da matriz assim:
Eu estou mencionando isso porque
não funcionou para mim. Eu espero que isso ajude.
fonte
Se os dados vierem de uma biblioteca externa, pode ser necessário executar a instrução upate de dados dentro
zone.run(...)
. Injetezone: NgZone
para isso. Se você já pode executar a instanciação da biblioteca externazone.run()
, talvez não seja necessáriozone.run()
mais tarde.fonte
$scope.$apply
?zone.run
é semelhante a$scope.apply
.Use
ChangeDetectorRef.detectChanges()
para informar ao Angular para executar uma detecção de alterações ao editar um objeto aninhado (que está ausente na verificação suja).fonte
Tenho 2 soluções para resolver seu problema
ngDoCheck
para detectarobject
dados alterados ou nãoobject
a um novo endereço de memóriaobject = Object.create(object)
do componente pai.fonte
Minha solução 'hack' é
selectedTps muda ao mesmo tempo que rawLapsData e isso dá ao mapa outra chance de detectar a alteração por meio de um tipo primitivo de
objetomais simples . NÃO é elegante, mas funciona.fonte
A detecção de alterações não é acionada quando você altera uma propriedade de um objeto (incluindo objeto aninhado). Uma solução seria reatribuir uma nova referência de objeto usando a função 'lodash' clone ().
fonte
Aqui está um truque que me tirou de problemas com este.
Portanto, um cenário semelhante ao OP - eu tenho um componente Angular aninhado que precisa de dados passados para ele, mas a entrada aponta para uma matriz e, como mencionado acima, o Angular não vê uma alteração, pois não examina o conteúdo da matriz.
Portanto, para corrigi-lo, converto a matriz em uma sequência para que o Angular detecte uma alteração e, no componente aninhado, divido (',') a sequência novamente em uma matriz e nos seus dias felizes novamente.
fonte
Eu me deparei com a mesma necessidade. E eu li muito sobre isso, aqui está o meu cobre sobre o assunto.
Se você deseja a detecção de alterações por push, você a teria quando alterar o valor de um objeto dentro, certo? E você também o teria se, de alguma forma, remover objetos.
Como já foi dito, o uso de changeDetectionStrategy.onPush
Digamos que você tenha esse componente criado com changeDetectionStrategy.onPush:
Em seguida, você pressiona um item e aciona a detecção de alterações:
ou você removeria um item e acionaria a detecção de alterações:
ou você alteraria um valor de atributo para um item e acionaria a detecção de alterações:
Conteúdo da atualização:
O método de fatia retorna exatamente a mesma matriz e o sinal [=] faz uma nova referência a ela, acionando a detecção de alterações sempre que você precisar. Fácil e legível :)
Saudações,
fonte
Eu tentei todas as soluções mencionadas aqui, mas por algum motivo
ngOnChanges()
ainda não disparou para mim. Então eu ligueithis.ngOnChanges()
depois de chamar o serviço que repovoa minhas matrizes e funcionou .... correto? provavelmente não. Arrumado? de jeito nenhum. Trabalho? sim!fonte
ok, então minha solução para isso foi:
E isso me desencadeou ngOnChanges
fonte
Eu tive que criar um hack para isso -
fonte
No meu caso, foram as alterações no valor do objeto que o
ngOnChange
não estava capturando. Alguns valores de objeto são modificados em resposta à chamada da API. A reinicialização do objeto corrigiu o problema e causou ongOnChange
acionamento no componente filho.Algo como
fonte