Récupérer les infos d'un Object obtenu via axios

Bonjour à tous !
Je suis nouveau sur VueJS et je tatonne encore pas mal…

J’ai besoin de votre aide et de votre avis la communauté sur mon code pour savoir si je fais bien les choses…

Mon but est tout simple : afficher une liste d’offres d’emplois et lorsque l’on clique sur l’une d’entre elles, avoir son détail sur la page.

J’ai réussi à faire mon affichage de la liste des offres sans trop de difficultés.

Par contre pour l’affichage d’une seule offre j’ai un peu plus souffert.

Je récupère l’offre de cette manière :

getOffer(offer) {
        axios.get('https://mon.api.com/api/public/job/' + offer, auth)
                .then(response => {
                    this.result_offer = response;
                    console.log(this.result_offer);
                })
                .catch(error => {
                    console.log(error);
                    this.errored2 = true;
                })
                .finally(() => this.loading2 = false);
    },detailOffer(offerId) {
        console.log(offerId);
        document.getElementById("listOffers").style.display = "none";
        document.getElementById("showOffer").style.display = "block";
        this.getOffer(offerId);
    },computed: {
    displayedOffer() {
        return this.result_offer;
    }
},

Pour le template, ça donne ça :

<div id="showOffer" style="display:none;">
                                <section v-if="errored2">
                                    <p>Nous sommes désolés, nous ne sommes pas en mesure de récupérer ces informations pour le moment. Veuillez réessayer ultérieurement.</p>
                                </section>

                                <section v-else>
                                    <div v-if="loading2">Chargement...</div>

                                    <div v-if="displayedOffer.data">
                                        <a href="#offers" class="discover" v-on:click="showOffers()">Retour aux offres</a>
                                        <div class="col-lg-12 col-md-12 col-sm-2 col-xs-12"  style="margin-top:20px;min-height:300px;">
                                            <div class="card card-accent-dark">
                                                <div class="card-body">
                                                    <div class="card-header text-info">{{ displayedOffer.data.title }}</div>
                                                    <div class="card-body text-dark">
                                                        <h3 class="card-title" v-if="displayedOffer.data.region">{{ displayedOffer.data.region }} <span v-if="displayedOffer.data.postalCode">({{ displayedOffer.data.postalCode }})</span></h3>
                                                        <div class="card-text">
                                                            <span v-if="displayedOffer.data.reference">Ref : {{ displayedOffer.data.reference }}</span>
                                                            <br>
                                                            <span v-if="displayedOffer.data.contractTypeNames">{{ displayedOffer.data.contractTypeNames[0] }}</span>
                                                            <br>
                                                            <span v-if="displayedOffer.data.lastPublicationDate">Publiée le {{ displayedOffer.data.lastPublicationDate | formatDate }}</span> 
                                                            <br>
                                                            <span v-if="displayedOffer.data.missionDescription">Description du poste : {{ displayedOffer.data.missionDescription }}</span> 
                                                            <br><br>
                                                            <span v-if="displayedOffer.data.profileDescription">Profil recherché : {{ displayedOffer.data.profileDescription }}</span> 
                                                            <br><br>
                                                            <div class="badge badge-info" style="margin-top: 10px;">#{{ displayedOffer.data.urlFriendly }}</div>
                                                        </div>
                                                    </div> 
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </section>
                            </div>

Ce que je trouve un peu bizarre sur mon code, qui fonctionne “by the way”, c’est de devoir accéder dans le template à mes données via la variable displayedOffer.data et non displayedOffer directement.

J’ai essayé en renvoyant :

    displayedOffer() {
            return this.result_offer.data;
        }

Mais sans succès côté template…

C’est normal que tu aies besoin de faire this.result_offer.data pour récupérer le payload de ton backend.

Axios renvoie un objet représentant la réponse du server ; cela permet de récupérer les headers HTTP, le status code (200, 3xx, 4xx, …), le payload (.data) et d’autres choses

Comment est initialisé this.result_offer dans la méthode data du composant ?

Si tu le mets à null au début, tu as dû voir passer une erreur dans ta console en utilisant

        displayedOffer() {
            return this.result_offer.data;
        }

il faut utiliser :
return this.result_offer && this.result_offer.data;

Merci pour ton aide ! :slight_smile:

Exact ! Si je mets null j’obtiens une erreur direct :

Ma méthode data ressemble à ça actuellement :

data: {
    results: [],
    result_offer: [],
    loading: true,
    errored: false,
    loading2: false,
    errored2: false,
    page: 1,
    perPage: 9,
    pages: []
},

En utilisant la ligne :
return this.result_offer && this.result_offer.data;

ça plante aussi :confused:

Du coup je vais laisser comme ça je pense :

        displayedOffer() {
                return this.result_offer;
            }

Même si je trouve ça moins beau dans le template :sweat_smile:

Bon j’ai finalement trouvé ma solution !

J’ai initialisé data comme ceci :

data: {
        results: [],
        result_offer: {data:{}},
        loading: true,
        errored: false,
        loading2: false,
        errored2: false,
        page: 1,
        perPage: 9,
        pages: []
    },

Du coup, je peux récupérer :
this.result_offer = response.data;

Puis dans le template, retirer tous les displayedOffer.data !

Voilà c’est bien plus propre je trouve comme cela :slight_smile:

Oui c’est déjà mieux que d’avoir result_offer qui change de type (il passait de Array à Object, ce qui est plutôt une mauvaise pratique (menant à des erreurs runtime))

Pour que
result_offer: null
passe, il faut être cohérent

si displayedOffer est
this.result_offer && this.result_offer.data
alors il ne faut plus jamais utiliser
displayedOffer.data
mais juste
displayedOffer

ou bien displayedOffer est juste this.result_offer
(ce qui rend inutile la computed property)
il faut alors changer changer la condition
<div v-if="displayedOffer.data">
en
<div v-if="displayedOffer">
mais continuer à utiliser displayedOffer.data à l’intérieur du if