Components

TreeRemote

Componente Tree gerarchico con nodi caricati da sorgente remota, selezione singola, multipla o checkbox.

Panoramica

TreeRemote è un componente Tree che carica la struttura gerarchica dei nodi in modo asincrono tramite fetchFn. Ideale per dati con struttura ad albero come categorie, organigrammi, filesystem o menu di navigazione.

La fetchFn deve restituire un array di TreeNode nel formato PrimeVue:

interface TreeNode {
  key: string
  label: string
  data?: unknown
  icon?: string
  children?: TreeNode[]
  leaf?: boolean
}

Caratteristiche principali:

  • Tre modalità di selezione: single, multiple, checkbox
  • Filtro/ricerca sui nodi
  • Filtri dinamici su altri campi del form
  • Supporto metaKeySelection per selezione multipla con Ctrl/Cmd

Casi d'uso tipici: navigazione categorie, selezione reparti organizzativi, selezione voci di menu, strutture di classificazione.

Anteprima live (con fetchFn mockato)

Utilizzo nello schema

const schema = [{
  name: 'categoriaSelezionata',
  type: 'treeremote',
  label: 'Categoria',
  props: {
    fetchFn: fetchAlberoCategorie,
    selectionMode: 'single',
    showFilter: true,
  }
}, {
  // Selezione multipla con checkbox
  name: 'repartiAssegnati',
  type: 'treeremote',
  label: 'Reparti',
  props: {
    fetchFn: fetchAlberoReparti,
    selectionMode: 'checkbox',
    metaKeySelection: false,
  }
}]

Utilizzo diretto

Selezione singola

<TreeRemote
  v-model="categoriaSelezionata"
  :fetch-fn="fetchCategorie"
  selection-mode="single"
  show-filter
  label="Categoria"
/>

Selezione multipla con checkbox

<TreeRemote
  v-model="repartiSelezionati"
  :fetch-fn="fetchReparti"
  selection-mode="checkbox"
  :meta-key-selection="false"
  label="Reparti assegnati"
/>

Struttura dati attesa da fetchFn

// La fetchFn deve restituire TreeNode[]
const fetchCategorie = async (): Promise<TreeNode[]> => {
  const res = await fetch('/api/categorie/albero')
  const data = await res.json()
  // Trasformare i dati nel formato TreeNode se necessario
  return data
}

// Esempio struttura TreeNode
const esempio: TreeNode[] = [{
  key: '0',
  label: 'Elettronica',
  icon: 'pi pi-desktop',
  children: [{
    key: '0-0',
    label: 'Computer',
    icon: 'pi pi-laptop',
    data: { id: 1, slug: 'computer' }
  }, {
    key: '0-1',
    label: 'Smartphone',
    icon: 'pi pi-mobile',
    leaf: true,
    data: { id: 2, slug: 'smartphone' }
  }]
}]

Formato del valore (modelValue)

Il valore dipende dalla selectionMode:

// selectionMode: 'single'
// Record<string, boolean> con una sola chiave
{ '0-1': true }

// selectionMode: 'multiple'
// Record<string, boolean> con più chiavi
{ '0-0': true, '0-1': true }

// selectionMode: 'checkbox'
// Record con stato checked/partialChecked per ogni nodo
{ '0': { checked: false, partialChecked: true }, '0-0': { checked: true, partialChecked: false } }

Props

PropTipoDefaultDescrizione
modelValueRecord<string, boolean> | string[] | nullnullNodi selezionati (v-model). Record<string, boolean> per single/multiple/checkbox; string[] accettato come alternativa quando il consumer gestisce la selezione come lista di chiavi
labelstringEtichetta del campo
helperTextstringTesto di supporto sotto il campo
errorstringMessaggio di errore (attiva stato invalid)
disabledbooleanfalseDisabilita il campo
invalidbooleanfalseAttiva visivamente lo stato di errore
fetchFnFetchFn<TreeNode>Funzione asincrona per caricare i nodi
filterstring | FilterCriteriaFiltro statico passato alla fetchFn
filterFieldsstring[][]Campi del form da osservare per filtri dinamici
fullDataRecord<string, unknown>{}Dati completi del form (per filtri dinamici)
selectionMode'single' | 'multiple' | 'checkbox''single'Modalità di selezione
showFilterbooleanfalseMostra campo di ricerca/filtro
filterPlaceholderstring(da i18n)Placeholder del campo filtro
metaKeySelectionbooleantrueRichiede Ctrl/Cmd per selezione multipla

Metodi esposti

MetodoDescrizione
reload()Ricarica i nodi chiamando nuovamente la fetchFn

Slot

Tutti gli slot del componente Tree di @pzeta/vue-components vengono propagati automaticamente. Slot tipici:

SlotPropsDescrizione
default{ node }Template personalizzato per ogni nodo (sostituisce label + icon)
nodeicon{ node, expanded, selected }Override dell'icona del nodo
togglericon{ node, expanded }Override dell'icona di espansione/collasso
header/footerContenuto sopra/sotto la lista nodi

Eventi

EventoPayloadDescrizione
update:modelValueRecord<string, boolean> | string[] | nullSelezione aggiornata

Validazione suggerita

import { z } from 'zod'

const schema = z.object({
  // Selezione singola: verifica che almeno un nodo sia selezionato
  categoriaSelezionata: z.record(z.boolean())
    .refine(v => Object.keys(v).length > 0, 'Seleziona una categoria')
    .nullable()
    .refine(v => v !== null, { message: 'La categoria è obbligatoria' }),
})