VueJS - Popular select with API data

1

I'm having trouble popping a select with the data I got as a return from an API. I'm using Vue.

Following codes:

My HTML looks 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 am making the API call with axios:

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 the select is not populated. If I take the comment from console.log (this.accounts) after the push, it shows in the console the values inside the right array.

Could anyone help me?

#### EDIT

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

First the questions of @guastallaigor's response:

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'll put this code on 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 console.log that I put inside created (), it returns the accounts variable populated with the API data correctly, but the select is still empty. That is, when I call the function that fetches the data in the API, it actually populates the accounts variable, but does not populate the select.

    
asked by anonymous 07.05.2018 / 16:07

1 answer

2

I'll try to help based on what I understand and your answers in the comment.

There are some details that may be influencing your problem.

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

Your code looks like this:

data() {
  accounts: []
},

When it should look like this:

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

Or so:

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

2. Make sure that the way you're using axios is correct, as it differs from the documentation and the way I use / see it;

You're using it like this:

this.$axios.$get

I usually use / look like this:

axios.get // ou mudando a nomenclatura

And so importing, usually in your mainjs :

import axios from 'axios'

3. Make sure that the API response is actually a array ;

You use the response directly with the function map

res.map(account => {

When the response is an object, an error occurs. Another point is that if it is an array, it can be assigned as follows:

this.accounts = res

Or, by copying:

this.accounts = [...res]

There is no need for map , as map will still return a array , which you are not using. If you do not want to do so, and indeed with the push function, you could use a forEach .

4. Make sure the API is correct and return JSON as expected;

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

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

In this case, putting the entire object (assuming it is an object) within the :key attribute is not advisable. If it is an object, and does not have a id for it, put it like this:

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

Example:

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

HelloWorld.vue

<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>
    
08.05.2018 / 02:22