Sé que no soy el primero en preguntar sobre esto, pero no puedo encontrar una respuesta en las preguntas anteriores. Tengo esto en un componente
<div class="col-sm-5">
<laps
[lapsData]="rawLapsData"
[selectedTps]="selectedTps"
(lapsHandler)="lapsHandler($event)">
</laps>
</div>
<map
[lapsData]="rawLapsData"
class="col-sm-7">
</map>
En el controlador rawLapsdata
se muta de vez en cuando.
En laps
, los datos se generan como HTML en formato tabular. Esto cambia cada vez que rawLapsdata
cambia.
Mi map
componente debe usarse ngOnChanges
como desencadenante para volver a dibujar marcadores en un mapa de Google. El problema es que ngOnChanges no se dispara cuando hay rawLapsData
cambios en el padre. ¿Que puedo hacer?
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();
}
Actualización: ngOnChanges no funciona, pero parece que lapsData se está actualizando. En el ngInit es un detector de eventos para cambios de zoom que también llama this.drawmarkers
. Cuando cambio el zoom, sí veo un cambio en los marcadores. Entonces, el único problema es que no recibo la notificación en el momento en que cambian los datos de entrada.
En el padre, tengo esta línea. (Recuerde que el cambio se refleja en vueltas, pero no en el mapa).
this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);
Y tenga en cuenta que this.rawLapsData
es en sí mismo un puntero al centro de un gran objeto json
this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;
zone.run(...)
debería hacerlo entonces.ngOnChanges()
lo que no se llamará. Puede usarngDoCheck()
e implementar su propia lógica para determinar si el contenido de la matriz ha cambiado.lapsData
se actualiza porque tiene / es una referencia a la misma matriz querawLapsData
.Respuestas:
rawLapsData
continúa apuntando a la misma matriz, incluso si modifica el contenido de la matriz (por ejemplo, agregar elementos, eliminar elementos, cambiar un elemento).Durante la detección de cambios, cuando Angular verifica las propiedades de entrada de los componentes para detectar cambios, utiliza (esencialmente)
===
para la verificación sucia. Para las matrices, esto significa que las referencias de la matriz (solo) están sucias. Como larawLapsData
referencia de matriz no está cambiando,ngOnChanges()
no se llamará.Se me ocurren dos posibles soluciones:
Implemente
ngDoCheck()
y realice su propia lógica de detección de cambios para determinar si el contenido de la matriz ha cambiado. (El documento Lifecycle Hooks tiene un ejemplo ).Asigne una nueva matriz
rawLapsData
cada vez que realice cambios en el contenido de la matriz. LuegongOnChanges()
se llamará porque la matriz (referencia) aparecerá como un cambio.En su respuesta, se le ocurrió otra solución.
Repitiendo algunos comentarios aquí sobre el OP:
laps
componente, su código / plantilla recorre cada entrada de lalapsData
matriz y muestra el contenido, por lo que hay enlaces angulares en cada pieza de datos que se muestra.===
comprobación), todavía (por defecto) comprueba suciamente todos los enlaces de plantilla. Cuando alguno de esos cambios, Angular actualizará el DOM. Eso es lo que estás viendo.maps
componente probablemente no tiene enlaces en su plantilla a sulapsData
propiedad de entrada, ¿verdad? Eso explicaría la diferencia.Tenga
lapsData
en cuenta que en ambos componentes yrawLapsData
en el componente principal todos apuntan a la misma / una matriz. Entonces, aunque Angular no nota ningún cambio (de referencia) en laslapsData
propiedades de entrada, los componentes "obtienen" / ven cualquier cambio en el contenido de la matriz porque todos comparten / hacen referencia a esa matriz. No necesitamos Angular para propagar estos cambios, como lo haríamos con un tipo primitivo (cadena, número, booleano). Pero con un tipo primitivo, cualquier cambio en el valor siempre se activaríangOnChanges()
, lo cual es algo que explota en su respuesta / solución.Como probablemente haya descubierto ahora, las propiedades de entrada de objeto tienen el mismo comportamiento que las propiedades de entrada de matriz.
fuente
No es el enfoque más limpio, pero ¿puede clonar el objeto cada vez que cambia el valor?
Creo que preferiría este enfoque en lugar de implementar el suyo,
ngDoCheck()
pero tal vez alguien como @ GünterZöchbauer podría intervenir.fuente
En Case of Arrays puedes hacerlo así:
En el
.ts
archivo (componente principal) donde está actualizando,rawLapsData
hágalo así:Solución:
y
ngOnChanges
llamará en el componente hijofuente
Como una extensión a la segunda solución de Mark Rajcok
puede clonar el contenido de la matriz de esta manera:
Estoy mencionando esto porque
no funciono para mi Espero que esto ayude.
fuente
Si los datos provienen de una biblioteca externa, es posible que deba ejecutar la declaración de actualización de datos dentro
zone.run(...)
. Inyectarzone: NgZone
para esto. Si ya puede ejecutar la creación de instancias de la biblioteca externazone.run()
, es posible que no necesitezone.run()
más tarde.fuente
$scope.$apply
?zone.run
es similar al$scope.apply
.Use
ChangeDetectorRef.detectChanges()
para decirle a Angular que ejecute una detección de cambios cuando edita un objeto anidado (que se pierde con su verificación sucia).fuente
Tengo 2 soluciones para resolver tu problema.
ngDoCheck
para detectarobject
datos modificados o noobject
a una nueva dirección de memoria por parteobject = Object.create(object)
del componente principal.fuente
Mi solución de 'pirateo' es
selectedTps cambia al mismo tiempo que rawLapsData y eso le da al mapa otra oportunidad de detectar el cambio a través de un tipo primitivo de
objetomás simple . NO es elegante, pero funciona.fuente
La detección de cambios no se activa cuando cambia una propiedad de un objeto (incluido el objeto anidado). Una solución sería reasignar una nueva referencia de objeto usando la función 'lodash' clone ().
fuente
Aquí hay un truco que me sacó de problemas con este.
Entonces, un escenario similar al OP: tengo un componente angular anidado que necesita datos transmitidos, pero la entrada apunta a una matriz y, como se mencionó anteriormente, Angular no ve un cambio ya que no examina el contenido de la matriz.
Entonces, para solucionarlo, convierto la matriz en una cadena para que Angular detecte un cambio, y luego, en el componente anidado, dividí (',') la cadena en una matriz y sus días felices nuevamente.
fuente
Me topé con la misma necesidad. Y leí mucho sobre esto, así que aquí está mi cobre sobre el tema.
Si desea su detección de cambio en el momento, entonces la tendría cuando cambie el valor de un objeto dentro de la derecha? Y también lo tendría si de alguna manera, elimina objetos.
Como ya se dijo, el uso de changeDetectionStrategy.onPush
Digamos que tiene este componente que creó, con changeDetectionStrategy.onPush:
Luego empujaría un elemento y activaría la detección de cambio:
o eliminaría un elemento y activaría la detección de cambio:
o cambiaría un valor de atributo para un artículo y activaría la detección de cambio:
Contenido de actualización:
El método de división devuelve exactamente la misma matriz, y el signo [=] le hace una nueva referencia, activando la detección de cambios cada vez que lo necesite. Fácil y legible :)
Saludos,
fuente
He intentado todas las soluciones mencionadas aquí, pero por alguna razón
ngOnChanges()
todavía no me ha funcionado. Entonces lo llaméthis.ngOnChanges()
después de llamar al servicio que repobla mis matrices y funcionó ... ¿correcto? Probablemente no. ¿Ordenado? diablos no. ¿Trabajos? ¡si!fuente
ok, entonces mi solución para esto fue:
Y esto me dispara ngOnChanges
fuente
Tuve que crear un truco para ello.
fuente
En mi caso, fueron los cambios en el valor del objeto lo que
ngOnChange
no estaba capturando. Algunos valores de objeto se modifican en respuesta a una llamada api. Reinicializar el objeto solucionó el problema y provocóngOnChange
que se activara en el componente secundario.Algo como
fuente