vuejs todolist2

Validação de formulário e tela empty state VueJS – ToDo List parte 2

Introdução

No artigo passado mostrei como fazer a criação de um projeto de ToDo List com VueJS.

Este é uma continuação deste projeto, embora seja um projeto simples, da para aplicar muitos conceitos e técnicas que podem ser utilizadas no dia a dia.

Neste artigo você vai ver como fazer a validação de um formulário com VueJS, como fazer um efeito de transição entre as rotas, para uma navegação mais suave e também como fazer uma tela empty state, indicando que não há registros cadastrados.

Preview

Caso você queira obter o código fonte do artigo passado, de como implementar o projeto de ToDo List com VueJS, para implementar a partir deste artigo, veja neste link.

Validação de formulário

Para a validação do formulário, vou utilizar a biblioteca Vuelidate, ela é uma biblioteca de validação de formulários VueJS bem simples de configurar e boa para utilizar nos projetos.

Primeiro vou realizar a instalação da biblioteca no projeto com o comando:

npm install vuelidate

Depois de instalado, vou realizar a configuração da biblioteca no main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import { BootstrapVue } from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)

//configuração da biblioteca vuelidate
import Vuelidate from "vuelidate";
Vue.use(Vuelidate);

Vue.config.productionTip = false
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

Com a instalação e configuração realizada, a próxima etapa é ir no formulário para fazer a validação.

Neste caso, irei realizar a validação somente do campo título, que é o campo obrigatório, e vou validar também se ele tem pelo menos três caracteres.

No Form.vue, vou fazer a importação da biblioteca e só vou importar o que será utilizado, no caso o required e o minLength:

import { required, minLength } from "vuelidate/lib/validators";

Depois disso, logo abaixo do data() vou fazer a configuração da validação.

Essa configuração é feita utilizando a chave validations, que a biblioteca disponibiliza.

Dentro dessa chave é necessário colocar qual campo será validado, e as validações nele:

validations: {
    form: {
      subject: {
        required,
        minLength: minLength(3)
      }
    }
  },

Dessa forma será validado o campo subject que está dentro do form, e as validações é de campo requerido e pelo menos três caracteres.

A validação está pronta, mas é necessário colocar agora no campo de título, as cores vermelho e verde que vão informar ao usuário se o formulário está válido ou não.

Para isso o BootstrapVue no campo input, conta com a prop state, que para ela, podemos passar true para quando o campo está válido, e false para inválido.

Será necessário também atualizar o v-model para utilizar os atributos da biblioteca de validação para que ela tenha acesso aos dados, o input fica assim:

<b-form-input
      id="subject"
      v-model.trim="$v.form.subject.$model"
      type="text"
      placeholder="Ex: lavar carro"
      required
      autocomplete="off"
      :state="getValidation"
      aria-describedby="subject-feedback"
></b-form-input>
<b-form-invalid-feedback id="subject-feedback">Campo obrigatório.</b-form-invalid-feedback>

O state aponta para o getValidation, que é um computed que vai ter a lógica de validação, esse computed fica assim:

computed: {
    getValidation() {
      if(this.$v.form.subject.$dirty === false) {
        return null;
      }

      return !this.$v.form.subject.$error;
    }
  }

Se o campo ainda não foi alterado, retorna cai na primeira validação e retorna null.

Caso tenha algum erro no campo, a chave da biblioteca que é a $error vai ficar como true, porém se retornar o true diretamente ao state, ele vai ficar verde, porque o true para o state é válido, por isso eu retorno o contrário do que está no error, para o state ficar correto.

Com isso a validação já estará funcionando, mas um ponto adicional é bloquear o botão de salvar, visto que o usuário não poderá salvar o formulário quando ele estiver inválido.

Para isso vou utilizar o mesmo computado do getValidation para desabilitar o campo.

É possível passar a prop disabled para o b-button do BootstrapVue, porém essa prop funciona ao contrário do state, ela espera true para bloquear o campo, então a única coisa a se fazer é utilizar o disabled com o inverso do getValidation:

<b-button 
    type="submit" 
    variant="outline-primary" 
    @click="saveTask"
    :disabled="!getValidation"
> Salvar </b-button>

E com isso a validação está funcionando e o campo de salvar está sendo bloqueado corretamente.

Transição entre rotas

A transição entre as rotas é utilizada para trazer uma navegação mais suave ao usuário, é um efeito simples de criar com o VueJS e traz um bom resultado ao sistema.

Para criar o efeito vou voltar no App.vue, e vou colocar o router-view dentro de um componente transition:

<template> <!-- App.vue -->
  <div id="app">
    <b-navbar toggleable="lg" type="dark" variant="dark">
      <b-navbar-brand href="#">ToDo List</b-navbar-brand>

      <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>

      <b-collapse id="nav-collapse" is-nav>
        <b-navbar-nav>
          <b-nav-item to="/">Tarefas</b-nav-item>
          <b-nav-item to="/form">Formulário</b-nav-item>
        </b-navbar-nav>
      </b-collapse>
    </b-navbar>

    <transition name="fade" mode="out-in">
      <router-view />
    </transition>
  </div>
</template>

Agora é necessário criar o estilo do efeito, coloquei o nome dele de fade.

Na parte de estilo do App.vue, o efeito fica dessa forma:

<style>
.fade-enter-active, .fade-leave-active {
  transition-duration: 0.2s;
  transition-property: opacity;
  transition-timing-function: ease;
}

.fade-enter, .fade-leave {
  opacity: 0;
}
</style>

Bem simples, este é um efeito nativo do VueJS e somente isso já faz o efeito mais suave de navegação entre as telas.

Tela empty state

Essa tela é utilizada para quando uma parte de um sistema ainda não tem dados cadastrados.

Em vez de deixar somente uma tela em branco, ou então um texto avisando que não há dados, é mais bonito e mais agradável colocar alguma imagem e um botão de chamada para o usuário criar um registro.

Com isso então fiz a implementação da tela empty state no VueJS.

Primeiramente fui no site unDraw e fiz a busca por “empty” para buscar uma imagem para usar no projeto, fiz o download da imagem e coloquei dentro de src/assets/images/.

Eu precisei criar a pasta images, e também renomeei a imagem que fiz o download para ficar mais fácil de usar.

Depois, no componente List.vue, será necessário criar uma forma para verificar se não tem nenhuma tarefa cadastrada.

E para isso eu criei um computed do VueJS chamado isTasksEmpty, e nele fiz a verificação se o array de tarefas é vazio:

computed: {
    isTasksEmpty() {
      return this.tasks.length === 0;
    },
},

Agora vou utilizar este computado na parte de HTML do List.vue para fazer uma verificação condicional, se não tiver tarefas, renderizar a imagem, e se tiver, renderizar a lista de tarefas.

<template v-if="isTasksEmpty"> 
      <div class="empty-data mt-2">
        <img src="../assets/images/empty-data.svg" class="empty-data-image">
        <b-button 
          variant="outline-primary" 
          class="mt-2" 
          size="lg"
          to="/form"
        > Criar tarefa </b-button>
      </div>  
    </template>
    <template v-else>
      <div v-for="(task, index) in tasks" :key="index">
        <b-card :title="task.subject" class="mb-2">
          <b-card-text>{{ task.description }}</b-card-text>

          <b-button
            variant="outline-secondary"
            class="mr-2"
            @click="edit(index)"
          >
            Editar
          </b-button>
          <b-button
            variant="outline-danger"
            class="mr-2"
            @click="remove(task, index)"
          >
            Excluir
          </b-button>
        </b-card>
      </div>
    </template>

Também coloquei um botão para criar a tarefa, pois se não tem tarefas ainda, pode ser uma boa chamar o usuário para criar a sua primeira.

A tela fica assim:

Vídeo

Veja o vídeo prático de como realizar essas três implementações com o VueJS.

Código fonte

O código fonte está no meu CodeSandbox, neste link.

Para ver outros canais onde o posto conteúdo sobre VueJS, veja os Links do Programando Soluções.

Conclusão

Essas três funcionalidades são muito úteis no dia a dia, a implementação delas com VueJS é simples é traz um ótimo resultado para o sistema.

Referências

https://www.npmjs.com/package/vuelidate

https://bootstrap-vue.org/

https://undraw.co/search

Este conteúdo te ajudou de alguma forma?