Je suis coincé depuis quelques semaines dans un problème de rendu des données avec VueJS.
Ce que je fais, c'est faire des appels axios (l'un dans l'autre). Mon problème est que les données sont rendues avant que les appels ne soient terminés, donc la vue ne montre rien.
J'ai vu des codes qui font des "appels en attente" et des "appels asynchrones" mais rien ne semble résoudre mon problème.
Il y a aussi quelque chose de similaire ici Demander au composant d'attendre les données asynchrones avant le rendu Mais ne fonctionne pas non plus
voici mon code:
<template> <div class="m-portlet m-portlet--full-height" m-portlet="true" id="m_portlet_validate_agenda"> ... <div class="m-portlet__body"> <div class="tab-content"> <div class="tab-pane active" id="m_widget2_tab1_diagnose"> <div class="m-widget2"> <div v-for="diagnose in diagnoses" v-if="diagnoses.length" :class="'m-widget2__item m-widget2__item--' + diagnose.delayColor[0]"> <div class="m-widget2__checkbox" > <label class="m-checkbox m-checkbox--solid m-checkbox--single m-checkbox--brand"> <span class="m--bg-white" v-html="diagnose.concurrence"></span> </label> </div> <div class="m-widget2__agenda col-2"> {{ diagnose.started_at | moment("HH:mm A") }} </div> <div class="m-widget2__desc" v-if="!isFetching"> <div> <span class="m-widget2__text"> </span><br> <span class="m-widget2__user-name"> <a href="#" class="m-widget2__link m-link"> Paciente: {{ diagnose.details[0].name }} </a><br> <a href="#" class="m-widget2__link m-link"> Tratante: </a> </span> </div> </div> </div> </div> </div> </div> </div> </div> </template> <script> export default { data() { return { events: [], diagnoses: [], urgencies: [], treatments: [], isFetching: true } }, mounted() { this.loadData(); }, methods: { loadData: async function() { await axios.get('/pacientes/request-json/agenda/validarAsistencia/eventos').then(res => { this.events = res.data; this.diagnoses = []; this.urgencies = []; this.treatments = []; this.getDetails(); this.getDelayColor(); this.getConcurrence(); vm.$nextTick(function () { $('[data-toggle="m-tooltip"]').tooltip(); }); console.log('end LoadData'); }); }, getDetails: function() { console.log('cargando'); this.events.forEach(event => { axios.get('/pacientes/request-json/agenda/validarAsistencia/eventos/' + event.id).then(res => { event.details = res.data; console.log(res.data); }); }); this.distributeEvents(); console.log('montado'); }, distributeEvents: function() { this.events.forEach(event => { if ( event.event.event_type == "diagnosis" ) { this.diagnoses.push(event); } else if ( event.event.event_type == "urgency" ) { this.urgencies.push(event); } else if ( event.event.event_type == "treatment" ) { this.treatments.push(event); } }); this.isFetching = false; }, getDelayColor: function() { this.events.forEach(event => { do something... }); }, getConcurrence: function() { this.events.forEach(event => { do something... }); }, diffMinutes: function(started_at) { do something... } } }
3 Réponses :
Pour empêcher le composant de s'afficher avant que les données ne soient renvoyées, vous pouvez:
ajoutez une propriété "isFetching" aux données et définissez-la sur "true"
dans le rappel de récupération, définissez isFetching sur "false"
3. ajoutez v-if = "! isFetching" au wrapper du composant
Dois-je avoir besoin d'implémenter un observateur également
non, la propriété "isFetching" est dans l'objet 'data', ce qui signifie que la vue le surveille pour nous, et mettra à jour le composant automatiquement une fois modifié. aucune montre nécessaire.
Cela ne semble pas fonctionner non plus ... [Vue warn]: Erreur de rendu: "TypeError: diagnose.details est indéfini"
Déplacez le 'v-if = "! IsFetching"' vers le wrapper, le premier div du composant. Ou du moins pour encapsuler l'accès à la variable dans le modèle
La solution:
Merci les gars!
loadData: function() { axios.get('/pacientes/request-json/agenda/validarAsistencia/eventos') .then(res => { this.events = res.data; this.getDelayColor() // sync operation; no need to be returned this.getConcurrence(); vm.$nextTick(function () { $('[data-toggle="m-tooltip"]').tooltip(); }); return this.getDetails(); // Return the promise(s) }) .then((res) => { console.log(res.length); for (var i = 0; i < res.length; i++) { this.events[i].details = res[i].data; } this.distributeEvents(); console.log('end LoadData'); }) .catch(error => { console.log('error'); }) }, getDetails: function() { let url = '/pacientes/request-json/agenda/validarAsistencia/eventos/'; let promisedEvents = []; this.events.forEach(event => { promisedEvents.push(axios.get(url + event.id)) }); return Promise.all(promisedEvents) },
Vous ne gérez pas correctement les promesses, elles continuent donc à être non résolues . Vous pouvez utiliser async
, await
, bien que je préfère utiliser Promise Objects :
getDetails ()
est une autre histoire. Vous créez une boucle, et forEach
boucle vous envoyez une requête axios . Vous devrez peut-être stocker chaque Promise renvoyée par chaque appel axios dans un tableau, puis appeler Promise.all .
loadData: function() { axios.get('/pacientes/request-json/agenda/validarAsistencia/eventos') .then(res => { this.events = res.data; this.getDelayColor() // sync operation; no need to be returned return this.getDetails(); // Return the promise(s) }) .then((res) => { // do something with the response from your array of Promises }) .then(anotherPromise) // You can also return a promise like this .catch(handleError) // Very important to handle your error!! }); },
Après cela, je ferais quelque chose comme ceci:
getDetails: function() { let url = '/pacientes/request-json/agenda/validarAsistencia/eventos/'; console.log('loading'); let promisedEvents = []; this.events.forEach(event => { promisedEvents.push(axios.get(url + event.id)) }); return Promise.all(promisedEvents) },
Je ne dis pas que c'est la meilleure façon de réaliser ce que vous voulez, mais que c'est une façon de faire fonctionner votre code. Il est important ici de vous renseigner sur les promesses.
Merci je vais essayer ça, je vais aussi lire quelque chose sur les promesses
Faites-moi savoir si vous avez besoin d'aide pour clarifier quelque chose!
Aussi, hablo español. :)
il y a un tas de documentation qui parle de préférer async / await au lieu de promesses
@Pablo Araya Bien sûr, mais vous devez comprendre les promesses avant de sauter dans async / wait . Au final, j'aime plus personnellement la syntaxe des Promesses .