mad-tree-view
Árvore hierárquica com expand/collapse.
Componente de arvore hierarquica com expand/collapse, context menu por no, badges, persistencia de estado e operacoes parciais via MadResponse.
Tag compilada pelo MadGridCompiler.
Props
| Prop | Tipo | Default | Descricao |
|---|---|---|---|
| name | string | '' | Identificador (ops, localStorage, DOM) |
| model | string | '' | Classe model Eloquent para auto-query |
| database | string | MAIN_DATABASE | Conexao do banco |
| display | string | 'nome' | Campo ou template {nome} ({codigo}) |
| key | string | 'id' | Campo PK |
| parent-field | string | 'parent_id' | Campo que referencia o pai |
| icon | string | 'file' | Icone Lucide padrao |
| active-icon | string | '' | Icone quando selecionado |
| expanded-icon | string | '' | Icone quando expandido com filhos |
| icon-field | string | '' | Campo do model para icone por no |
| order-by | string | display | Campo de ordenacao |
| filters | array | [] | Filtros (mesma sintaxe do dbcombo): [['campo', 'op', 'val'], ...] |
| items | array | null | Dados manuais (dispensa model) |
| active | string | '' | ID do no ativo/selecionado |
| count-field | string | '' | Campo do model para badge de contagem |
| mad:click | string | '' | Metodo PHP ao clicar no (recebe ID) |
| expanded | string | 'all' | Estado inicial: all, none, first |
| persist | bool | false | Persistir expand state em localStorage |
| class | string | '' | Classes CSS extras |
Tags filhas
<mad-tree-actions position="top|bottom">
Botoes globais acima ou abaixo da arvore. Conteudo e HTML/Blade livre.
<mad-tree-actions position="top">
<mad-btn navigate="CategoriaForm" variant="ghost" size="sm" icon="plus">Nova Categoria</mad-btn>
</mad-tree-actions>
<mad-tree-context-menu>
Template de context menu aplicado a cada no. Suporta placeholders {id}, {name}, {label} e qualquer campo do model.
<mad-tree-context-menu>
<mad-menu-item icon="pencil" navigate="CategoriaForm::onEdit({id})">Editar</mad-menu-item>
<mad-menu-separator />
<mad-menu-item icon="trash-2" variant="danger" mad:click="onDelete({id})">Excluir</mad-menu-item>
</mad-tree-context-menu>
Uso com model (auto-query)
<mad-tree-view name="pastas" model="GedFolder" database="communication"
display="name" parent-field="parent_id"
icon="folder" active-icon="folder-open"
order-by="name" :active="$folderId"
count-field="_document_count"
mad:click="onSelectFolder" persist>
<mad-tree-context-menu>
<mad-menu-item icon="folder-plus" navigate="GedFolderForm" params="{parent_id: {id}}">
Nova subpasta
</mad-menu-item>
<mad-menu-separator />
<mad-menu-item icon="pencil" navigate="GedFolderForm::onEdit({id})">Editar</mad-menu-item>
<mad-menu-item icon="trash-2" variant="danger" mad:click="onDeleteFolder({id})">Excluir</mad-menu-item>
</mad-tree-context-menu>
</mad-tree-view>
Uso com dados manuais
@php
$tree = [
['id' => 1, 'name' => 'Raiz A', 'icon' => 'folder', '_count' => 5, 'children' => [
['id' => 2, 'name' => 'Sub A1', 'icon' => 'folder', '_count' => 3, 'children' => []],
]],
['id' => 3, 'name' => 'Raiz B', 'icon' => 'file', '_count' => 0, 'children' => []],
];
@endphp
<mad-tree-view name="categorias" :items="$tree" display="name"
icon="folder" count-field="_count" mad:click="onSelect" persist />
Estrutura do array: ['id', 'name', 'icon'?, 'children'?, '{count-field}'?]
MadResponse — Operacoes parciais
Adicionar no
return (new MadResponse())
->treeAddNode('pastas', [
'id' => $folder->id,
'parent_id' => $folder->parent_id,
'name' => $folder->name,
'icon' => 'folder',
])
->toast('Pasta criada!', 'success')
->closeDrawer();
Remover no (com animacao)
return (new MadResponse())
->treeRemoveNode('pastas', $folderId)
->toast('Pasta excluida', 'success');
Atualizar no (label, icone, badge)
return (new MadResponse())
->treeUpdateNode('pastas', $folderId, [
'name' => $novoNome,
'icon' => 'folder-lock',
'count' => 42,
]);
Mudar no ativo
return (new MadResponse())
->treeSetActive('pastas', $folderId);
Icones dinamicos
{{-- Icone muda quando selecionado --}}
<mad-tree-view icon="folder" active-icon="folder-open" ...>
{{-- Icone muda quando expandido --}}
<mad-tree-view icon="folder" expanded-icon="folder-open" ...>
{{-- Icone por no (campo do model) --}}
<mad-tree-view icon-field="icone" ...>
Persistencia de estado
Com persist, o estado de expand/collapse e salvo em localStorage com a key mad-tree-{name}-expanded. Restaura automaticamente ao recarregar.
Filtros
A prop :filters e o UNICO mecanismo de filtro do <mad-tree-view> — um array de
tuplas [campo, operador, valor] aplicado direto no Eloquent Builder do model
(Mad\Database\QuerySource::applyArrayFilters()). Nao existe prop :criteria —
qualquer valor passado nela e silenciosamente ignorado pelo compilador.
{{-- Filtro simples (1 condicao) --}}
<mad-tree-view name="categorias" model="Categoria" display="nome"
:filters="[['ativo', '=', '1']]" />
{{-- Multiplas condicoes (AND implicito) --}}
<mad-tree-view name="categorias" model="Categoria" display="nome"
:filters="[['ativo', '=', '1'], ['tipo', '=', 'produto']]" />
{{-- Operadores: '=', '>', '<', '>=', '<=', '<>', 'in', 'not in', 'is null', 'is not null' --}}
<mad-tree-view name="pastas" model="GedFolder" display="name"
:filters="[['owner_id', 'in', $ownerIds]]" />
{{-- Filtro dinamico vindo de outra parte da tela --}}
<mad-tree-view name="categorias" model="Categoria" display="nome"
:filters="[['empresa_id', '=', $this->empresaId]]" />
Para uma fonte mais elaborada que :filters nao cobre (joins, subqueries, scopes
do model), monte o array fora do componente reaproveitando um Eloquent Builder
normal — sem nenhuma classe de criterio dedicada:
@php
$ativos = Categoria::ativas()->pluck('id')->all(); // scope do model, por exemplo
@endphp
<mad-tree-view name="categorias" model="Categoria" display="nome"
:filters="[['id', 'in', $ativos]]" />
NUNCA fazer
{{-- ERRADO: montar arvore manualmente com @foreach recursivo --}}
@foreach($folders as $f)
<div style="padding-left:{{ $depth * 14 }}px;">{{ $f->name }}</div>
@if($f->children)
@include('partials.tree-item', ['items' => $f->children, 'depth' => $depth + 1])
@endif
@endforeach
{{-- CERTO --}}
<mad-tree-view name="pastas" model="GedFolder" display="name" parent-field="parent_id"
icon="folder" mad:click="onSelect" />
{{-- ERRADO: buscar a arvore no controller e passar :criteria/objeto de query --}}
@php $crit = Categoria::where('ativo', '1'); @endphp
<mad-tree-view name="categorias" :criteria="$crit" />
{{-- :criteria nao existe — o compilador ignora a prop silenciosamente --}}
{{-- CERTO: usar model + :filters (array-DSL) --}}
<mad-tree-view name="categorias" model="Categoria" display="nome" parent-field="parent_id"
:filters="[['ativo', '=', '1']]" />
{{-- ERRADO: recarregar a arvore inteira apos criar/editar/excluir --}}
$this->loadData(); // full re-render
{{-- CERTO: ops parciais --}}
return (new MadResponse())->treeAddNode('pastas', [...]);
return (new MadResponse())->treeRemoveNode('pastas', $id);
return (new MadResponse())->treeUpdateNode('pastas', $id, ['name' => $nome]);