Vuejs - Popular select with API data

Asked

Viewed 3,336 times

1

I am having problems to popular a select with the data I have as return of an API. I am using Vue.

Follows codes:

My HTML is like this:

<select>
  <option value="" disabled selected>Escolha uma conta</option>
  <option v-for="account in accounts" :key="account" :value="account">{{ account }}</option>
</select>

I’m doing the API flame with Aces:

data() {
  accounts: []
},

methods: {
  async getAccounts() {
   await this.$axios.$get('http://localhost:4000/api/accounts')
    .then(res => {
      // console.log(res)
      res.map(account => {
        this.accounts.push(account)
        // console.log(this.accounts)
      })
    })
    .catch(err => {
      // console.log(err)
      M.toast({html: 'Houve um erro ao buscar contas.', classes: 'rounded red darken-1', outDuration: 1000})
    })
  }
},

created() {
  this.getAccounts()
}

But when you load the page select is not populated. If I take the comment from the console.log(this.Accounts) after the push, it shows on the console the values inside the right array.

Could someone help me?

#### EDIT

Updating the code after a few changes, both in Vue and in the API I consume. And giving some explanations regarding some points that @guastallaigor raised.

First questions from @guastallaigor’s reply:

1 - data () sempre deve ser uma função e ela deve retornar um objeto

    R: O código esta com o return no data, é que no momento de fazer a 
     pergunta eu não selecionei tudo, dei ctrl+c e ctrl+v, eu fui 
     pegando por parte do código e jogando aqui, ai nessa posso ter 
     deixado passar o return.

2 - Verifique se a maneira que você está utilizando o axios está 
    correta, pois está divergente da documentação e da maneira que 
    costumo utilizar/ver. (axios.get - no meu esta $axios.$get)

    R: Estou utilizando desta forma, porque não estou utilizando o 
       VueJS puro, estou utilizando o Nuxt, que é um "framework" (não 
       sei se da pra chama-lo assim), construído em cima do Vue, é bem 
       interessante, e nele ja vem o axios configurado. Aí no Nuxt pra 
       usar o axios devo dar um this.$axios.$get por exemplo, ai não 
       necessito dar import no axios também.

3/4 - Verifique se a resposta da API é de fato um array / Verifique se 
      a API está correta e voltando o JSON da maneira esperada;

    R: A API esta retornando um array de objetos da forma que preciso 
       no front, agora não necessito mais do map ou forEach. Depois 
       que alterei o retorno da API agora só preciso do   
       this.accounts = res, e ele ja me retorna corretamente, verifico 
       isso pelo console.log(res)

5 - Utilize o :key com uma chave única, ou a chave do próprio v-for

    R: A API me retorna um array de objetos, com, conta e 
       descricao_conta. Dentro das options, devo mostrar "conta - 
       descricao_conta", então como tenho o código da conta, no :key, 
       eu jogo accounts.conta, e não necessito da chave do próprio 
       objeto.

Now I will put as this the code of my front:

<select v-model="selected">
  <option value="" disabled selected>Escolha uma conta</option>
  <option
      v-for="account in accounts"
      :key="account.conta" 
      :value="account.conta">
      {{ account.conta }} - {{ account.descricao_conta }}
 </option>
</select>


data() {
    return {
        selected: null,
        accounts: []
    }
}


methods: {
  async getAccounts() {
    let self = this
    await this.$axios.$get('http://localhost:4000/api/accounts')
      .then(res => {
        // console.log(res)
        self.accounts = res
        // console.log(self.accounts)
      })
      .catch(err => {
        // console.log(err)
        M.toast({html: 'Houve um erro ao buscar as contas.', classes: 'rounded red darken-1', outDuration: 1000})
      })
  }
}


async created() {
  await this.getAccounts()
  console.log(this.accounts)
}

The.log console I placed inside created(), it returns the Accounts variable filled with the API data correctly, but the select remains empty. That is, when I call the function that searches the data in the API, it actually populates the variable Accounts, but does not populate the select.

  • how are console.log(this.accounts) before the this.accounts.push(account) ? [] or undefined?

  • It returns no data. Returns [ob: Observer]

  • I changed the API, and I’ve already set the data to come in Array the way I need, so in Vue I’m just assigning the res to Accounts

  • But it still doesn’t work. I tried to create a non-Axios variable to store this, but still it wasn’t

  • Why don’t you put it all in created()? leaving so async created ()

  • I tried that way but it didn’t work either :/

  • I don’t know where it could be wrong

  • Inside the getAccounts function instead of setting the value to the Accounts variable, I put a Return res. And within date, where I declare the accoounts variable to assign it by default the method like this: date: { Accounts: getAccounts } But it still doesn’t work

  • this getAccounts()

  • and so this.accounts = res ?

  • Just as I’m trying

  • {{ accounts }} shows the result of res ?

  • If I give a console.log(this.Accounts) within the getAccounts() method it returns the correct values, but if I give console.log(this.Accounts) in created(), after calling this.getAccounts(), it returns empty

  • Yeah, that’s what I figured but try those codes inside the async created(), without methods

  • I tried this way and he doesn’t even bring the console.

  • Is the API response correct? The console.log(res) shows that the data is coming back in the expected way?

  • @Gabriel Here are the points you have to test, this is working within the async? if it does not work, nor will it record the data because there is no communication with data()

  • What if you put console.log(typeof res, res); where you have // console.log(res)?

Show 13 more comments

1 answer

2

I will try to help based on what I understand and your responses in the comment.

There are some details that may be influencing your problem.

1. data () always must be a function and it must return an object;

Your code is like this:

data() {
  accounts: []
},

When I should be like this:

data () {
  return {
    accounts: []
  }
},

Or so:

data: () => ({
  accounts: []
}),

2. Check whether the way you are using the axios is correct as it is divergent from the documentation and the way I usually use/see;

You’re using it like this:

this.$axios.$get

I usually use/see like this:

axios.get // ou mudando a nomenclatura

And importing so, usually in your mainjs:

import axios from 'axios'

3. Verify that the API response is in fact a array;

You use the answer directly with the function map

res.map(account => {

When the answer is an object, an error will occur. Another point is that if it is actually an array, it can be assigned like this:

this.accounts = res

Or so, making the copy:

this.accounts = [...res]

No need for the map, for the map will still return a array, which you are not using. If you do not wish to use it thus, and indeed with the function push, could use a forEach.

4. Check that the API is correct and return the JSON in the expected way;

There is nothing to explain in this case, just check the return with console.log.

5. Use the :key with a single key, or the key itself v-for;

In this case, place the whole object (assuming it is an object) inside the attribute :key is not advisable. If it is an object, and does not have a id for him, put it like this:

<option v-for="(account, key) in accounts" :key="key" :value="account">{{ account }}</option>

Example:

Starting a new project, and using the axios the way it shows the documentation, as well as some points I said, along with mockAPI, there is this functional result, filling the select correctly:

Helloworld.Ve

<template>
  <div class="stackoverflow">
    <select>
      <option value="" disabled selected>Escolha uma conta</option>
      <option v-for="account in accounts" :key="account" :value="account">{{ account.name }}</option>
    </select>
  </div>
</template>

<script>
import axios from 'axios'
const url = 'http://5af0e90b954a1000145c4c65.mockapi.io/accounts'

export default {
  name: 'Stackoverflow',
  data: () => ({
    accounts: []
  }),
  methods: {
    async getAccounts () {
      await axios.get(url)
        .then(res => {
          console.log(res)
          this.accounts = [...res.data]
        })
        .catch(err => {
          console.log(err)
          // M.toast({html: 'Houve um erro ao buscar contas.', classes: 'rounded red darken-1', outDuration: 1000})
        })
    }
  },
  created () {
    this.getAccounts()
  }
}
</script>
  • Thank you for the @guastallaigor force. I will edit my question as I changed the feedback the API sends to Vue. And explain some points you raised with your answer.

  • as regards the this.$axios, he possibly should be doing a Mixin to inject the same (or at least I hope he is).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.