Listando categorias

Já fizemos um pequeno teste listando categorias em Testando o service Categorias. Agora precisamos que, ao invés de exibir estes dados em um console.log, exibir em uma tabela.

Criando a rota (router)

Acesse o arquivo src/router.js e adicione a rota para o componente Categorias, veja:
























 
 
 
 
 



import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    },
    {
      path: '/categorias',
      name: 'Categorias',
      component: () => import(/* webpackChunkName: "categorias" */ './views/Categorias.vue')
    }
  ]
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

webpackChunkName

O webpackChunkName é uma funcionalidade fenomenal do webpack (que atua por tras dos panos no vue). A grosso modo, ele divide os arquivos finais do projeto em pedaços, que são carregados sob demanda.

Criando o componente

Agora crie o componente Categorias.vue, com o seguinte código:

<template>
  <div>
    <div class="hero is-light">
      <div class="hero-body">
        <h1 class="title">Categorias</h1>
      </div>
    </div>
    <section class="section">
      Texto....
    </section>
  </div>
</template>
<script>
export default {
  name: 'Categorias'
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Criando o menu

No arquivo App.vue, precisamos adicionar um novo item no menu apontando para a rota /categorias:







 






<template>
  <div id="app">
    <nav class="navbar is-dark">
      <div class="navbar-brand">
        <router-link class="navbar-item" to="/">Home</router-link>
        <router-link class="navbar-item" to="/about">About</router-link>
        <router-link class="navbar-item" to="/categorias">Categorias</router-link>
      </div>
    </nav>
    <router-view />
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12

O resultado final depois de todos esses passos é a tela a seguir:

Armazenando as categorias em uma variável

Seguindo o exemplo que foi feito no Home.vue, vamos usar a api do service Categories e preencher uma variável com as categorias:









 




 


 
 
 
 
 
 
 
 
 
 
 
 
 





<template>
  <div>
    <div class="hero is-light">
      <div class="hero-body">
        <h1 class="title">Categorias</h1>
      </div>
    </div>
    <section class="section">
      {{items}}
    </section>
  </div>
</template>
<script>
import cateories from '../services/categories'
export default {
  name: 'Categorias',
  data () {
    return {
      items: []
    }
  },
  async mounted () {
    try {
      this.items = await cateories.getAll()
    } catch (error) {
      console.error(error)
    } finally {
      // todo...
    }
  }
}
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

Neste código, criamos a variável items, que a princípio está sendo exibida na página (na tag <section>). O método mount é marcado como assíncrono através da palavra async para que possamos utilizar o await na consulta do service categories. Se você não conhece async/await, recomendo ler este artigo. Basicamente, ao invés de utilizarmos o then() após o getAll, usamos async/await para deixar o código mais legível. O await fará com que o fluxo de código javascript pare em categories.getAll() e só retorne após a requisição retornar, atribuindo o retorno a variável this.items.

A resposta deste novo código é semelhante a figura a seguir:

Ao analisar o JSON que retornou do service, veja que os dados que precisamos está na propriedade chamada "data". Então é necessário realizar o seguinte ajuste no código:



 
 







async mounted () {
  try {
    const result = await cateories.getAll()
    this.items = result.data
  } catch (error) {
    console.error(error)
  } finally {
    // todo...
  }
}
1
2
3
4
5
6
7
8
9
10

Ou seja, atribuímos o retorno do service a constante result e depois atribuímos a variável this.items ao result.data.

Dica

Ainda existe uma simplificação muito utilizada nos sistemas "reais" em vue, que determina o retorno dos dados no próprio service. Por exemplo, se o nosso service categories fosse assim (repare o .then):




 



import http from './http'

export default {
  getAll: () => http.get('/categories').then(r => r.data),
  getOne: id => http.get(`/categories/${id}`)
}
1
2
3
4
5
6

Poderíamos ter:

async mounted () {
    try {
      this.items = await cateories.getAll()
    } catch (error) {
      console.error(error)
    } finally {
      // todo...
    }
  }
1
2
3
4
5
6
7
8
9

Se você se sentiu a vontade em usar esta técnica, use-a! Senão, faça da forma mais simples.

Agora temos o seguinte resultado:

O que precisamos fazer agora é usar o laço v-for para iterar nesse array e mostrar em forma tabular ao usuário.

Iterando o Array na tabela

Utilizando o Bulma, podemos criar uma tabela, como no código a seguir:









 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

























<template>
  <div>
    <div class="hero is-light">
      <div class="hero-body">
        <h1 class="title">Categorias</h1>
      </div>
    </div>
    <section class="section">
      <table class="table is-striped is-fullwidth">  1️⃣
        <thead>
          <tr>
            <th>id</th>
            <th>Nome</th>
            <th>Descricao</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="item in items" :key="item.id"> 2️⃣
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.description}}</td>
          </tr>
        </tbody>
      </table>
    </section>
  </div>
</template>
<script>
import cateories from '../services/categories';
export default {
  name: 'Categorias',
  data () {
    return {
      items: []
    }
  },
  async mounted () {
    try {
      const result = await cateories.getAll()
      this.items = result.data
    } catch (error) {
      console.error(error)
    } finally {
      // todo...
    }
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

Neste código, criamos a tabela utilizando a tag table do html. As classes em 1️⃣ são classes do Bulma. A classe table é obrigatória, enquanto que as classes is-striped (alterna a cor de fundo da linha) e is-fullwidth (tabela fica com o máximo de largura) são opcionais e alteram a forma como a tabela será exibida.

O mais importante aqui é em 2️⃣, onde temos o v-for fazendo um laço na variável items, onde cada iteração do laço os dados são atribuídos a variável item. O parâmetro :key ajuda o Vue a ter uma performance melhor e atribuímos um valor único do :key, nesse caso o id.

Repare também que o v-for está dentro da tag html tr, então este tr será repetido várias vezes. Dentro do tr, temos os elementos td com os campos id, name e description, que são os campos da tabela categories do nosso backend.

O resultado desta implementação é visto a seguir: