mad-checklist-field
Checklist com colunas customizadas.
Lista de seleção múltipla com busca, contador, select-all e colunas customizadas — para
quando o <mad-checkbox-group-field> simples não basta (precisa mostrar mais de uma coluna
por item, ex: código + nome + status). Integra com MadForm/MadRenderContext igual aos
outros campos multi-select: form->fill() pré-marca os itens, form->save() persiste.
<mad-checklist-field> — items manuais (array em memória)
Props
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
| name | string | '' | Nome do campo (obrigatório, envia como name[]) |
| label | string | '' | Label acima da lista |
| items | array | [] | Linhas — array de arrays/objetos (cada um vira uma row) |
| columns | array | [] | Colunas a exibir — normalmente via <mad-col> filhos (ver abaixo) |
| id-column | string | 'id' | Campo da row usado como identificador (o que vai em name[]) |
| selected | array | auto | IDs pré-marcados (auto via MadRenderContext quando omitido) |
| searchable | bool | true | Mostra a busca client-side no topo |
| height | string | '320px' |
Altura máxima da área scrollável |
| placeholder | string | 'Buscar...' |
Placeholder do campo de busca |
| mode | string | 'comma' |
comma (CSV numa coluna) ou table (pivot 1:N) |
| pivot-model | string | '' | Classe do model Eloquent da pivot (mode=table) |
| foreign-key | string | '' | Coluna FK do registro pai na pivot (mode=table) |
| item-key | string | '' | Coluna FK do item selecionado na pivot (mode=table) |
| database | string | MAIN_DATABASE ou business |
Conexão usada na leitura/escrita da pivot |
| hint | string | '' | Texto de ajuda |
| error | string | '' | Mensagem de erro |
| required | bool | false | |
| disabled | bool | false | |
| attrs | string | '' | Atributos HTML extras |
Colunas via <mad-col> (compilado em tempo de build)
As colunas se declaram como filhos <mad-col> — o compilador Blade do MAD extrai essas tags
e injeta :columns="[...]" automaticamente, então não existe <mad-col> em runtime:
<mad-checklist-field name="opts" :items="['a' => 'Opt A', 'b' => 'Opt B']" :selected="['a']">
<mad-col field="id" label="Cód" width="60px" center />
<mad-col field="label" label="Nome" />
</mad-checklist-field>
Atributos aceitos em <mad-col> dentro do checklist: field (chave da row), label,
width, center/right (alinhamento), transform (callable/expressão PHP). Um field
prefixado com __ (ou a flag slot) vira coluna do tipo slot — <td> vazio
(data-mad-cl-col/data-mad-cl-row) para injetar conteúdo dinâmico via JS depois da
renderização (ex: botões de ação por linha), igual ao mecanismo de slot do
mad-grid.
Uso básico
@php
$items = [
['id' => 1, 'nome' => 'Leitura'],
['id' => 2, 'nome' => 'Escrita'],
['id' => 3, 'nome' => 'Exclusão'],
];
@endphp
<mad-checklist-field name="permissoes" label="Permissões" :items="$items" :selected="[1, 2]">
<mad-col field="id" label="ID" width="60px" center />
<mad-col field="nome" label="Permissão" />
</mad-checklist-field>
<mad-dbchecklist-field> — items via model Eloquent (auto-query)
Mesmo conceito do dbcombo-field: recebe model/display/filters e carrega via
Eloquent/Query Builder — sem precisar montar items manualmente no controller.
Props adicionais (sobre as do mad-checklist-field)
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
| model | string | '' | Classe do model Eloquent fonte das options |
| database | string | MAIN_DATABASE | Conexão |
| key | string | 'id' | Campo PK |
| display | string | 'nome' | Campo de exibição. Aceita template {nome} ({sigla}) |
| order-by | string | display | Ordenação |
| query | Builder | null | Eloquent/Query Builder pronto (alternativa a model+filters) |
| filters | array | [] | [['campo','op','val'], ...] — aplicado no Query Builder |
Quando columns não é declarado (nem via <mad-col>), o componente auto-gera duas colunas:
id (largura fixa, centralizada) + a coluna de display.
Uso básico
<mad-dbchecklist-field name="grupos" label="Grupos do usuário"
model="SystemGroup" database="permission" display="name" height="400px">
<mad-col field="id" label="ID" width="60px" center />
<mad-col field="name" label="Nome" />
</mad-dbchecklist-field>
Com filtro
<mad-dbchecklist-field name="categorias" label="Categorias"
model="Categoria" display="nome"
:filters="[['ativo', '=', '1']]" />
Persistência — mode="table" + form->save() (recomendado)
Igual ao <mad-dbcheckbox-group-field mode="table">: declare pivot-model +
foreign-key + item-key, e form->save($record) resolve tudo — apaga a pivot do
registro pai e reinsere um row por item marcado. O selected carrega automaticamente da
pivot no onEdit (via form->fill()), sem código extra.
<mad-dbchecklist-field name="grupos" label="Grupos do usuário"
model="SystemGroup" database="permission" display="name"
mode="table" pivot-model="SystemUserGroup"
foreign-key="system_user_id" item-key="system_group_id">
<mad-col field="id" label="ID" width="60px" center />
<mad-col field="name" label="Nome" />
</mad-dbchecklist-field>
use Illuminate\Support\Facades\DB;
public function onSave(): MadResponse
{
DB::connection('business')->transaction(function () {
$user = SystemUsers::findOrNew($this->registroId);
$this->form->save($user); // salva campos + sincroniza a pivot automaticamente
});
return (new MadResponse())->toast('Salvo!', 'success')->closeDrawer();
}
Persistência — mode="comma" (CSV numa coluna)
Sem pivot-model, o mode padrão é comma: form->save($record) grava os IDs
selecionados como CSV na própria coluna name.
<mad-checklist-field name="categorias_csv" label="Categorias" :items="$items" />
$this->form->save($record);
// $record->categorias_csv = '1,3,7'
Persistência manual — MadChecklistTrait (quando precisa de dados extras por item)
Use o trait Mad\Form\MadChecklistTrait (saveChecklist/loadChecklist) em vez do
mode="table" automático quando a tabela pivot tem colunas extras por linha (ex:
permissões granulares por grupo) que não cabem no contrato padrão de
foreign-key/item-key:
use Mad\Form\MadChecklistTrait;
class GrupoProgramaForm extends MadComponent
{
use MadChecklistTrait;
public function onEdit(int $id): void
{
$cl = $this->loadChecklist(IamGroupProgram::class, 'program_id', $id, 'group_id',
fn ($record) => json_decode($record->actions ?: '[]', true)
);
$this->form->setItems('groups', $this->gruposDisponiveis(), $cl['selected']);
// $cl['extras'] = [groupId => actions, ...] — use pra pré-preencher colunas extras
}
public function onSave(): MadResponse
{
$data = $this->form->getData();
DB::connection('iam')->transaction(function () use ($data) {
$this->saveChecklist(IamGroupProgram::class, 'program_id', $this->registroId,
'group_id', $data->groups,
fn ($record, $itemId) => $record->actions = json_encode($_POST["{$itemId}_actions"] ?? [])
);
});
return (new MadResponse())->toast('Salvo!', 'success')->closeDrawer();
}
}
Resumo de decisão
| Preciso... | Usar |
|---|---|
| Booleano simples (sim/não) | <mad-checkbox-field> |
| N entre N, sem precisar de colunas extras por item | <mad-checkbox-group-field> / <mad-dbcheckbox-group-field> |
| N entre N, com múltiplas colunas por item (código, nome, status...) | <mad-checklist-field> / <mad-dbchecklist-field> |
| Pivot 1:N simples (sem dado extra por linha) | mode="table" + form->save() |
| Pivot 1:N com colunas extras por linha (ex: permissões por grupo) | MadChecklistTrait (saveChecklist/loadChecklist) |
NUNCA fazer
{{-- ERRADO: @foreach manual de checkboxes pra simular um checklist com colunas --}}
@foreach($grupos as $g)
<label><input type="checkbox" name="grupos[]" value="{{ $g->id }}"> {{ $g->name }} ({{ $g->id }})</label>
@endforeach
{{-- CERTO --}}
<mad-dbchecklist-field name="grupos" model="SystemGroup" display="name">
<mad-col field="id" label="ID" width="60px" center />
<mad-col field="name" label="Nome" />
</mad-dbchecklist-field>
{{-- ERRADO: carregar items do banco no controller pra passar pro checklist manual --}}
@php $itens = Categoria::orderBy('nome')->get()->toArray(); @endphp
<mad-checklist-field name="cats" :items="$itens" />
{{-- CERTO: dbchecklist-field carrega sozinho --}}
<mad-dbchecklist-field name="cats" model="Categoria" display="nome" />
{{-- ERRADO: sincronizar a pivot manualmente quando mode=table resolve --}}
foreach ($_POST['grupos'] as $gid) {
$ug = new SystemUserGroup();
$ug->system_user_id = $user->id;
$ug->system_group_id = $gid;
$ug->save();
}
{{-- CERTO: mode=table + form->save() --}}
<mad-dbchecklist-field name="grupos" model="SystemGroup"
mode="table" pivot-model="SystemUserGroup"
foreign-key="system_user_id" item-key="system_group_id" />
{{-- ERRADO: <template x-for> aninhado dentro de <tr> pra renderizar colunas custom --}}
<template x-for="item in items">
<tr>
<template x-for="col in cols"><td x-text="item[col.key]"></td></template>
</tr>
</template>
{{-- O parser HTML do browser remove <template> inválido dentro de <table>, quebrando o
scoping do Alpine — é exatamente por isso que <mad-col> é resolvido em PHP (build time),
não em Alpine x-for aninhado. --}}
{{-- CERTO: <mad-col> compilado em PHP, sem x-for aninhado em tr/td --}}
<mad-checklist-field name="opts" :items="$items">
<mad-col field="id" label="ID" />
<mad-col field="nome" label="Nome" />
</mad-checklist-field>