working not ngonchanges ngonchange example docheck change angular

not - Detección de cambio Angular2: ngOnChanges no dispara para objeto anidado



ngonchanges angular 4 example (13)

Aquí hay un truco que me sacó de problemas con este.

Entonces, un escenario similar al OP: tengo un componente angular anidado que necesita que se le transmitan datos, 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.

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 salen como HTML en formato tabular. Esto cambia cada vez que rawLapsdata cambia.

Mi componente de map necesita usar ngOnChanges como desencadenante para volver a dibujar marcadores en un mapa de Google. El problema es que ngOnChanges no se dispara cuando rawLapsData cambia 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í un puntero al centro de un gran objeto json

this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;


Como una extensión a la segunda solución de Mark Rajcok

Asigne una nueva matriz a rawLapsData siempre que realice cambios en el contenido de la matriz. Entonces se llamará a ngOnChanges () porque la matriz (referencia) aparecerá como un cambio

puede clonar el contenido de la matriz de esta manera:

rawLapsData = rawLapsData.slice(0);

Estoy mencionando esto porque

rawLapsData = Object.assign ({}, rawLapsData);

No funcionó para mí. Espero que esto ayude.


En Case of Arrays puedes hacerlo así:

En el archivo .ts (componente principal) donde está actualizando su rawLapsData hágalo así:

rawLapsData = somevalue; // change detection will not happen

Solución:

rawLapsData = {...somevalue}; //change detection will happen

y ngOnChanges llamará al componente hijo


He intentado todas las soluciones mencionadas aquí, pero por alguna razón ngOnChanges() todavía no se ngOnChanges() para mí. Entonces lo llamé con this.ngOnChanges() después de llamar al servicio que this.ngOnChanges() mis matrices y funcionó ... ¿correcto? probablemente no. ¿Ordenado? diablos no. ¿Trabajos? ¡sí!


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 ().

import * as _ from ''lodash''; this.foo = _.clone(this.foo);


Me topé con la misma necesidad. Y leí mucho sobre esto, así que aquí está mi cobre sobre el tema.

Si desea que su detección de cambio en la inserción, 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:

<component [collection]="myCollection"></component>

Luego empujaría un elemento y activaría la detección de cambio:

myCollection.push(anItem); refresh();

o eliminaría un elemento y activaría la detección de cambio:

myCollection.splice(0,1); refresh();

o cambiaría un valor de atributo para un artículo y activaría la detección de cambio:

myCollection[5].attribute = ''new value''; refresh();

Contenido de actualización:

refresh() : void { this.myCollection = this.myCollection.slice(); }

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,


Mi solución de ''pirateo'' es

<div class="col-sm-5"> <laps [lapsData]="rawLapsData" [selectedTps]="selectedTps" (lapsHandler)="lapsHandler($event)"> </laps> </div> <map [lapsData]="rawLapsData" [selectedTps]="selectedTps" // <-------- class="col-sm-7"> </map>

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 objeto más simple. NO es elegante, pero funciona.


No es el enfoque más limpio, pero ¿puede clonar el objeto cada vez que cambia el valor?

rawLapsData = Object.assign({}, rawLapsData);

Creo que preferiría este enfoque a implementar su propio ngDoCheck() pero tal vez alguien como @ GünterZöchbauer podría intervenir.


Si los datos provienen de una biblioteca externa, es posible que deba ejecutar la declaración de actualización de datos dentro de zone.run(...) . zone: NgZone para esto. Si ya puede ejecutar la creación de instancias de la biblioteca externa dentro de zone.run() , es posible que no necesite zone.run() más adelante.


Tengo 2 soluciones para resolver tu problema.

  1. Use ngDoCheck para detectar datos de object modificados o no
  2. Asigne object a una nueva dirección de memoria por object = Object.create(object) del componente padre.

Use ChangeDetectorRef.detectChanges() para indicarle a Angular que ejecute una detección de cambios cuando edita un objeto anidado (que se pierde con su comprobación sucia).


ok, entonces mi solución para esto fue:

this.arrayWeNeed.DoWhatWeNeedWithThisArray(); const tempArray = [...arrayWeNeed]; this.arrayWeNeed = []; this.arrayWeNeed = tempArray;

Y esto me dispara ngOnChanges


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. Dado que la referencia de matriz rawLapsData no cambia, no se llamará a ngOnChanges() .

Se me ocurren dos posibles soluciones:

  1. 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 ).

  2. Asigne una nueva matriz a rawLapsData siempre que realice cambios en el contenido de la matriz. Entonces se ngOnChanges() porque la matriz (referencia) aparecerá como un cambio.

En su respuesta, se le ocurrió otra solución.

Repitiendo algunos comentarios aquí sobre el OP:

Todavía no veo cómo las laps pueden captar el cambio (seguramente debe estar usando algo equivalente a ngOnChanges() sí mismo) mientras que el map no puede.

  • En el componente lapsData , su código / plantilla recorre cada entrada de la matriz lapsData y muestra el contenido, por lo que hay enlaces angulares en cada pieza de datos que se muestra.
  • Incluso cuando Angular no detecta ningún cambio en las propiedades de entrada de un componente (usando la 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.
  • El componente de maps probablemente no tiene enlaces en su plantilla a su propiedad de entrada lapsData , ¿verdad? Eso explicaría la diferencia.

Tenga en cuenta que lapsData en ambos componentes y rawLapsData en el componente principal apuntan a la misma / una matriz. Entonces, aunque Angular no nota ningún cambio (de referencia) en las propiedades de entrada lapsData , 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 desencadenaría ngOnChanges() , que 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.