Je sais que je ne suis pas le premier à poser des questions à ce sujet, mais je ne trouve pas de réponse dans les questions précédentes. J'ai ceci dans un composant
<div class="col-sm-5">
<laps
[lapsData]="rawLapsData"
[selectedTps]="selectedTps"
(lapsHandler)="lapsHandler($event)">
</laps>
</div>
<map
[lapsData]="rawLapsData"
class="col-sm-7">
</map>
Dans le contrôleur rawLapsdata
est muté de temps en temps.
Dans laps
, les données sont sorties au format HTML dans un format tabulaire. Cela change chaque fois que cela rawLapsdata
change.
Mon map
composant doit être utilisé ngOnChanges
comme déclencheur pour redessiner des marqueurs sur une carte Google. Le problème est que ngOnChanges ne se déclenche pas lors des rawLapsData
modifications du parent. Que puis-je faire?
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();
}
Mise à jour: ngOnChanges ne fonctionne pas, mais il semble que lapsData soit mis à jour. Dans le ngInit se trouve un écouteur d'événements pour les modifications de zoom qui appelle également this.drawmarkers
. Lorsque je change de zoom, je constate en effet un changement de marqueurs. Le seul problème est que je ne reçois pas la notification au moment où les données d'entrée changent.
Dans le parent, j'ai cette ligne. (Rappelez-vous que le changement se reflète dans les tours, mais pas sur la carte).
this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);
Et notez que this.rawLapsData
c'est lui-même un pointeur vers le milieu d'un grand objet json
this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;
zone.run(...)
devrait le faire alors.ngOnChanges()
ne sera pas appelé. Vous pouvez utiliserngDoCheck()
et implémenter votre propre logique pour déterminer si le contenu du tableau a changé.lapsData
est mis à jour car il a / est une référence au même tableau querawLapsData
.Réponses:
rawLapsData
continue de pointer vers le même tableau, même si vous modifiez le contenu du tableau (par exemple, ajouter des éléments, supprimer des éléments, changer un élément).Pendant la détection de changement, lorsque Angular vérifie les propriétés d'entrée des composants pour le changement, il utilise (essentiellement)
===
pour la vérification sale. Pour les tableaux, cela signifie que les références aux tableaux (uniquement) sont vérifiées. Comme larawLapsData
référence du tableau ne change pas,ngOnChanges()
ne sera pas appelée.Je peux penser à deux solutions possibles:
Implémentez
ngDoCheck()
et exécutez votre propre logique de détection des modifications pour déterminer si le contenu du tableau a changé. (Le document Lifecycle Hooks a un exemple .)Attribuez un nouveau tableau à
rawLapsData
chaque fois que vous apportez des modifications au contenu du tableau. PuisngOnChanges()
sera appelé car le tableau (référence) apparaîtra comme un changement.Dans votre réponse, vous avez proposé une autre solution.
Répétant ici quelques commentaires sur le PO:
laps
composant, votre code / modèle boucle sur chaque entrée dulapsData
tableau et affiche le contenu, de sorte qu'il existe des liaisons angulaires sur chaque élément de données affiché.===
vérification), il vérifie toujours (par défaut) toutes les liaisons de modèle. Lorsque l'un de ces changements change, Angular mettra à jour le DOM. C'est ce que vous voyez.maps
composant n'a probablement aucune liaison dans son modèle avec salapsData
propriété d'entrée, non? Cela expliquerait la différence.Notez que
lapsData
dans les deux composants etrawLapsData
dans le composant parent, tous pointent vers le même / un tableau. Ainsi, même si Angular ne remarque aucun changement (de référence) dans leslapsData
propriétés d'entrée, les composants "obtiennent" / voient tout changement de contenu du tableau parce qu'ils partagent / référencent tous ce tableau. Nous n'avons pas besoin d'Angular pour propager ces changements, comme nous le ferions avec un type primitif (chaîne, nombre, booléen). Mais avec un type primitif, toute modification de la valeur se déclencherait toujoursngOnChanges()
- ce que vous exploitez dans votre réponse / solution.Comme vous l'avez probablement compris maintenant, les propriétés d'entrée d'objet ont le même comportement que les propriétés d'entrée de tableau.
la source
Ce n'est pas l'approche la plus propre, mais vous pouvez simplement cloner l'objet à chaque fois que vous modifiez la valeur?
Je pense que je préférerais cette approche à la mise en œuvre de la vôtre,
ngDoCheck()
mais peut-être que quelqu'un comme @ GünterZöchbauer pourrait intervenir.la source
Dans le cas de tableaux, vous pouvez le faire comme ceci:
Dans le
.ts
fichier (composant parent) où vous mettez à jour,rawLapsData
procédez comme suit:Solution:
et
ngOnChanges
sera appelé dans le composant enfantla source
En tant qu'extension de la deuxième solution de Mark Rajcok
vous pouvez cloner le contenu du tableau comme ceci:
Je mentionne cela parce que
n'a pas fonctionné pour moi. J'espère que ça aide.
la source
Si les données proviennent d'une bibliothèque externe, vous devrez peut-être exécuter l'instruction de mise à jour des données dans
zone.run(...)
. Injectezzone: NgZone
pour cela. Si vous pouvez déjà exécuter l'instanciation de la bibliothèque externezone.run()
, vous n'en aurez peut-être pas besoinzone.run()
plus tard.la source
$scope.$apply
?zone.run
est similaire à$scope.apply
.Utilisez
ChangeDetectorRef.detectChanges()
pour dire à Angular d'exécuter une détection de changement lorsque vous modifiez un objet imbriqué (qu'il manque avec sa vérification sale).la source
J'ai 2 solutions pour résoudre votre problème
ngDoCheck
pour détecter lesobject
données modifiées ou nonobject
à une nouvelle adresse mémoire àobject = Object.create(object)
partir du composant parent.la source
Ma solution de 'hack' est
selectedTps change en même temps que rawLapsData et cela donne à la carte une autre chance de détecter le changement grâce à un type primitif d'
objetplus simple . Ce n'est PAS élégant, mais cela fonctionne.la source
La détection des modifications n'est pas déclenchée lorsque vous modifiez une propriété d'un objet (y compris un objet imbriqué). Une solution serait de réaffecter une nouvelle référence d'objet en utilisant la fonction clone () 'lodash'.
la source
Voici un hack qui vient de me sortir des ennuis avec celui-ci.
Donc, un scénario similaire à l'OP - j'ai un composant angulaire imbriqué qui a besoin de données qui lui sont transmises, mais l'entrée pointe vers un tableau, et comme mentionné ci-dessus, Angular ne voit pas de changement car il n'examine pas le contenu du tableau.
Donc, pour le réparer, je convertis le tableau en une chaîne pour qu'Angular détecte un changement, puis dans le composant imbriqué, j'ai divisé (',') la chaîne en un tableau et ses jours heureux à nouveau.
la source
Je suis tombé sur le même besoin. Et j'ai beaucoup lu à ce sujet, voici donc mon cuivre sur le sujet.
Si vous voulez votre détection de changement sur push, alors vous l'auriez lorsque vous modifiez la valeur d'un objet à l'intérieur, n'est-ce pas? Et vous l'auriez également si, d'une manière ou d'une autre, vous supprimiez des objets.
Comme déjà dit, l'utilisation de changeDetectionStrategy.onPush
Supposons que vous ayez ce composant que vous avez créé, avec changeDetectionStrategy.onPush:
Ensuite, vous poussez un élément et déclenchez la détection de changement:
ou vous supprimez un élément et déclenchez la détection des modifications:
ou vous modifiez une valeur attrbibute pour un élément et déclenchez la détection de changement:
Contenu de rafraîchissement:
La méthode slice renvoie exactement le même tableau et le signe [=] y fait une nouvelle référence, déclenchant la détection de changement chaque fois que vous en avez besoin. Facile et lisible :)
Cordialement,
la source
J'ai essayé toutes les solutions mentionnées ici, mais pour une raison quelconque,
ngOnChanges()
je n'ai toujours pas tiré pour moi. Donc je l'ai appeléthis.ngOnChanges()
après avoir appelé le service qui repeuple mes tableaux et cela a fonctionné .... correct? probablement pas. Soigné? sûrement pas. Travaux? Oui!la source
ok donc ma solution était:
Et cela me déclenche ngOnChanges
la source
J'ai dû créer un hack pour cela -
la source
Dans mon cas, c'était des changements de valeur d'objet qui
ngOnChange
ne capturaient pas. Quelques valeurs d'objet sont modifiées en réponse à l'appel de l'API. La réinitialisation de l'objet a résolu le problème et provoqué lengOnChange
déclenchement du dans le composant enfant.Quelque chose comme
la source