GUIDA: creare un form di inserimento "orizzontale" (guida per sviluppatori)

31 contenuti / 0 new
Ultimo contenuto
GUIDA: creare un form di inserimento "orizzontale" (guida per sviluppatori)

Una delle domande più ricorrenti per gli sviluppatori di moduli di drupal è il seguente: come si crea un form su più linee? Avrete sicuramente notato che quando create un form, questo viene messo in orizzontale (tutti i campi sono allineati uno sotto l'altro). La cosa può andar bene se sono pochi campi.... ma se avessi molti campi e volessi rendere il form più bello e più usabile, disponendo i campi in verticale e orizzontale.... come faccio? Esistono alcuni sistemi per far ciò, alcuni semplici ma ingestibili alla lunga (se si modifica spesso il forum).... ma c'è un sistema molto elegante, efficace e perfettamente temizzato alla grafica da voi scelta.

Ovviamente, per allineare campi di un form in orizzontale e verticale, disponendo più campi di inserimento in orizzontale, ci serve una tabella. Noi utilizzeremo le api di drupal per disegnare la tabella e metteremo nelle celle i campi che a noi interessano.
Supponiamo di avere i seguenti campi di inserimento:
id, codice_anagrafico, cap, citta, provincia, regione, codice_anagrafico_nazione, nazione, raggruppamento_nazioni

Voglio creare un form fatto in questo modo:

codice_anagrafico
Provincia Regione CAP codice_anagrafico_nazione
nazione
raggruppamento_nazioni

Per far ciò, dobbiamo mettere il tutto in una tabella di 4 colonne X 4 righe.

Iniziamo:
1) Prepariamo la funzione che richiamerà il form (è la funzione che richiameremo dall' hook_menu)

<?php
 
function citta_inserisci() {
   
$output drupal_get_form('citta_form_inserisci_modifica',$value);
    return
$output;
}
?>

2) prepariamo la funzione in cui andremo a definire i campi. Il nome della funzione è lo stesso definito nella funzione utilizzata sopra (drupal_get_form):

<?php
 
function citta_form_inserisci_modifica($value = NULL) {
   
$form['principale']['id'] = array(
       
'#type' => 'hidden',
       
'#title' => t('id'),
       
'#value' => $value['id'],
      );
   
$form['principale']['codice_anagrafico'] = array(
       
'#type' => 'textfield',
       
'#title' => t('Codice'),
       
'#size' => 7,
       
'#maxlength' => 6,
       
'#default_value' => $value['codice_anagrafico'],
       
'#description' => t('Alfanumerico'),
      );
   
$form['principale']['cap'] = array(
       
'#type' => 'textfield',
       
'#title' => t('CAP'),
       
'#size' => 6,
       
'#maxlength' => 5,
       
'#default_value' => $value['cap'],
       
'#description' => t('cap'),
      );
   
$form['principale']['citta'] = array(
       
'#type' => 'textfield',
       
'#title' => t('Citta\''),
       
'#size' => 41,
       
'#maxlength' => 40,
       
'#default_value' => $value['citta'],
       
'#description' => t('Alfanumerico'),
      );
   
$form['principale']['provincia'] = array(
       
'#type' => 'textfield',
       
'#title' => t('Provincia'),
       
'#size' => 3,
       
'#maxlength' => 2,
       
'#default_value' => $value['provincia'],
       
'#description' => t('Sigla Prov.'),
      );
   
$form['principale']['regione'] = array(
       
'#type' => 'textfield',
       
'#title' => t('Regione'),
       
'#size' => 23,
       
'#maxlength' => 22,
       
'#default_value' => $value['regione'],
       
'#description' => t('Alfanumerico'),
      );
   
$form['principale']['codice_anagrafico_nazione'] = array(
       
'#type' => 'textfield',
       
'#title' => t('Cod An Naz'),
       
'#size' => 4,
       
'#maxlength' => 3,
       
'#default_value' => $value['codice_anagrafico_nazione'],
       
'#description' => t('Alfanumerico'),
      );
   
$form['principale']['nazione'] = array(
       
'#type' => 'textfield',
       
'#title' => t('Nazione'),
       
'#size' => 41,
       
'#maxlength' => 40,
       
'#default_value' => $value['nazione'],
       
'#description' => t('Alfanumerico'),
      );
   
$form['principale']['raggruppamento_nazioni'] = array(
       
'#type' => 'textfield',
       
'#title' => t('Ragguppamento Nazioni'),
       
'#size' => 41,
       
'#maxlength' => 40,
       
'#default_value' => $value['raggruppamento_nazioni'],
       
'#description' => t('Alfanumenrico'),
      );
    
$form['submit'] = array(
         
'#type' => 'submit',
         
'#value' => t('Conferma'),
    );
    return
$form;
}  
?>

3) Ok, fin quì nulla di strano..... Adesso dobbiamo disegnare il tutto in una tabella. Per far questo, creiamo una funzione composta da theme_ + nome del form (o se lo capite meglio, theme_ + il nome della funzione in cui son definiti i campi.... quella del punto 2). Quindi creeremo una funzione chiamata "theme_citta_form_inserisci_modifica". Questa funzione deve avere un parametro, che di fatto è l'array di definizione del form: theme_citta_form_inserisci_modifica($form).
Ora vi mostro l'intera funzione e ve la spiego sotto, passo passo:

<?php
 
function theme_citta_form_inserisci_modifica($form) {
   
$output = drupal_render($form['principale']['id']);
   
$rows[] = array(
        array(
'data' => drupal_render($form['principale']['codice_anagrafico']), 'colspan' => 4)
     );
   
$rows[] = array(
        array(
'data' => drupal_render($form['principale']['citta']), 'colspan' => 4)
     );
   
$rows[] = array(
       
drupal_render($form['principale']['provincia']),
       
drupal_render($form['principale']['regione']),
       
drupal_render($form['principale']['cap']),
       
drupal_render($form['principale']['codice_anagrafico_nazione'])
     );
   
$rows[] = array(
        array(
'data' => drupal_render($form['principale']['nazione']), 'colspan' => 4)
     );
   
$rows[] = array(
        array(
'data' => drupal_render($form['principale']['raggruppamento_nazioni']), 'colspan' => 4)
     );
   
$rows[] = array(
        array(
'data' => drupal_render($form['submit']), 'colspan' => 4)
     );
   
$output .= drupal_render($form);
   
$output .= theme('table', array(), $rows);
    return
$output;
}
?>

La funzione drupal_render, ci disegna i singoli campi del form. Nella prima riga (

<?php
 $output
= drupal_render($form['principale']['id']);
?>
) viene disegnato il campo hidden. Questo si trova fuori dalla tabella..... tanto è un campo nascosto e lo possiamo creare dove vogliamo.
Successivamente vengono create le righe della tabella. Se in una riga vogliamo mettere più campi, li elencheremo all'intrno della stessa. Quindi, nel nostro caso, la riga 2 avrà 4 campi. 4 campi corrispondono a 4 celle, quindi le righe sopra e sotto, dovranno esser composte da 1 cella con colspan=4 (
<?php
 
array('data' => drupal_render($form['submit']), 'colspan' => 4)
?>
).
Disegnato le righe, si deve disegnare tutto il restanti dati del form, con l'istruzione
<?php
 drupal_render
($form);
?>

Ok, adesso non ci resta che da temizzare la tabella, passando le linee:
<?php
 $output
.= theme('table', array(), $rows);
?>

Sembra complicato, ma vi invito a rileggere e provare.... i risultati sono notevoli.

Questo sotto è il risultato:
Image is Free Hosted By Pictiger.com

Ciao e alla prossima guida..... sono incerto tra un trucchetto per temizzare un nodo/pagina particolare o una guida per la creazione di un nuovo tipo di nodo personalizzato con nuovi campi..... boh.... vedremo quando ne ho voglia :-)

Ciao
Gianni Giusti

Ottima guida! Direi che è perfetta. Anche se io solitamente uso dei nomi in inglese per classi, funzioni e forms; ma questa è una guida italiana, e mi pare giusto così ;)

Aggiungo alla documentazione per sviluppatori.
http://www.drupalitalia.org/node/2540

Personalmente preferisco usare nomi in italiano se il modulo è ad uso e consumo interno e inglese se dev'essere pubblicata per qualsiasi persona nel mondo.
.....prima di tutto comodità per chi deve leggere il tutto :-) in questo caso, noi italiani.
E' molto più semplice ricordare un nome di funzione/variabile in italiano che in inglese ;-)

Battuto sul tempo!!

Visto che in questo periodo mi devo dare alla programmazione drupal pensavo proprio con l'occasione di scrivere anche piccoli esempi di codice che alla fine sono sempre utili
Penso che un libro sia ottimo se cresce vediamo di rappresentarlo magari ad albero o... si accettano idee!!

Penso che il primo passo è stato fatto vediamo cosa succede!!

PS: I permessi per creare documetazione dovrebbero esserci, controlla!

PS2: Psico Ripristina il file pdf della guida

Uccio wrote:
Battuto sul tempo!!
PS2: Psico Ripristina il file pdf della guida

ehm ci sono probs con FTP :P

di che tipo??

So che aruba ha rigenerato le credenziali a molti forse... anche a noi!!
Chiedi a michele

Quote:
PS: I permessi per creare documetazione dovrebbero esserci, controlla!

Se ho ben capito, gli articoli come questo andrebbero creati come "book page", sotto il libro "documentazione".... giusto?
Non ho mai usato il modulo book, spiegami una cosa: il genitore, in questo caso, si riferisce a quello che nel libro potrebbe essere un "capitolo" o un "sottocapitolo"... giusto?

Ho visto che ho i permessi di upload. Posso utilizzarlo se mi dovesse servire? (mi bastano i permessi per pdf e formato openoffice)

Ciao e grazie
Gianni

Quote:
Se ho ben capito, gli articoli come questo andrebbero creati come "book page", sotto il libro "documentazione".... giusto?
Non ho mai usato il modulo book, spiegami una cosa: il genitore, in questo caso, si riferisce a quello che nel libro potrebbe essere un "capitolo" o un "sottocapitolo"... giusto?

Si esatto. Ma ho già creato questo nodo che linka questo nodo.
http://www.drupalitalia.org/node/2541

Quote:
Ho visto che ho i permessi di upload. Posso utilizzarlo se mi dovesse servire? (mi bastano i permessi per pdf e formato openoffice)

Dovrebbero essere abilitati. Carica i file in quel nodo book, ed eventualmente qui

ciao gianni,

Ti ho eletto a redettarore e mangiatore di Api (:-))e penso che ho solo anticipato (forse per una volta) la prossima mossa dell'onnipresente 'Psico' .Collabori con il forum da un sacco di tempo ed hai sempre risposto ai post più impegnativi ed è giusto che tu possa contribuire (se hai tempo e voglia) in maniera più libera.
Con questo sei autorizzato ad allegare scrivede e rivede ciò che ti aggrada.
Se hai idee che possono rivoluzionare drupalitalia parlane nei vari forum in maniera che si sappia ciò che accadrà. Drupalitalia come sai si basa sul dialogo!!
Le modifiche dirette al core di drupal, ed ai moduli le fa solo Psico quindi rivolgiti a lui tranquillamente. Per i menu posso occuparmene anche io e fax oltre a Michele!!

Per qualunque problema siamo qui accanto a te!! :P

Ciao Uccio

... Ops

Secondo me la documentazione nel libro è più fruibile quindi cosa ne pensate se per esempio qusta guida la spostiamo poi interamete come pagina??
In sostanza credo che la documetazione nasca nel forum e poi magari elaborata possa finire nel libro!!

Cosa ne pensate??

Uccio wrote:
ciao gianni,
Ti ho eletto a redettarore e mangiatore di Api (:-))e penso che ho solo anticipato (forse per una volta) la prossima mossa dell'onnipresente 'Psico' .[cut....]
Per qualunque problema siamo qui accanto a te!! :P
Ciao Uccio

Avevo notato un incremento notevole di iconcine, vicino al mio nick :-)
Che dire.... sono molto onorato (veramente, non è una frase di circostanza).

Per quanto riguarda il libro, condivido la tua idea

P.S.
Per qualche giorno sarò assente perchè me ne vado in vacanza..... quindi non vi preoccupate, non sono scappato :-) . Ci risentiamo Sabato o Domenica.

Ciao e grazie ancora
Gianni

In parte concordo con Uccio. Cerco di elencare i vantaggi/svantaggi delle due scelte

Ricopiare/ridefinire la guida sul book ha il notevole vantaggio di non creare link da seguire per leggere la guida. In modo che eventualmente possa essere inclusa in futuro in un pdf. Ottimo.

Purtroppo duplicare i contenuti non è mai un'ottima idea, sia per questioni SEO (una delle due pagine è possibile che scompaia dall'indice di Google), sia perchè una delle due potrebbe restare indietro, e diventa necessario aggiornarle entrambe (e carichiamo di lavoro gianni :P).

Ovviamente propenderei per la prima, sempre se chi cura la Doc ha voglia di tenere entrambe le versioni aggiornate.
Ah, uccio che ne pensi di inserire quel modulo doc-book, di cui è stato fatto il porting per 5.x?

Psicomante wrote:
e diventa necessario aggiornarle entrambe (e carichiamo di lavoro gianni :P).

....mi sa tanto che ci ho ripensato... forse ha ragione Psicomante :-P

Ciao
Gianni

giannigiusti wrote:
Psicomante wrote:
e diventa necessario aggiornarle entrambe (e carichiamo di lavoro gianni :P).

....mi sa tanto che ci ho ripensato... forse ha ragione Psicomante :-P

Ciao
Gianni

Riesco proprio a convincere tutti allora. Adesso provo al contrario.

"Tranquillo gianni, se qualcuno se ne accorge, modifica le tue guide. In ogni caso potremmo mettere link incrociati così da eventualmente risolvere il problema della de-sincronizzazione".

Ora? :)

Quote:
. quindi non vi preoccupate, non sono scappato Smiling

meno male!!

Buona vacanza

... per quando torni :-P

ho appena provato la guida ma non riesco a far eseguire la funzione theme il codice del mini modulo di prova è:

<?php
 
function page_example_menu($may_cache) {
 
$items = array();
  if (
$may_cache) {
   
$items[] = array('path' => 'foo', 'title' => t('foo'),
     
'callback' => 'page_example_test',
     
'access' => user_access('access foo'));
  }
  return
$items;
}
function
page_example_test() {
 
$content = '<p>Proviamo i form.</p>';
 
$content .= drupal_get_form('page_example_form');
  return
$content;
}
function
theme_page_example_form($forms)
    {
    
$output = "ciao sono il tema";
    
$rows[] = array(
        array(
'data' => drupal_render($form['findpeople']),
               
drupal_render($form['submit'])));
   
$output .= drupal_render($form);
   
$output .= theme('table', array(), $rows);
    }
function
page_example_form() {
 
$form = array();
 
$form['findpeople'] = array(
   
'#type' => 'textfield',
   
'#required' => FALSE,
   
'#size' => 15,
   
'#description' => t(''),
   
'#weight'=> 1,  );
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => t('Search'),
      
'#weight'=> );
  return
$form;
}
 
?>

l'obbiettivo era creare una serch box lineare ma .... ci sono dei problemi

Non ho tempo per provarlo... vado a nanna e domani parto. Però, al volo noto un errore nella function theme_page_example_form($forms):

Tu scrivi:

<?php
      $rows
[] = array(
        array(
'data' => drupal_render($form['findpeople']),
               
drupal_render($form['submit'])));
?>

Ma corretta è:

<?php
      $rows
[] = array(
       
drupal_render($form['findpeople']),
       
drupal_render($form['submit'])
        );
?>

Quello che tu hai fatto è il caso in cui devi passare dei dati e dei parametri... esempio:

<?php
 
array('data' => drupal_render($form['principale']['citta']), 'colspan' => 4)
?>

in questo caso come 'data' (ossia i dati che vanno nella cella), viene passato la temizzazione del campo citta, poi viene passato un parametro che si chiama 'colspan' che provvede a fare la cella unita.
Nel tuo caso, devi semplicemente mettere i campi temizzati in 2 celle, senza alcuna proprietà per la cella. Provalo e fammi sapere.

P.S.
Se non funziona mandami un messaggio privato perchè tra 5/6 giorni, quando torno, non so se riesco a leggere tutti i post passati

Ciao
Gianni

Non preoccuparti,

Conto di lavorarci un po su!!
Scrivo in maniera che i problemi e dubbi rimangano tracciati per i posteri!! compreso io!

Grazie

Uccio wrote:
Non preoccuparti,
Conto di lavorarci un po su!!
Scrivo in maniera che i problemi e dubbi rimangano tracciati per i posteri!! compreso io!
Grazie

Traccia traccia che è meglio va :D

Ciao, come soluzione ai campi allineati sulla stessa linea, è possibile agire anche tramite CSS, utilizzando le tecniche di display (http://www.quirksmode.org/css/display.html)

Per esempio l'ho utilizzata per la gestione degli inserimenti delle date tramite select multipli..

Ciao

thePanz wrote:
Ciao, come soluzione ai campi allineati sulla stessa linea, è possibile agire anche tramite CSS, utilizzando le tecniche di display (http://www.quirksmode.org/css/display.html)

Per esempio l'ho utilizzata per la gestione degli inserimenti delle date tramite select multipli..

Ciao

La cosa mi interessa parecchio, come hai gestito le date con select multiple?

Nel modulo DateAPI il display degli input è già attivato in modo "inline":

.container-inline-date {width:auto; clear:both;}
.container-inline-date .form-item {float:left; padding:0; margin:0}
.container-inline-date .form-item, .container-inline-date .form-item input {width:auto;}
.container-inline-date .description {clear: both;}
.container-inline-date .form-item input, .container-inline-date .form-item select {margin-right:.5em;}
.container-inline-date {
  display: -moz-inline-block;
  display: -moz-inline-box;
  display: inline-block;
}

Quello che ho aggiunto io (linee con -moz-*) è la possibilità (nei browser decenti) di affiancare i box di inserimento di due date (quando il campo date è impostato per permettere un data-inizio e data-fine)..

Prova a dare un occhio al date.css del modulo DateAPI!

Ciao!

thePanz wrote:
Ciao, come soluzione ai campi allineati sulla stessa linea, è possibile agire anche tramite CSS, utilizzando le tecniche di display (http://www.quirksmode.org/css/display.html)

Per esempio l'ho utilizzata per la gestione degli inserimenti delle date tramite select multipli..

Ciao

La cosa mi interessa parecchio, come hai realizzato la data a select multipli?

Caro Gianni, ho letto il tuo manuale e ti ringrazio per le preziose informazioni che ne ho ricavato.
Mi è rimasto tuttavia un problema attinente alla strutturazione visuale del form.
Una volta costruita la riga orizzontale, nel modo che tu ci hai mostrato, non riesco a farla correttamente rientrare nel box del fieldset come invece avviene correttamente per i campi di input lasciati fluire in verticale.
E possibile ottenere anche quel risultato?
Mi farebbe immensamente comodo.
Io uso la versione 5.x.
Grazie dell'attenzione.

Ciao Emanuele01,
il mio esempio, era il modo più semplice per ottenere il form orizzontale e serviva come esempio. Adesso che hai capito il sistema, puoi raffinarlo con questa tecnica:
1) nella definizione del fildset, aggiungi anche la voce

'#theme' => 'citta_group',

Tipo:

<?php
     $form
['principale'] = array(
       
'#type' => 'fieldset',
       
'#theme' => 'citta_group',
      );
?>

a seguire la definizione dei campi del fieldset

In questo modo, il gruppo di campi appartenente al fieldset "principale", verranno temizzati dalla funzione "theme_citta_group" (notare il nome: citta_group, definito in #theme + la scritta theme_).

2) Fai la funzione "theme_citta_group" in temizzi quel gruppo specifico

Tipo:

<?php
 
function theme_citta_group($form) {
 
$row = array();
  foreach (
element_children($form) as $key) {
   
array_push($row, drupal_render($form[$key]));
  }
 
$rows[] = array('data' => $row);
 
$output .= theme('table', array(), $rows);
  return
$output;
}
?>

Nel caso specifico sopra, c'è un ciclo che non fa altro che prendere i singoli elementi del gruppo e li temizza in una tabella, restituendoli al form

3) facendo il sistema sopra, non ti serve la funzione "theme_citta_form_inserisci_modifica" del mio esempio.... anzi, la devi eliminare e temizzare gruppo per gruppo

Questo sistema dovrebbe rimediare anche al tuo problema.

p.s.
......difficile spiegare in poche righe..... spero comunque di averti fatto capire la strada che dovresti seguire

Ciao
Gianni

Grazie Gianni, ero sicuro che avevi la soluzione!
Ora però mi chiedo (l'appetito vien mangiando!) se, avemdo da codificare una tabella a più righe, si debba costruire un fieldset per ogni riga o se esista un sistema più semplice.
Scusa se ti interpello ancora ma sai com'è, quando si affonda si bada soprattutto ad arrivare a riva.
Grazie ancora
Emanuele

puoi anche usare il theming del form (ti consiglio una lettura sull'handbook) per avere proprio una tabella con campi da un parte e label dall'altra.. ma non è bellissima come soluzione, IMHO meglio giocare con i CSS in questo caso.

Ciao
Marco
--
My blog
Working at @agavee

EMAnuele01 wrote:

Ora però mi chiedo (l'appetito vien mangiando!) se, avemdo da codificare una tabella a più righe, si debba costruire un fieldset per ogni riga o se esista un sistema più semplice.

La soluzione più semplice è quella di dividere le "righe" (i campi che vuoi mettere in orizzontale) mettendo un tipo markup (che non risulterà visibile, ma lo userai per creare dei gruppi, ossia le tue righe).... lo usi allo stesso modo del fieldset:

<?php
   $form
['riga1'] = array(
   
'#type' => 'markup',
   
'#theme' => 'disegna_group',
  );
?>

poi metti tutti qui campi della riga, ovviamente definiti typo:
$form['riga1']['nome'] = array(.... ecc... ecc...

fai la riga due:

<?php
   $form
['riga2'] = array(
   
'#type' => 'markup',
   
'#theme' => 'disegna_group',
  );
$form['riga2']['nome'] = array(.... ecc... ecc...
?>

e così via, per ogni riga che contiene N campi (ovviamente per le righe ad un solo campo, non devi farlo)

poi metti la tua bella funzione:

<?php
 
function theme_disegna_group($form) {
 
$row = array();
  foreach (
element_children($form) as $key) {
   
array_push($row, drupal_render($form[$key]));
  }
 
$rows[] = array('data' => $row);
 
$output .= theme('table', array(), $rows);
  return
$output;

?>

che provvede a disegnare le varie righe (tutte le tue righe passeranno da lì)

Perfezionando ulteriormente, nella definizione dei '#type' => 'markup' e '#type' => 'fieldset', aggiungi anche il "peso" ('#weight' => -10) variando il -10, con la posizione in cui vuoi mostrare la riga, rispetto al form. In questo modo, potrai facilmente spostere le righe a tuo piacimento.

Se vuoi strafare, puoi anche definire la class nella tabella, in modo che poi potrai persino temizzare le tabelle nei css, aggiungendo, nell'array delle $rows[] 'class'=>'nomedellaclassechevuoi'

Diciamo che la soluzione genera un po' di tabelle.... ovviamente, agendo sui css, redi le tabelle non visibili (ne righe, ne sfondo) e tanti saluti.... ecco il tuo bel form preciso e perfetto, pronto a fare la sua bella figura :-)

P.S.
e' già da un po' che non uso drupal 5.... quindi potrei anche avere sbagliato qualche parametro di funzione. L'importante è che tu abbia capito il sistema :-)

Ciao
Gianni

Ci terrei solo a precisare (scusa, ma in questo sono abbastanza fissato) ceh el tabelle servono presentare dati in forma tabulare, non a creare layout di form & simili, quindi è preferibile agire tramite CSS, per esempio impostando per i label e campi vari luna larghezza prefissata e disponendoli inline, non che il risultato di gianni sia sbagliato!

PS: oggi ho inviato la prima patch per D7, D6 mi sa che lo salterò a piè pari :P

Ciao
Marco
--
My blog
Working at @agavee

mavimo wrote:
Ci terrei solo a precisare (scusa, ma in questo sono abbastanza fissato)

La penso esattamente come te (ne abbiamo parlato anche altre volte).
Ovviamente, la tecnica si riferisce ai casi in cui l'importanza della presentazione a video del form, è più importante delle regole di accessibilità: applicazioni interne (gestionali), siti personali, siti aziendali, form riservati ad un numero ben delimitato di persone ecc...

Ciao
Gianni

ok tutto bellissimo, ma dove scrivo quei codici?