Form con campi variabili

Un’esigenza che ogni tanto mi capita di quella è di avere form i cui campi non sono predeterminati ma “appaiono” secondo particolari condizioni.

Il caso più frequente è quando ho un cliente che deve gestire contratti o preventivi che cambiano nel tempo, con informazioni che non sono prevedibili a priori ma che all’occorrenza il cliente stesso può indicare e che poi finiscono su un documento pdf da rilasciare all’utente finale.

In questi casi utilizzo una gestione a template, dove i documenti vengono creati da modelli in cui sono presenti dei tag che poi vengono sostituiti con i dati definitivi al momento della generazione del pdf.

Per la compilazione del template, di solito utilizzo il componente editor html incluso in IDC, il trumbowvg (che a proposito, è terribile ma quello c’è), in cui vengonono inseriti i tag che rappresentano i dati da raccogliere in un secondo momento.

Per fare un esempio pratico, un template può essere composto in questo modo:

Preventivo n. {{numero_preventivo}} del {{data_preventivo}}

Gentile {{cognome_cliente}} {{nome_cliente}}, le presentiamo la nostra migliore offerta per {{descrizione_prodotto}}

ecc. ecc. ecc.

{{note_cliente}}

Al momento della generazione, i tag {{numero_preventivo}}, {{data_preventivo}}, {{cognome_cliente}}, {{nome_cliente}}, {{descrizione_prodotto}}, {{note_cliente}} vengono sostituiti con i valori corretti recuperati dal database o chiesti al volo al compilatore del documento, procedendo poi alla creazione del pdf.

In questo modo il cliente può costruire tutti i template che desidera e poi utilizzarli per generare i documenti “finali”.

Il problema che resta da risolvere è: come raccogliere i dati da sostituire ai tag, visto che questi possono essere decisi dal cliente e non è prevedibile a priori quali saranno e che dati rappresenteranno?

Le soluzioni possibili sono o di aggiornare il software di volta in volta aggiungendo alle videate i nuovi campi collegati ai nuovi tag, o compilare a runtime le videate con campi decisi al momento.

Il secondo caso è quello più efficiente per il cliente, poiché lo rende indipendente dal mio intervento, ma come creare le form con i campi necessari, visto che con IDC di norma permette di creare soltanto form “statiche”, ossia con un’impostazione predeterminata?

Nella stragrande maggioranza dei casi, il comportamento di IDC è quello più efficiente, poiché mantiene una organizzazione uniforme di dati e elementi video e permette di avere una ben chiara struttura delle informazioni.

Ma il mondo del software, così come come il ventaglio delle esigenze cliente, è vario e non sempre completamente ordinato; a noi resta l’ingrato compito di trovare una soluzione, al meglio possibile.

Per il caso descritto, per fortuna non frequente, nonostante IDC preferisca avere videate e campi predeterminati, in realtà permette comunque di definire a runtime la composizione dei campi su una videata, seppur con qualche limite.

Gli strumenti chiave in questo caso sono i metodi clone() e appendChild().

Il primo, chiamato su un oggetto visuale ne provoca la duplicazione, il secondo, chiamato su un oggetto container, ne permette l’aggiunta al DOM “sotto” l’elemento su cui l’appendChild() viene invocato.

Ad esempio, se sulla videata è presente un inputbox chiamato $MyInputBox e un Container (un div) chiamato $MyDiv, possiamo creare una copia di $MyInputBox e aggiungerla a $MyDiv in questo modo:

let new_inputbox = $MyInputBox.clone();
$MyDiv.appendChild(new_inputbox);

La videata rifletterà automaticamente il cambiamento, mostrando il nuovo campo input, che a design time non era presente.

Il clone() è estremamente efficiente, copia davvero tutto dell’oggetto di origine, eventi compresi.

Ad esempio, se in $MyInputBox creato a design time, abbiamo definito l’evento onCLick(), questo sarà presente anche per new_inputbox e scatterà esattamente come ci si aspetta.

Poiché però a runtime non possiamo cambiare il codice all’interno degli eventi, dobbiamo provvedere a monte ad un codice “generico”, che sia in grado di capire su quale input l’evento è scattato e comportarsi di conseguenza.

Un altro limite è che gli oggetti da clonare debbono essere già presenti sulla videata, non possiamo crearne di completamente nuovi a runtime.

Questo ci obbliga a limitare il tipo di campi input includibili nella nostra form a campi variabili, aggiungendoli a design time e duplicandoli poi alla bisogna a runtime.

Certo, possiamo caricare in una videata tutti i tipi di campi input disponibili, ma di norma è meglio arrivare ad un compromesso e includere solo quelli d’uso più frequente/probabile, facendo poi accettare questo vincolo al cliente.

Per avere un’idea di come possa funzionare una form costruita con questa tecnica, ho preparato un progetto di esempio, clone-example, che trovate tra i progetti condivisi.

Nella form presente nel progetto, all’interno dell’evento onLoad vengono creati tre campi di input di tipo testo e tre selettori Ion Toggle.

Gli elementi da cui vengono clonati sono stati aggiunti a design time e posti in stato non visibile, poiché di fatto non partecipano alla gestione della videata, sono utilizzati solo come modelli da cui generare i campi che verranno effettivamente usati.

Ogni copia viene resa visibile (per farla apparire nella videata) e posta in un array, così che sia poi semplice recuperare tutti i valori inseriti dall’utente, insieme a qualche proprietà aggiuntiva per facilitarmi la gestione.

Gli input box hanno un evento onClick che quando scatta, mostra il valore del campo su cui è stato invocato.

Cliccando sul bottone presente sul fondo della videata, vengono mostrati i valori di tutti i campi.

Notare che il valore di default degli Ion Toggle è undefined, anche se in teoria dovrebbero valere solo true o false.

Questo può essere utile per capire se l’utente ha “toccato” un toggle, ma in generale sarebbe molto più utile che di default valga false, così da dover evitare di inizializzarli noi, col rischio di dimenticarne qualcuno e ritrovarsi con valori non voluti tra le mani.

Magari in futuro ProGamma deciderà di cambiare questo comportamento predefinito.

I valori inseriti nei “campi variabili” poi li raccolgo in un oggetto JSON che salvo nel database per utilizzarli al momento della generazione del template, sostituendo i tag con i valori conservati nel JSON.

E voi come fate a gestire questo tipo di esigenze?

Farlo come ho mostrato qui è funzionale ma non particolarmente agevole, visti i limiti ed il ridotto supporto di IDC per questo tipo di compito (più che comprensibile vista la filosofia di questo strumento).

Qualcuno di voi ha trovato una via più pratica che magari ha voglia di condividere qui?

3 Mi Piace

In Foudation c’è il servizio documentale Schema estendibile. Non so se in Cloud c’è un equivalente.

Io in Inde Foundation ho creato un componente che sfrutta il FormJSON.
Quindi la possibilità di creare form variabili partendo da uno schema in JSON ed ottenere indietro i valori inseriti dall’utente come oggetto JSON da salvare sul DB o eventualmente decodificare.
Si puo’ provare qui: https://app.cavallinipietro.com/gallerycomponents/
scegliendo nel menu ADDONESTERNI → Form Dinamici da JSON

3 Mi Piace

No, purtroppo no, ma sarebbe interessante.

Questo è fantastico! @paolo.giannelli , sarebbe possibile avere qualcosa del genere anche in Cloud? Sempre se interessa anche ad altri utenti ovviamente, se sono l’unico con questa esigenza mi arrangio serenamente :grinning:

@giorba non te lo so dire coì al volo.
Quello che immagino che faccia il componente che cita @eurekapv è creare dei campi a partire da un JSON ma non so se sono campi nativi di Instant Developer Foundation quelli generati secondo me o mi sbaglio @eurekapv?

Se questo tipo di comportamento fosse molto richiesto ci si potrebbe anche pensare ad aggiungerlo come possibilità.

Ciao a tutti, beh sono campi input opportunamente formattati seguendo un tema che puo esser bootstrap o altro.
Assumono quindi un aspetto molto simile a quelli dell applicazione ospitante.
Si riesce quindi a creare campi input standard, numerici, di data ora, combobox ed altro.
Consente anche la creazione di Array con inserimento righe etc…(tabelle)

É possibile impostare metodi di validazione il tutto passando lo schema corretto che ovviamente puoi essere creato al volo in esecuzione.

Io lo uso molto quando ho molti campi che alla fine devono solo esser memorizzati ma su cui non ci son grandi elaborazioni dietro… invece che creano 50 campi sul db ne ho uno solo con il JSON dei valori.
Comunque essendo tutto javascript é possibilissimo inserirlo in Cloud.

5 Mi Piace

@eurekapv grazie del chiarimento.