5
votes

Vue JS en attente de données avant le rendu

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...
        }

    }

}


0 commentaires

3 Réponses :


13
votes

Pour empêcher le composant de s'afficher avant que les données ne soient renvoyées, vous pouvez:

  1. ajoutez une propriété "isFetching" aux données et définissez-la sur "true"

  2. dans le rappel de récupération, définissez isFetching sur "false"

3. ajoutez v-if = "! isFetching" au wrapper du composant


4 commentaires

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



0
votes

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)
        },


0 commentaires

3
votes

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.


5 commentaires

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 .