Overview

Custom Actions

Il framework permette di aggiungere azioni personalizzate sopra una <wuic-list-grid>. Esistono due tipi distinti, con tabella metadata e firma callback diverse:

  • Table action (azione di tabella / bulk): bottone nella toolbar sopra la griglia, opera su selezione multipla o sull'intera vista.
  • Row action (azione di riga): bottone su ogni riga, opera sul singolo record.

> La distinzione è importante: _mtdt__cstom__actions__tabelle contiene solo table-action. Per una row-action si crea invece una colonna virtuale in _metadati__colonne. Non esiste un campo di scope in _mtdt__cstom__actions__tabelle: un'azione inserita lì è sempre una table-action, anche se il callback usa record.

Table action (toolbar / bulk)

Si registra in _mtdt__cstom__actions__tabelle. Il callback ha questa firma:

Snippet 1js
function (datasource, metaInfo, record, event, wtoolbox) {
  // datasource : il DataSourceComponent della griglia
  // metaInfo   : metadati tabella/colonne
  // record     : record correnti / selezionati
  // event      : evento UI
  // wtoolbox   : servizi framework (notifiche, dialog, ...)
}
  • Per abilitare la selezione multipla sulla griglia imposta mdmultipleselection=1 sulla tabella metadata.
  • Per rinfrescare la UI dopo l'azione usa datasource.fetchData() (NON refresh()).
  • Per un toast di conferma usa wtoolbox.messageNotificationService.add().
Snippet 2js
async function (datasource, metaInfo, record, event, wtoolbox) {
  const ids = (datasource.resultInfo?.selected || []).map(r => r.id.value);
  await fetch('/api/Custom/bulkApprove', { method: 'POST', body: JSON.stringify(ids) });
  await datasource.fetchData();
  wtoolbox.messageNotificationService.add({ severity: 'success', summary: 'Approvati', detail: ids.length + ' record' });
}

Row action (bottone per riga)

Si crea come colonna virtuale in _metadati__colonne:

  • mc_ui_column_type = 'button'
  • mc_voa_class = 6 (classe della colonna-bottone)
  • callback nel campo mcbuttonaction (text)

Il callback riceve il record della riga ed è quindi adatto ad azioni single-record (stampa singola riga, apertura dialog one-click, cambio stato del record corrente).

Snippet 3SQL
-- esempio: bottone "Stampa" su ogni riga di fatture_inviate
INSERT INTO _metadati__colonne (md_id, mc_nome_colonna, mc_ui_column_type, mc_voa_class, mcbuttonaction, mc_ordine)
VALUES (@md_id, 'print_action', 'button', 6, '<callback JS>', 100);

Tabella di confronto

Table actionRow action
Tabella metadata_mtdt__cstom__actions__tabelle_metadati__colonne (colonna virtuale)
Posizione UItoolbar sopra la grigliabottone su ogni riga
Scopeselezione multipla / vistasingolo record
Callback(datasource, metaInfo, record, event, wtoolbox)callback in mcbuttonaction, riceve il record
Multi-selectmdmultipleselection=1n/a
Refresh UIdatasource.fetchData()datasource.fetchData()

Vedi anche

<!-- incode-injection -->

Iniezione in-code (solo questo componente)

Le table action si possono iniettare anche direttamente nel `.ts` del componente, senza patch SQL. Differenza fondamentale: la patch SQL su _mtdt__cstom__actions__tabelle rende l'azione visibile in ogni componente che usa quella route (persistente, route-wide); l'iniezione in-code la limita a questo solo componente.

L'azione è un elemento dell'array metaInfo.tableMetadata._Metadati_Custom_Actions_Tabelles (già inizializzato a []). Campi della classe MetadatiCustomActionTabella: button_caption (etichetta, obbligatorio), button_image? (icona PrimeNG), action_callback__fn — la FUNZIONE eseguita al click, firma (datasource, metaInfo, record, event, wtoolbox) => void (non una stringa; la variante stringa serializzata è action_callback), disable_callback__fn? per disabilitare condizionalmente, ordine?.

Wiring: ottieni il DataSourceComponent con @ViewChild('ds', { static: true }) e fai il push in `ngOnInit` (NON ngAfterViewInit) quando fetchInfo$ pubblica i metadati — così la patch precede il primo render della <wuic-list-grid> figlia (che si iscrive a fetchInfo$ nel suo ngOnInit, dopo quello del padre). Guard idempotente .some(...) perché fetchInfo$ riemette. Refresh UI con datasource.fetchData() (non refresh()).

Snippet 4ts
import { Component, ViewChild, OnInit } from '@angular/core';
import { DataSourceComponent, ListGridComponent } from 'wuic-framework-lib';

@Component({
  selector: 'app-aziende-grid',
  imports: [DataSourceComponent, ListGridComponent],
  template: `

Iniezione in-code — row action (bottone per riga)

La row action (bottone su ogni riga) si inietta in-code come colonna virtuale bottone in metaInfo.columnMetadatanon in _Metadati_Custom_Actions_Tabelles (quello è solo toolbar/bulk).

⚠️ Differenza critica rispetto alla versione DB. La stringa mcbuttonaction viene compilata in mc_button_action__fn da MetadataProviderService solo al caricamento dei metadati dal DB. Una colonna pushata in ngOnInit è dopo quel load → la stringa non viene mai compilata, e DataActionButtonComponent (che richiede mc_button_action__fn in isMetadataButtonEnabled) lascia il bottone disabilitato. Quindi in-code si imposta direttamente la FUNZIONE `mc_button_action__fn`, non la stringa.

Campi della button column (runtime, classe MetadatiColonna):

  • mc_ui_column_type: 'button'
  • mc_button_caption — etichetta del bottone (senza → label = mc_nome_colonna, es. "rinnova_action" invece di "Rinnova")
  • mc_button_image? — icona PrimeNG (es. 'pi pi-refresh')
  • mc_button_action__fn — la FUNZIONE eseguita al click, firma (datasource, record, event, field, wtoolbox) => void (NON la stringa mcbuttonaction/mc_button_action)
  • mc_button_confirm_message?, mc_button_visibility_condition? — opzionali

record nel callback è { [col]: BehaviorSubject<any> } → leggi i valori con record['<col>']?.value (la PK con record['<PK>']?.value).

Snippet 5ts
ngOnInit() {
  this.ds.fetchInfo$.subscribe(info => {
    if (!info?.metaInfo) return;
    const cols = info.metaInfo.columnMetadata;
    if (cols.some(c => c.mc_nome_colonna === 'rinnova_action')) return; // idempotente (BehaviorSubject riemette)
    cols.push({
      mc_nome_colonna: 'rinnova_action',

Versus la versione DB (sezione "Row action" sopra): lì la callback è la stringa mcbuttonaction, compilata dal framework al load. Le due strade NON sono intercambiabili: DB = stringa `mcbuttonaction`, in-code = funzione `mc_button_action__fn`.