Components

SelectRemote

Dropdown con caricamento opzioni da sorgente remota, filtri dinamici e template personalizzabile.

Panoramica

SelectRemote è un componente dropdown che carica le opzioni in modo asincrono tramite una fetchFn. Supporta filtri dinamici basati su altri campi del form, template personalizzati per le etichette e immagini nelle opzioni.

Caratteristiche principali:

  • Caricamento asincrono opzioni tramite fetchFn
  • Filtri dinamici: quando i valori di altri campi cambiano, i dati vengono ricaricati automaticamente (filterFields + fullData)
  • Template etichette con interpolazione (optionTemplate)
  • Immagini nelle opzioni (optionImage)
  • Ricerca/filtro integrato

Casi d'uso tipici: selezione categorie, comuni/province, utenti, prodotti, qualsiasi lookup su API.

Anteprima live (con fetchFn mockato)

Nel preview qui sotto la fetchFn simula una chiamata API ritornando un array statico — in produzione la stessa funzione effettua un fetch() verso il backend.

Pattern fetchFn

type FetchFn<T = Record<string, unknown>> = (
  filters?: FilterCriteria,
  signal?: AbortSignal
) => Promise<T[]>

// Esempio base
const fetchCategorie = async () => {
  const res = await fetch('/api/categorie')
  return res.json()
}

// Con filtri passati dal composable
const fetchComuni = async (filters?: FilterCriteria) => {
  const params = new URLSearchParams()
  if (filters?.provinciaId) params.set('provinciaId', String(filters.provinciaId.value))
  const res = await fetch(`/api/comuni?${params}`)
  return res.json()
}

Utilizzo nello schema

const schema = [{
  name: 'idCategoria',
  type: 'selectremote',
  label: 'Categoria',
  props: {
    fetchFn: fetchCategorie,
    optionLabel: 'nome',
    optionValue: 'id',
    showFilter: true,
    showClear: true,
  }
}, {
  // Filtro dinamico: ricarica comuni quando cambia la provincia
  name: 'idComune',
  type: 'selectremote',
  label: 'Comune',
  props: {
    fetchFn: fetchComuni,
    optionLabel: 'nome',
    optionValue: 'id',
    filterFields: ['idProvincia'],   // Osserva questo campo
    // fullData viene iniettato automaticamente da DynamicFormLayouts
  }
}, {
  // Con template personalizzato per etichetta
  name: 'idUtente',
  type: 'selectremote',
  label: 'Assegna a',
  props: {
    fetchFn: fetchUtenti,
    optionTemplate: '{cognome} {nome} ({email})',
    optionValue: 'id',
  }
}]

Utilizzo diretto

<SelectRemote
  v-model="idSelezionato"
  :fetch-fn="fetchCategorie"
  option-label="nome"
  option-value="id"
  label="Categoria"
  show-filter
  show-clear
/>

Con filtro dinamico (fuori DynamicFormLayouts)

<SelectRemote
  v-model="idComune"
  :fetch-fn="fetchComuni"
  option-label="nome"
  option-value="id"
  :filter-fields="['idProvincia']"
  :full-data="formData"
  label="Comune"
/>

Con immagini nelle opzioni

<SelectRemote
  v-model="idPaese"
  :fetch-fn="fetchPaesi"
  option-label="nome"
  option-value="codice"
  option-image="urlBandiera"
  label="Paese"
/>

Props

PropTipoDefaultDescrizione
modelValuestring | number | boolean | nullnullValore selezionato (v-model)
labelstringEtichetta del campo
helperTextstringTesto di supporto sotto il campo
errorstringMessaggio di errore (attiva stato invalid)
disabledbooleanfalseDisabilita il campo
invalidbooleanfalseAttiva visivamente lo stato di errore
requiredbooleanfalseIndica campo obbligatorio
fetchFnFetchFnFunzione asincrona per caricare le opzioni
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)
optionLabelstring'label'Proprietà dell'oggetto da usare come etichetta
optionTemplatestringTemplate interpolato per l'etichetta, es. '{nome} ({codice})'
optionValuestring'value'Proprietà dell'oggetto da usare come valore
optionImagestringProprietà dell'oggetto contenente URL immagine
showClearbooleanfalseMostra pulsante per resettare la selezione
showFilterbooleanfalseAbilita ricerca nel dropdown
filterPlaceholderstring(da i18n)Placeholder del campo di ricerca

Metodi esposti

MetodoDescrizione
reload()Ricarica i dati chiamando nuovamente la fetchFn
<SelectRemote ref="selectRef" :fetch-fn="fetchCategorie" ... />

// Nel codice
selectRef.value?.reload()

Eventi

EventoPayloadDescrizione
update:modelValuestring | number | boolean | nullValore aggiornato

Validazione suggerita

import { z } from 'zod'

const schema = z.object({
  idCategoria: z.number({ required_error: 'Seleziona una categoria' })
    .positive('ID categoria non valido')
    .nullable()
    .refine(v => v !== null, { message: 'La categoria è obbligatoria' }),
})