Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Vue TreeView

Bom dia.

Estou com problema em fazer um campo "search" para um TreeView. Gostaria de algum exemplo/dica.. E onde estou errando...

Estou usando como exemplo o https://vuejs.org/v2/examples/tree-view.html

main.js

import _ from 'lodash'
import Vue from 'vue'
import VueResource from 'vue-resource'

Vue.use(VueResource);

import TreeView from './components/modTreeView.vue';

new Vue({    
    el: '#container',
    components: {        
        TreeView
    }

});

arquivo.blade.php

<div class="col-xs-12" id="container">
        <tree-view datatree="{{ $data }}"></tree-view>        
    </div>

Ahh a data que passo é essa : O $data vem de um controller e alimenta minha view eu poderia ter feito com o vue resource tambem que daria na mesma coisa. (O importante que passa um json ai ^^)

$data = '{
          "name": "My Tree",
          "children": [
            { "name": "hello" },
            { "name": "wat" },
            {
              "name": "child folder",
              "children": [
                {
                  "name": "child folder",
                  "children": [
                    { "name": "hello" },
                    { "name": "wat" }
                  ]
                },
                { "name": "hello" },
                { "name": "wat" },
                {
                  "name": "child folder",
                  "children": [
                    { "name": "hello" },
                    { "name": "wat" }
                  ]
                }
              ]
            }
          ]
        }';

modTreeView.vue

<template>
    <div>
        <div>
            <input type="text" class="form-control" placeholder="Filtrar Tree View" v-model="filterTerm">
        </div>

        <ul>
            <item class="item" :model="filterList"></item>
        </ul>

    </div>
</template>

<script>
    import Vue from 'vue'
    Vue.component('item', {
      template: `<li>
          <div
            :class="{bold: isFolder}"
            @click="toggle"
            @dblclick="changeType">
            {{model.name}}
            <span v-if="isFolder">[{{open ? "-" : "+"}}]</span>
          </div>
          <ul v-show="open" v-if="isFolder">
            <item
              class="item"
              v-for="model in model.children"
              :model="model">
            </item>
            <li class="add" @click="addChild">+</li>
          </ul>
        </li>`,
      props: {
        model: Object
      },
      data: function () {
        return {
          open: false,
          filterTerm: ''
        }
      },
      computed: {
        isFolder: function () {
          return this.model.children &&
            this.model.children.length
        }        
      },
      methods: {
        toggle: function () {
          if (this.isFolder) {
            this.open = !this.open
          }
        },
        changeType: function () {
          if (!this.isFolder) {
            Vue.set(this.model, 'children', [])
            this.addChild()
            this.open = true
          }
        },
        addChild: function () {
          this.model.children.push({
            name: 'new stuff'
          })
        }
      }
    })        

    export default {
        props: ['datatree'],        
        data(){
            return{
                list: [], 
                sortProperty: 'name',
                sortDirection: 1,
                filterTerm: ''
            }
        },    
        ready(){ //mounted
            console.log('testeeee');
            // console.log(this.datatree);
            this.list = JSON.parse(this.datatree);          
            // console.log(this.list);
        },
        computed:{
            filterList(){
                console.log('computed');
                console.log(this.list);
                console.log(typeof this.list);
              if(this.filterTerm){                  
                let exp = new RegExp(this.filterTerm.trim(), 'i');
                // return this.list.children.filter(x => exp.test(x.name));
                var res = this.list.children.filter(function(filho){
                    return exp.test(filho.name);
                });
                return res;
              }else{
                return this.list;
              }
            }
        },
        methods: {
            sort (ev, proper) {
                ev.preventDefault()

                this.sortProperty = proper;
                 if(this.sortDirection == 1){
                    this.sortDirection = -1
                 }else{
                    this.sortDirection = 1
                 }
            }
        }
    }
</script>

<style scoped=''>
    .item {
      cursor: pointer;
    }
    .bold {
      font-weight: bold;
    }
    ul {
      padding-left: 1em;
      line-height: 1.5em;
      list-style-type: dot;
    }
</style>

Eu fiz um computed chamado filterList para fazer esse filtro mas nao me retorna corretamente a lista...

PS: E possivel fazer esse tipo de filtro usando o filterBy ?? Qual a melhor maneira de fazer isso ?

PS2: Tambem nao entendi muito bem como serve o 'template' que o vue tras como exemplo.. por exemplo parece que ele chama ele mesmo e isso mesmo ?! tem como separar esse template como modulo ?

6 respostas

Renato, só uma pergunta para eu me situar. Você termiou os dois cursos de Vue.js do Alura antes de tentar implementar soluções como essa? Se fez, tranquilo, é que eles não aparecem como concluídos para mim em seu perfil. É que tem muita coisa legal nele que pode ajudá-lo.

Digo isso porque aprendemos em um dos capítulos criar uma computed property que é usada em um filtro. Mas você esta associando através de :model uma computed property. Não é esse caminho.

Seu model com o dado do filtro deve ser associado a uma propriedade da função data. Quem é uma computed property é a lista que você vai associar com o elemento que vai repetir com v-for.

Com essa orientação, dá uma alterada no seu código. Vai que é esse o problema.

Bom dia Flavio ^^

Eu finalizei o curso de Vue 1 e comecei o Vue 2 (Pretendo finalizar ainda essa semana o curso).

No codigo eu removi o v-model="filterTerm" e no lugar eu coloquei um v-on:input="filterTerm = $event.target.value" para pegar os valores do input e fazer o filtro no computed conforme explicado no Modulo 5.

Mas ainda estou com duvida em como fazer o filtro aqui

computed:{
            filterList(){
                console.log('computed');
              if(this.filterTerm){                  
                let exp = new RegExp(this.filterTerm.trim(), 'i');
                // return this.list.children.filter(x => exp.test(x.name));
                var res = this.list.children.filter(function(son){
                    return exp.test(son.name);
                });
        // Aqui nao funciona. 
                return res;
              }else{
        // Aqui funciona
                return this.list;
              }
            }
        }

A minha lista esta sendo retornada pelo this.list. So que this.list é um object e nao consigo fazer o filter direto na list, entao eu tenho que entrar na propriedade children dela que é uma lista de array e ai sim eu consigo fazer o filter. Porem no retorno nao me tras nada. Acho que este caso é mais javascript do que vue.js

No v-for vc itera em um objeto que tem uma lista, certo? Então sua cp não pode retornar uma lista, mas um objeto que contém a lista filtrada. Filtre a lista e pendure na propriedade de um {} antes de retorna-la. A propriedade tem que ter o mesmo nome da propriedade que você esta iterando no v-for.

O seu modelo não ajuda a eu entende-lo. Os nomes são genericos demais. Até agora não sei no que você quer iterar. Então to focando a parte técnica só. Dai você ajusta de acordo com seu modelo.

solução!

Você esta é filtrando o children de a propriedade list de um objeto. Sendo assim, no seu filter você deve retornar { list: res }. No caso, usando sua lógica, res a o children filtrado.

Acho que é isso, porque se você diz que retornando this.list funciona, é porque esse list tem children e esse children é usado para itera com v-for.

Era isso mesmo Favio.

Muito obrigado ^^

Excelente Renato! Sucesso e bom estudo meu aluno!