Overview

Layout responsive mobile

Il framework rileva automaticamente il viewport e cambia rendering dei due componenti principali — <wuic-list-grid> e <wuic-parametric-dialog> (edit-form) — su schermi stretti, senza richiedere modifiche ai metadata applicativi.

Cosa cambia su mobile

ComponenteDesktop (>768px)Mobile (≤768px)
<wuic-list-grid><p-table> con righe orizzontali, frozen action column, scroll virtuale tabellareLa stessa <p-table> con row template card-style: stack di card verticali (una per record) con caption/valore in due colonne, action button in cima, paginator in fondo, [virtualScroll] opzionale (condiviso col desktop)
<wuic-parametric-dialog> (edit-form)Field disposti su una o piu' colonne secondo mc_ui_size_widthField full-width stackati verticalmente, tab list scrollabile orizzontalmente, toolbar compressa

Lo switch e' trasparente al codice applicativo: nessun template host da forkare, nessun metadato da settare. Riusa tutte le regole metadata esistenti (mc_hide_in_list, mc_ui_grid_column_data_template, custom action button, conditional styling).

Soglia configurabile

La soglia di switch e' di default 768px, allineata al breakpoint Bootstrap-like. Per cambiarla nel proprio host:

Snippet 1ts
// app bootstrap (es. main.ts oppure un APP_INITIALIZER)
import { MetadataProviderService } from 'wuic-framework-lib';
import { environment } from './environments/environment';

MetadataProviderService.widgetDefinition.mobileBreakpointPx =
  environment.mobileBreakpointPx ?? 768;

E nell'environment.ts:

Snippet 2ts
// src/environments/environment.ts
export const environment = {
  production: false,
  mobileBreakpointPx: 768  // tablet escluso
  // mobileBreakpointPx: 1024  // tablet portrait/landscape inclusi
  // mobileBreakpointPx: 600   // solo smartphone reali
};

La soglia viene letta una volta al constructor del singleton DeviceAwarenessService. Se vuoi cambiarla a runtime, ricrea l'istanza tramite re-bootstrap dell'app (caso d'uso raro).

Detection programmatica

Il singleton DeviceAwarenessService espone:

  • isMobile$: Observable<boolean> — emette ad ogni transizione viewport (basato su window.matchMedia)
  • isMobile: boolean — snapshot sincrono

Uso tipico in un componente custom:

Snippet 3ts
import { Component, inject } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { DeviceAwarenessService } from 'wuic-framework-lib';

@Component({
  selector: 'my-card',
  imports: [AsyncPipe],

Customizzare il template card mobile

La card mobile di default mostra actions + label/value rows. Per fornire un template completamente custom (es. avatar + titolo + sotto-info), settare WidgetDefinition.mobileCardTemplate con una stringa Angular markup. Il template viene compilato runtime via ɵcompileComponent, quindi puo' usare directives, pipes e binding standard.

Variabili disponibili nello scope del template (passate come inputs da <wuic-list-grid> mobile):

  • rowData — record corrente
  • rowIndex — indice della riga (0-based)
  • columns — array [{ field, header, metaColumn, ... }]
  • metaInfo — meta info di tabella (metaInfo.tableMetadata, metaInfo.columnMetadata)
  • datasource — istanza DataSourceComponent
  • actionButtonRowIsVisible(rowIndex) — booleano per virtualizzazione (sempre true se non virtualizzato)

Esempio — card a due righe con avatar e azioni in basso:

Snippet 4ts
import { MetadataProviderService } from 'wuic-framework-lib';

MetadataProviderService.widgetDefinition.mobileCardTemplate = `
  <div class="my-mobile-card">
    <div class="my-mobile-card-header">
      <img *ngIf="rowData.avatar_url"
           [src]="rowData.avatar_url"

> Nota rendering: il markup viene iniettato dentro la cella <td class="wuic-mobile-card-cell"> del row template mobile (compilato via DynamicRowTemplateComponent.getComponentFromTemplate, selector tr), lo stesso path JIT usato in desktop. Gira quindi nello scope del componente row: le variabili elencate sopra sono direttamente disponibili nel binding, senza *ngComponentOutlet [inputs]. Basta concentrarsi sul markup interno; niente host element da gestire manualmente.

> Gli stili custom vanno messi in CSS globale (es. styles.scss) o in un componente con encapsulation: ViewEncapsulation.None, perche' il row template card e' compilato in un componente separato dal <wuic-list-grid> host. In alternativa usare classi prefissate wuic-mobile-card-* gia' stilate dalla library.

Customizzare l'edit-form mobile

L'edit-form mobile e' CSS-only (nessun template alternativo): le regole sotto @media (max-width: 768px) in parametric-dialog.component.scss neutralizzano il width inline dei field e li impilano verticalmente.

Se vuoi un layout edit-form mobile completamente diverso (es. wizard a step su mobile, single-page su desktop), puoi usare il sistema esistente md_edit_template:

1. Crea un componente Angular con il markup desiderato e registralo nel widget map dell'host.

2. Settare la colonna md_edit_template di _metadati__tabelle col selector del componente.

3. Il <wuic-parametric-dialog> lo renderizza al posto del form generato di default.

Se serve cambiare il template solo su mobile, usa DeviceAwarenessService.isMobile dentro il componente custom per scegliere la variante.

Virtualizzazione card mobile

Dopo il refactor 2026-04-23, mobile e desktop condividono la stessa <p-table>: cambia solo il row template (una <td colspan="99"> card-style invece delle <td> per colonna). Di conseguenza la virtualizzazione mobile passa dallo stesso [virtualScroll] della p-table desktop — non c'e' un <p-virtualscroller> separato per le card.

Lo switch e' gated dallo stesso flag isListVirtualizationEnabled(), quindi:

  • Le tabelle che hanno metaInfo.tableMetadata.archetypes.list.virtualize (o page size > 1000) attivano la virtualizzazione anche sulla versione mobile.
  • L'altezza riga virtuale e' quella della p-table ([virtualScrollItemSize]="getListVirtualizationItemSize()"), condivisa tra i due layout.

Niente da configurare lato app: lo stesso flag e lo stesso <p-table> governano entrambe le modalita'.

Scroll-to-top automatico

Su mobile, dopo il cambio pagina dal paginator, lo scroll torna automaticamente all'inizio della lista card (sia il container .wuic-mobile-card-list che window). Su desktop il comportamento di default della <p-table> (scroll interno alla tabella) e' invariato.

Filter-bar su mobile

Il <wuic-filter-bar> cambia automaticamente comportamento sotto la soglia mobile:

DesktopMobile
Pannello inline collassabile (chevron). Il content (5 tab: Filter / Advanced Filter / Page Size / Sorting / Grouping + form) si espande sotto il toggle, riducendo l'area della lista nello stesso flex container.Toggle button con icona pi-filter. Lo stesso content (5 tab + form) viene promosso a overlay CSS fullscreen tramite la classe filter-bar-content-mobile-overlay, con un header filter-bar-mobile-header (titolo "Filter" + close button pi-times). La lista sotto resta intatta (l'overlay e' position: fixed sopra il layout) e alla chiusura l'app torna direttamente sulla lista senza saltare a top.

Stato sincronizzato tramite lo stesso isCollapsed del desktop (toggle via toggleCollapse()): l'overlay CSS si attiva quando isMobile && !isCollapsed. Niente da configurare lato app — il switch e' trasparente.

Razionale architetturale: la catena flex .repeater-content > wuic-data-repeater > .data-repeater-body > wuic-list-grid-lazy > :host e' tutta overflow: hidden + max-height: 100%. Su viewport stretto, un pannello inline che cresce verticalmente schiaccia il list-grid a 0px, perche' il container scrollabile (.repeater-content) e' vincolato al viewport e non puo' scrollare per rivelare la lista nascosta. L'overlay CSS fullscreen evita il problema tirando fuori il content dal layout flow, senza un <p-dialog>: i binding [(ngModel)] e [record]="filterDescriptor" di <wuic-field-filter> richiedono che il content resti nel template del componente, altrimenti i valori digitati non si propagano al filterDescriptor.

Best practice

  • Lascia il default della soglia 768px se non hai esigenze precise: e' il valore standard piu' diffuso e gia' allineato al breakpoint usato dalle altre regole @media del framework.
  • Quando provi un template card custom, parti dal default buildDefaultMobileCardTemplate (vedi sorgente list-grid) e modifica iterativamente — riusare formatGridViewValue e <wuic-data-action-button-lazy> mantiene coerenza con desktop.
  • Su mobile inline edit non e' supportato by design: il click su una card apre l'edit-form. Se hai un workflow che richiede edit cella-per-cella anche su mobile, valuta un template custom che inietta <wuic-field-editor-lazy> per i campi editabili.
  • Testare sempre entrambi i viewport prima di chiudere un task UI: il resize tra desktop e mobile deve essere fluido senza reload (la subscription a isMobile$ ricostruisce il template automaticamente).

Screenshot

List grid mobile — card stack (cities)
List grid mobile — card stack (cities)
Carousel mobile — Upload Sample
Carousel mobile — Upload Sample
Chart mobile — radar (cities)
Chart mobile — radar (cities)
Kanban mobile — board scrolls horizontally
Kanban mobile — board scrolls horizontally
Map mobile — Google maps with markers
Map mobile — Google maps with markers
Scheduler mobile — month calendar (schedules)
Scheduler mobile — month calendar (schedules)