J'ai une configuration de composant parent/enfant où le parent charge les données du serveur et les transmet aux enfants via des accessoires. Chez l'enfant, je voudrais instancier un calendrier jQuery avec certaines des données qu'il reçoit du parent.
Afin d'attendre les données avant de configurer le calendrier, je diffuse un événement dans le parent pour lequel j'ai une configuration d'écouteur d'événements pour l'enfant.
L'auditeur est renvoyé chez l'enfant mais si je this.$log('theProp')
, ce n'est pas défini. Cependant, si j'inspecte les composants avec les devtools VueJs, la relation parent/enfant est là et l'enfant a reçu l'accessoire entre-temps.
L'hélice est définie sur l'enfant comme une hélice dynamique :the-prop="theProp"
. Étant donné que l'enfant reçoit l'hélice à la fin, je suppose que ma configuration est correcte, mais il semble y avoir une sorte de retard. Le parent définit les accessoires dans la fonction de retour de l'appel ajax et encore: cela fonctionne, juste avec un léger retard semble-t-il.
J'ai également essayé d'enregistrer un écouteur watch
sur l'accessoire de l'enfant afin que je puisse ensuite configurer le calendrier et être sûr que l'accessoire est là. Cependant, l'écouteur de surveillance se déclenche, mais this.$log('theProp')
n'est toujours pas défini.
Si je transmets les données avec l'appel diffusé, comme this.$broadcast('dataLoaded', theData)
, l'enfant les reçoit très bien. Mais il semble mal de le faire de cette façon, car je construis essentiellement mon propre gestionnaire d'accessoires.
Je ne publie pas de code car les composants sont plutôt volumineux et les devtools VueJs me disent que la situation parent/enfant fonctionne.
Suis-je en manque d'informations? Y a-t-il un léger délai entre la définition d'une valeur dans le parent et l'enfant qui la reçoit? Quelle serait la bonne façon d'attendre les données des parents chez l'enfant?
Normalement, lorsque vous effectuez simplement le rendu des données dans le modèle, le timing n'a pas tellement d'importance car les données sont liées au modèle. Mais dans ce cas, j'ai vraiment besoin des données pour configurer le calendrier, sinon ce sera faux.
Merci.
éditez 1: voici un jsfiddle: https://jsfiddle.net/dr3djo0u/1/ Il semble confirmer que le les données ne sont pas disponibles immédiatement après la diffusion. Cependant, l'observateur fonctionne, même si je pouvais presque jurer que parfois this.$log('someData')
renvoyait undefined
lorsque je configurais ce testcase.
Mais je suppose que mon problème pourrait être ailleurs, j'irai voir ce soir, je n'ai pas le projet avec moi pour le moment.
édition 2: a fait quelques tests supplémentaires. Mon problème était que a) les écouteurs d'événements ne semblaient pas recevoir les données instantanément et b) j'essayais également d'initier le calendrier dans le rappel route.data
Si someData
était déjà là (par exemple en venant du parent), mais ce rappel de route est appelé avant que le composant ne soit prêt, il ne fonctionnait donc pas non plus.
Ma solution est maintenant la suivante:
// works when the child route is loaded directly and parent finishes loading someData
watch: {
someData() {
this.initCalendar();
}
},
// works when navigating from parent (data already loaded)
ready() {
if (this.someData && this.someData.length) {
this.initCalendar()
}
}
Pour autant que je sache, vous ne devriez pas avoir besoin d'événements pour transmettre des données du parent à l'enfant.
Tout ce dont vous avez besoin est, dans le composant enfant: props: ['theProp']
Et lorsque vous utilisez le composant enfant dans le parent: <child :theProp="someData"></child>
Maintenant, où que vous modifiiez someData
dans le parent, le composant enfant réagira en conséquence.
Vous n'avez pas besoin d'événements, vous n'avez pas besoin de "regarder", vous n'avez pas besoin de "prêt".
Par exemple: après un appel AJAX, dans le parent "prêt", vous chargez des données:
// at the parent component
data: function () {
return {
someData: {}
}
},
ready: function () {
var vm = this;
$.get(url, function(response) {
vm.someData = response;
});
}
Maintenant, vous n'avez besoin de rien d'autre pour transmettre les données à l'enfant . Il est déjà chez l'enfant comme theProp
!
Ce que vous devez vraiment faire, c'est avoir, chez l'enfant, quelque chose qui réagit aux changements de données sur sa propre propriété theProp
.
Soit dans l'interface:
<div v-if="theProp.id > 0">
Loaded!
</div>
Ou en code JavaScript:
// at the child component
computed: {
// using a computed property based on theProp's value
awesomeDate: function() {
if (!this.theProp || (this.theProp.length === 0)) {
return false;
}
if (!this.initialized) {
this.initCalendar();
}
return this.theProp.someThing;
}
}
Mise à jour 1
Vous pouvez également, dans le parent, rendre l'enfant sous condition:
<child v-if="dataLoaded" :theProp="someData"></child>
Ne définissez dataLoaded
sur true que lorsque les données sont disponibles.
Mise à jour 2
Ou peut-être que votre problème est lié à un modification de la mise en garde de détection
Peut-être que vous créez une nouvelle propriété dans un objet ...
vm.someObject.someProperty = someValue
... quand tu devrais faire ...
vm.$set('someObject.someProperty', someValue)
... entre autres "mises en garde".
Mise à jour 3
Dans VueJS 2, vous n'êtes pas limité aux modèles. Vous pouvez utiliser une fonction de rend et coder la logique de rendu la plus complexe que vous souhaitez.
Mise à jour 4 (concernant les OP éditez 2 )
Vous pouvez peut-être supprimer ready
et utiliser l'option immediate
, afin que votre initialisation se fasse en un seul endroit:
watch: {
someData: {
handler: function (someData) {
// check someData and eventually call
this.initCalendar();
},
immediate: true
}
}
Dans le composant enfant utilisant simplement les données
props
, pas besoin de réaffecter les valeurs deprops
àdata
, ce sera un bug de mise à jour!