Componente VueJS de dropdowns dependentes

Pois é, faz tempo mesmo que não escrevo nada. Muito tempo se passou, e aprendi muita coisa nova, sendo que uma delas foi conhecer VueJS para a criação de componentes, com uso no Laravel.

Eu já trabalho com Laravel a algum tempo, e sempre uso nos meus projetos PHP. Antes dele, eu sofri um pouco com o Prado e o Zend 2, os quais me serviram de preparo para chegar ao Laravel.

Mas o VueJS é uma grata surpresa. Reaproveitar código através de componentes que posso personalizar como quiser, e emprega-los usando apenas uma linha, é fantástico, além de economizar muito tempo de trabalho.

Bom, na verdade você só economiza depois que o componente estiver pronto e funcionando, porque até lá você vai padecer…

Vou mostrar aqui um componente que criei para facilitar a minha vida na hora de usar dropdowns dependentes para Estado e Cidade, o que é muito comum na grande maioria dos sistemas que precisam manter o cadastro de clientes, fornecedores, e etc. Talvez precise de algum refinamento, mas está funcional para as minhas demandas.

UFCidade.vue

<template>
    <div>
        <div style="display: none;" v-once>{{iduf}}</div>        
        <div class="form-group">
            <label for="estado">Estado</label>            
            <select :name="nomecampouf" class='form-control' v-model='estado' @change='getCidades()'>
                <option value='0' disabled>-- Estado --</option>
                <option v-for='data in estados' :value='data.id' :key='data.id' :selected="estado === data.id">{{ data.nomeuf }}</option>
            </select>
        </div>        
        <div style="display: none;" v-once>{{idcidade}}</div>
        <div class="form-group">
            <label for="cidade">Cidade</label>
            <select :name="nomecampocidade" class='form-control' v-model='cidade'>
                <option value='0' disabled>-- Cidade --</option>
                <option v-for='data in cidades' :value='data.id' :key='data.id' :selected="cidade === data.id">{{ data.nomecidade }}</option>
            </select>
        </div>
    </div>
</template>   

<script>  
    export default {
        props: ['nomecampocidade', 'nomecampouf','idcidade', 'iduf'],
        data(){
            return {
                estado: 0,
                estados: [],
                cidade: 0,
                cidades: []
            }
        },
        methods:{
            getEstados: function(){
              axios.get('/api/getEstados')
              .then(function (response) {
                 this.estados = response.data;
              }.bind(this));
            },
            getCidades: function() {                
                axios.get('/api/getCidades',{
                 params: {
                   idUF: this.estado
                 }
              }).then(function(response){
                    this.cidades = response.data;
                }.bind(this));
            }
        },
        created: function(){
            this.getEstados();            
        },
        watch: {
            'iduf': function(){
                if(this.iduf != null)
                {
                    this.estado = this.iduf;
                    this.getCidades();
                }
            },
            'idcidade': function(){
                if(this.idcidade != null)
                {
                    this.cidade = this.idcidade;
                }
            }
        },
    }
</script>

Eu registrei o template descrito acima no arquivo [app.js] do Laravel, da seguinte forma:

Vue.component('inputufcidade', require('./components/UFCidade.vue').default);

Depois, nas páginas *.blade.php eu posso chamar o componente assim:

Em um formulário de cadastro:

<inputufcidade nomecampouf="idUF" nomecampocidade="idCidade"></inputufcidade>

Em um formulário de atualização:

<inputufcidade nomecampouf="idUF" nomecampocidade="idCidade" :idcidade="$store.state.item.idCidade" :iduf="$store.state.item.idUF"></inputufcidade>

Sobre os parâmetros do componente:

  • nomecampouf: serve para indicar o nome do campo que será utilizado para o <select name=””> que enviará o post com o ID da UF escolhida. Este parâmetro é obrigatório nos formulários de cadastro e atualização (CRUD).
  • nomecampocidade: serve para indicar o nome do campo que será utilizado para o que enviará o post com o ID da Cidade escolhida. Este parâmetro é obrigatório nos formulários de cadastro e atualização (CRUD).
  • iduf: serve para receber o valor inicial da UF, caso esteja utilizando o componente em uma atualização de cadastro.
  • idcidade: serve para receber o valor inicial da Cidade, caso esteja utilizando o componente em uma atualização de cadastro.

Vale ressaltar que os respectivos dropdowns de UF e Cidade são preenchidos através da chamada dos métodos getEstados() e getCidades() respectivamente. Estes métodos estão inseridos em uma API Controller do Laravel, conforme descrito abaixo:

    public function getEstados()
    {
        $data = Uf::select('id', 'nomeuf')->get();
        return response()->json($data);
    }

    public function getCidades(Request $request)
    {
        $data = Cidade::where('idUF', $request->idUF)->get();
        return response()->json($data);
    }

Apesar de existir o relacionamento UF –> Cidade, foi necessário incluir o campo idUF no cadastro, para facilitar a tarefa de atualização, visto que este valor (idUF) deve ser informado no controle VueJS.

“May the Force be with you”