Overview
Custom Actions
The framework lets you add custom actions on top of a <wuic-list-grid>. There are two distinct types, with different metadata table and callback signature:
- Table action (bulk action): a button in the toolbar above the grid, operating on a multiple selection or the whole view.
- Row action: a button on each row, operating on the single record.
> The distinction matters: _mtdt__cstom__actions__tabelle contains only table actions. For a row action you instead create a virtual column in _metadati__colonne. There is no scope field in _mtdt__cstom__actions__tabelle: an action placed there is always a table action, even if the callback uses record.
Table action (toolbar / bulk)
It is registered in _mtdt__cstom__actions__tabelle. The callback has this signature:
function (datasource, metaInfo, record, event, wtoolbox) {
// datasource : the grid's DataSourceComponent
// metaInfo : table/column metadata
// record : current / selected records
// event : UI event
// wtoolbox : framework services (notifications, dialog, ...)
}- To enable multiple selection on the grid set
mdmultipleselection=1on the table metadata. - To refresh the UI after the action use
datasource.fetchData()(NOTrefresh()). - For a confirmation toast use
wtoolbox.messageNotificationService.add().
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 (per-row button)
It is created as a virtual column in _metadati__colonne:
mc_ui_column_type = 'button'mc_voa_class = 6(button-column class)- callback in the
mcbuttonactionfield (text)
The callback receives the row's record and is therefore suited to single-record actions (printing a single row, opening a one-click dialog, changing the current record's state).
-- example: "Stampa" button on each row of 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);Comparison table
| Table action | Row action | |
|---|---|---|
| Metadata table | _mtdt__cstom__actions__tabelle | _metadati__colonne (virtual column) |
| UI position | toolbar above the grid | button on each row |
| Scope | multiple selection / view | single record |
| Callback | (datasource, metaInfo, record, event, wtoolbox) | callback in mcbuttonaction, receives the record |
| Multi-select | mdmultipleselection=1 | n/a |
| UI refresh | datasource.fetchData() | datasource.fetchData() |
See also
- List grid — the grid the actions operate on.
- Metadata integration — table/column metadata model.
<!-- incode-injection -->
In-code injection (this component only)
Table actions can also be injected directly in the component `.ts`, with no SQL patch. Key difference: the SQL patch on _mtdt__cstom__actions__tabelle makes the action visible in every component using that route (persistent, route-wide); the in-code injection limits it to this component only.
The action is an element of the metaInfo.tableMetadata._Metadati_Custom_Actions_Tabelles array (already initialized to []). Fields of the MetadatiCustomActionTabella class: button_caption (label, required), button_image? (PrimeNG icon), action_callback__fn — the FUNCTION run on click, signature (datasource, metaInfo, record, event, wtoolbox) => void (not a string; the serialized string variant is action_callback), disable_callback__fn? for conditional disabling, ordine?.
Wiring: get the DataSourceComponent via @ViewChild('ds', { static: true }) and push in `ngOnInit` (NOT ngAfterViewInit) when fetchInfo$ publishes the metadata — this way the patch precedes the first render of the child <wuic-list-grid> (which subscribes to fetchInfo$ in its own ngOnInit, after the parent's). Idempotent .some(...) guard because fetchInfo$ re-emits. Refresh the UI with datasource.fetchData() (not refresh()).
import { Component, ViewChild, OnInit } from '@angular/core';
import { DataSourceComponent, ListGridComponent } from 'wuic-framework-lib';
@Component({
selector: 'app-aziende-grid',
imports: [DataSourceComponent, ListGridComponent],
template: `In-code injection — row action (per-row button)
The row action (a button on each row) is injected in-code as a virtual button column in metaInfo.columnMetadata — not in _Metadati_Custom_Actions_Tabelles (that is toolbar/bulk only).
⚠️ Critical difference from the DB version. The mcbuttonaction string is compiled into mc_button_action__fn by MetadataProviderService only when the metadata is loaded from the DB. A column pushed in ngOnInit is after that load → the string is never compiled, and DataActionButtonComponent (which requires mc_button_action__fn in isMetadataButtonEnabled) leaves the button disabled. So in-code you set the FUNCTION `mc_button_action__fn` directly, not the string.
Fields of the button column (runtime, MetadatiColonna class):
mc_ui_column_type: 'button'mc_button_caption— button label (without it → label =mc_nome_colonna, e.g."rinnova_action"instead of"Rinnova")mc_button_image?— PrimeNG icon (e.g.'pi pi-refresh')mc_button_action__fn— the FUNCTION run on click, signature(datasource, record, event, field, wtoolbox) => void(NOT themcbuttonaction/mc_button_actionstring)mc_button_confirm_message?,mc_button_visibility_condition?— optional
record in the callback is { [col]: BehaviorSubject<any> } → read the values with record['<col>']?.value (the PK with record['<PK>']?.value).
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; // idempotent (BehaviorSubject re-emits)
cols.push({
mc_nome_colonna: 'rinnova_action',Versus the DB version (the "Row action" section above): there the callback is the string mcbuttonaction, compiled by the framework at load time. The two paths are NOT interchangeable: DB = `mcbuttonaction` string, in-code = `mc_button_action__fn` function.