Development

Documentation/it_IT/book/1.1/11-Ajax-Integration (diff)

You must first sign up to be able to contribute.

Changes from Version 1 of Documentation/it_IT/book/1.1/11-Ajax-Integration

Show
Ignore:
Author:
garak (IP: 83.103.98.10)
Timestamp:
10/22/08 14:51:06 (9 years ago)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/it_IT/book/1.1/11-Ajax-Integration

    v0 v1  
     1{{{ 
     2#!WikiMarkdown  
     3 
     4Capitolo 11 - Integrazione di Ajax 
     5================================== 
     6 
     7Le interazioni lato client, complicati effetti visuali e comunicazioni asincrone sono comuni in applicazioni web 2.0. Ognuna di tali interazioni necessita JavaScript, ma scrivere le funzioni a mano risulta spesso noioso e lungo da debuggare. Fortunatamente, symfony automatizza tramite un set di helper diverse fra le piu' comuni funzioni utilizzate nei template. Alcuni comportamenti lato client possono addirittura essere realizzati senza alcuna linea di codice JavaScript. Lo sviluppatore si deve solo preoccupare dell'effetto che vuole realizzare, e symfony gestirà le problematiche di sintassi e di compatibilità. 
     8 
     9Questo capitolo descrive gli strumenti inclusi in symfony per facilitare lo scripting lato client: 
     10  
     11  * Gli helper JavaScript di base stampano in output tag `<script>` rispettosi degli standard, per aggiornare il DOM (Document Object Model) o per chiamare degli script tramite link. 
     12  * Prototype è una libreria JavaScript integrata in symfony, che velocizza lo sviluppo lato client aggiungendo nuovi metodi e funzioni al core JavaScript. 
     13  * Gli helper Ajax permettono all'utente di aggiornare parti di una pagina cliccando un link, inviando una form o modificandone un elemento. 
     14  * Le diverse opzioni di questi helper forniscono anche grande flessibilità e potenza, grazie all'utilizzo di funzioni di callback. 
     15  * Script.aculo.us è un'altra libreria JavaScript, anch'essa integrata in symfony, che aggiunge effetti visuali dinamici e migliora l'interfaccia e la fruibilità. 
     16  * JavaScript Object Notation (JSON) è uno standard usato per la comunicazione tra uno script server ed uno client. 
     17  * Complicate interazioni lato client sono possibili in applicazioni symfony combinando le tecnologie appena menzionate. Auto-completamento, drag-and-drop, liste ordinabili e testo modificabile sono implementabili con una singola linea di PHP, ovvero una chiamata ad un helper di symfony. 
     18 
     19Helper JavaScript di base 
     20------------------------- 
     21 
     22Per un lungo tempo JavaScript ha avuto poca considerazione in applicazioni web professionali, a causa della mancanza di compatibilità cross-browser. Ad oggi, i problemi di compatibilità sono per la maggior parte risolti, ed alcune robuste librerie permettono di scrivere interazioni JavaScript complesse senza perdere ore in debug e centinaia di linee di codice. La tecnica piu' avanzata si chiama Ajax, che sarà discussa nella sezione "Helper Ajax" piu' avanti in questo capitolo. 
     23 
     24Paradossalmente, vedrai poche linee di codice JavaScript in questo capitolo. Questo perché symfony ha un approccio molto originale allo scripting lato client: esso pacchettizza ed astrae comportamenti JavaScript in helper, per cui alla fine le tue template non conterranno codice JavaScript. Per uno sviluppatore aggiungere un behavior ad un elemento della pagina significa scrivere una linea di codice PHP; ma tale chiamata naturalmente genera codice JavaScript in output, la cui complessità risulterà chiara nei sorgenti della pagina generata. Gli helper gestiscono le problematiche di consistenza del browser, complessi casi limite e così via, per cui l'ammontare di codice JavaScript che contengono può diventare assai importante. Ad ogni modo, il presente capitolo ti insegnerà come non utilizzare codice JavaScript per raggiungere effetti che di solito necessitano la scrittura di JavaScript. 
     25 
     26Tutti gli helper descritti nel seguito sono disponibili nei template, a patto di dichiarare l'utilizzo del gruppo di helper `Javascript`: 
     27 
     28    [php] 
     29    <?php use_helper('Javascript') ?> 
     30 
     31Come imparerai a breve, alcuni di questi helper stampano in output codice HTML, altri codice JavaScript. 
     32 
     33### JavaScript nei template 
     34 
     35In XHTML, i blocchi di codice JavaScript devono essere racchiusi in dichiarazioni CDATA. Ma le pagine che richiedono molti blocchi di codice JavaScript possono diventare noiose da scrivere. Ecco perché symfony mette a disposizione l'helper `javascript_tag()`, che trasforma una stringa in un tag `<script>` rispondente ai requisiti XHTML. Il Listato 11-1 ne mostra un esempio. 
     36 
     37Listato 11-1 - Includere JavaScript tramite l'helper `javascript_tag()` 
     38 
     39    [php] 
     40    <?php echo javascript_tag(" 
     41      function foobar() 
     42      { 
     43      ... 
     44      } 
     45    ") ?> 
     46     => <script type="text/javascript"> 
     47        //<![CDATA[ 
     48          function foobar() 
     49          { 
     50            ... 
     51          } 
     52        //]]> 
     53        </script> 
     54 
     55Ma l'utilizzo piu' comune di JavaScript, più che pezzi di codice, sono gli hyperlink che attivano altri script. L'helper `link_to_function()` fa esattamente questo, come mostrato nel Listato 11-2. 
     56 
     57Listato 11-2 - Attivare un link JavaScript tramite l'helper `link_to_function()` 
     58 
     59    [php] 
     60    <?php echo link_to_function('Click me!', "alert('foobar')") ?> 
     61     => <a href="#" onClick="alert('foobar'); return none;">Click me!</a> 
     62 
     63Come per l'helper `link_to()`, puoi aggiungere opzioni come terzo argomento al tag `<a>`. 
     64 
     65>**NOTE** 
     66>Esattamente come l'helper `link_to()` ha un fratello `button_to()`, puoi attivare JavaScript tramite un pulsante (`input type="button"`) chiamando l'helper `button_to_function()`. E se preferisci una immagine cliccabile, chiama `link_to_function(image_tag('myimage'), "alert('foobar')")`. 
     67 
     68### Aggiornare un elemento DOM 
     69 
     70Un task comune nelle interfacce dinamiche è l'aggiornamento di un elemento della pagina. Si tratta di qualcosa che di solito scrivi come nel Listato 11-3. 
     71 
     72Listato 11-3 - Aggiornare un elemento in JavaScript 
     73 
     74    [php] 
     75    <div id="indicator">Data processing beginning</div> 
     76    <?php echo javascript_tag(" 
     77      document.getElementById("indicator").innerHTML = 
     78        "<strong>Data processing complete</strong>"; 
     79    ") ?> 
     80 
     81Symfony fornisce un helper che produce codice JavaScript, non HTML, a tale scopo, e si chiama `update_element_function()`. Il Listato 11-4 ne mostra l'utilizzo. 
     82 
     83Listato 11-4 - Aggiornare un elemento in JavaScript tramite l'helper `update_element_function()` 
     84 
     85    [php] 
     86    <div id="indicator">Data processing beginning</div> 
     87    <?php echo javascript_tag( 
     88      update_element_function('indicator', array( 
     89        'content'  => "<strong>Data processing complete</strong>", 
     90      )) 
     91    ) ?> 
     92 
     93Ti potresti chiedere per quale motivo questo helper è utile, in quanto la lunghezza del codice è la stessa che scrivere JavaScript a mano. Si tratta in effetti di una questione di leggibilita'. Ad esempio, potresti voler inserire contenuto prima o dopo un elemento, o rimuoverlo invece di aggiornarlo, o anche non fare niente sotto certe condizioni. In tali casi, il codice JavaScript si complica in qualche modo, ma `update_element_function()` mantiene il template molto leggibile, come mostrato dal Listato 11-5. 
     94 
     95Listato 11-5 - Opzioni dell'helper `update_element_function()` 
     96 
     97    [php] 
     98    // Inserire contenuto subito dopo l'elemento 'indicator' 
     99    update_element_function('indicator', array( 
     100      'position' => 'after', 
     101      'content'  => "<strong>Data processing complete</strong>", 
     102    )); 
     103 
     104    // Rimuovere l'elemento prima di 'indicator', e solo se $condition è vera 
     105    update_element_function('indicator', array( 
     106      'action'   => $condition ? 'remove' : 'empty', 
     107      'position' => 'before', 
     108    )) 
     109 
     110Gli helper rendono le tue template facili da leggere, e tu hai una sintassi univoca per behavior simili. Questo è anche il motivo per cui i nomi degli helper sono così lunghi: rendono il codice sufficientemente chiaro da non necessitare altri commenti. 
     111 
     112### Degradazione scalabile 
     113 
     114Il tag `<noscript>` ti permette di specificare codice HTML visibile solo ai browser senza supporto JavaScript. Symfony fornisce un helper che lavora nel modo opposto: specifica codice visibile solo ai browser che supportano JavaScript. Gli helper `if_javascript()` e `end_if_javascript()` facilitano la creazione di applicazioni con degradazione scalabile, come dimostrato dal Listato 11-6. 
     115 
     116Listato 11-6 - Utilizzare l'helper `if_javascript()` per permettere degradazione scalabile 
     117 
     118    [php] 
     119    <?php if_javascript(); ?> 
     120      <p>You have JavaScript enabled.</p> 
     121    <?php end_if_javascript(); ?> 
     122 
     123    <noscript> 
     124      <p>You don't have JavaScript enabled.</p> 
     125    </noscript> 
     126 
     127>**NOTE** 
     128>Non c'è bisogno di utilizzare `echo` con gli helper `if_javascript()` e `end_if_javascript()`. 
     129 
     130Prototype 
     131--------- 
     132 
     133Prototype è una grande libreria JavaScript che estende le possibilità dello scripting lato client, aggiunge quelle funzioni mancanti di cui hai sempre sognato ed offre nuovi meccanismi per la manipolazione del DOM. Il sito del progetto è [http://prototypejs.org/]. 
     134 
     135Il file di Prototype sono inclusi in symfony ed accessibili da ogni progetto nella cartella `web/sf/prototype/`. Ciò significa che puoi usare Prototype inserendo il seguente codice alla tua azione: 
     136 
     137    [php] 
     138    $prototypeDir = sfConfig::get('sf_prototype_web_dir'); 
     139    $this->getResponse()->addJavascript($prototypeDir.'/js/prototype'); 
     140 
     141o, più semplicemente, includendolo nel file `view.yml`: 
     142 
     143    all: 
     144      javascripts: [%SF_PROTOTYPE_WEB_DIR%/js/prototype] 
     145 
     146>**NOTE** 
     147>Dato che gli helper Ajax di symfony, descritti nella prossima sezione, sono basati su Prototype, tale libreria viene inclusa automaticamente qualora tu utilizzi uno di essi. Ciò significa che non hai bisogno di includere manualmente Prototype se la tua template chiama almeno uno degli helper `_remote`. 
     148 
     149Una volta che la libreria Prototype è caricata, puoi avvantaggiarti di tutte le nuove funzioni che essa aggiunge al core di JavaScript. Tali funzioni esulano dallo scopo del presente libro, ma puoi trovare molta documentazione su Internet, inclusi i seguenti siti: 
     150 
     151  * Particletree: [[http://particletree.com/features/quick-guide-to-prototype/]] 
     152  * Sergio Pereira: [[http://www.sergiopereira.com/articles/prototype.js.html]] 
     153  * Script.aculo.us: [[http://wiki.script.aculo.us/scriptaculous/show/Prototype]] 
     154 
     155Una delle funzioni che Prototype aggiunge a JavaScript è il dollaro `$()`. Fondamentalmente questa funzione è solo un alias di `document.getElementById()`, ma un po' più potente. Vedi il Listato 11-7 per un esempio del suo utilizzo. 
     156 
     157Listato 11-7 - Uso della funzione `$()` per recuperare un ID in JavaScript 
     158 
     159    [php] 
     160    node = $('elementID'); 
     161 
     162    //  È lo stesso di 
     163    node = document.getElementById('elementID'); 
     164 
     165    // Può recuperarne anche due allo stesso tempo 
     166    // E in questo caso il risultato è un array di elementi DOM 
     167    nodes = $('firstDiv', 'secondDiv'); 
     168 
     169Prototype fornisce anche una funzione di cui si sente veramente la mancanza nel core JavaScript, la quale restituisce un array di tutti gli elementi che appartengono alla classe passata come argomento: 
     170 
     171    [php] 
     172    nodes = document.getElementByClassName('myclass'); 
     173 
     174Comunque la userai di rado, perché Prototype fornisce anche un'altra utilissima funzione chiamata doppio dollaro, `$$()`. Tale funzione restituisce un array di elementi DOM basati su un selector CSS. Per cui la funzione precedente puo' essere riscritta: 
     175 
     176    [php] 
     177    nodes = $$('.myclass'); 
     178 
     179Grazie alla potenza del selector CSS, puoi fare il parsing del DOM per classe, ID e relazioni genitore-figlio o precedente-seguente ancora piu' facilmente di come faresti usando un'espressione XPath. Puoi anche accedere ad elementi con selettori complicati: 
     180 
     181    [php] 
     182    nodes = $$('body div#main ul li.last img > span.legend'); 
     183 
     184Un ultimo esempio dei miglioramenti della sintassi forniti da Prototype è l'iteratore per ogni array. Fornisce la stessa concisione possibile in PHP, aggiunta alla capacita' di definire funzioni anonime e chiusure in JavaScript. Probabilmente la userai molto se scrivi codice JavaScript a mano. 
     185 
     186    [php] 
     187    var vegetables = ['Carrots', 'Lettuce', 'Garlic']; 
     188    vegetables.each(function(food) { alert('I love ' + food); }); 
     189 
     190Dato che programmare in JavaScript con Prototype è molto più divertente che farlo a mano, e dato che essa fa già parte di symfony, dovresti veramente passare un po' di tempo a leggere la documentazione relativa. 
     191 
     192Helper Ajax 
     193----------- 
     194 
     195Che succede se volessi aggiornare un elemento della pagina, non come nell'esempio 11-5 ma tramite uno script PHP eseguito sul server? Questo ti darebbe la possibilità di cambiare parte della pagina dopo una risposta del server. L'helper `remote_function()` serve esattamente a questo, come dimostrato dal Listato 11-8. 
     196 
     197Listato 11-8 - Usare l'helper `remote_function()` 
     198 
     199    [php] 
     200    <div id="myzone"></div> 
     201    <?php echo javascript_tag( 
     202      remote_function(array( 
     203        'update'  => 'myzone', 
     204        'url'     => 'mymodule/myaction', 
     205      )) 
     206    ) ?> 
     207 
     208>**NOTE** 
     209>Il parametro `url` puo' contenere sia una URI interna (`module/action?key1=value1&...`) sia il nome di una regola di routing, come per `url_for()`. 
     210 
     211Quando chiamato, questo script aggiornerà l'elemento con id `myzone` con la risposta o la richiesta dell'azione `mymodule/myaction`. Questo tipo di interazione è chiamato Ajax, ed è il cuore delle applicazioni web altamente interattive. Ecco come viene descritto da Wikipedia (http://en.wikipedia.org/wiki/AJAX): 
     212 
     213Ajax makes web pages feel more responsive by exchanging small amounts of data with the server behind the scenes, so that the entire web page does not have to be reloaded each time the user makes a change. This is meant to increase the web page's interactivity, speed, and usability. 
     214 
     215Ajax si basa su `XMLHttpRequest,`, un oggetto JavaScript che si comporta come un frame nascosto, che puoi aggiornare con la risposta di un server e riutilizzare per manipolare il resto della tua pagina. Si tratta di un oggetto abbastanza a basso livello, e browser diversi lo gestiscono in maniera diversa, per cui gestire richieste Ajax manualmente comporterebbe scrivere montagne di codice. Fortunatamente, Prototype incapsula tutto il codice necessario in un semplice oggetto Ajax, sul quale si basa symfony; ecco perché Prototype viene caricata automaticamente quando si usano helper Ajax nei template. 
     216 
     217>**CAUTION** 
     218>Gli helper Ajax non funzioneranno se la URL dell'azione remota non appartiene allo stesso dominio della pagina che la chiama. Questa restrizione esiste per questioni di sicurezza, e si basa su limitazioni del browser che non possono essere bypassate. 
     219 
     220Una interazione Ajax è composta da tre parti: un chiamante (link, pulsante, form, o qualsiasi altro tipo di elemento utilizzabile dall'utente per chiamare un'azione), un'azione del server ed una zona nella pagina in cui visualizzare la risposta di tale azione. Puoi anche costruire interazioni piu' complesse se i dati restituiti dal server devono a loro volta essere manipolati da JavaScript. Symfony dispone di diversi helper per inserire interazioni Ajax nelle tue template, tutti contenenti la parola `remote` nel proprio nome. Inoltre condividono tutti la stessa sintassi, ovvero un array associativo di parametri. Fai attenzione al fatto che gli helper potrebbe stampare in output codice HTML oppure JavaScript. 
     221 
     222>**SIDEBAR** 
     223>E le azioni Ajax? 
     224> 
     225>Le azioni chiamate come funzioni remote sono azioni normali. Esse seguono il routing, possono determinare quale vista renderizzare tramite la propria `return`, ed alterare il modello, proprio come le altre azioni. 
     226> 
     227>Comunque, quando chiamate tramite Ajax, le azioni restituiscono `true` alla seguente chiamata: 
     228> 
     229>     [php] 
     230>     $isAjax = $this->getRequest()->isXmlHttpRequest(); 
     231> 
     232>Symfony sa se un'azione si trova in un contesto Ajax, e può conseguentemente adattare la risposta. Perciò, per default, le azioni Ajax non includono la web debug toolbar nell'ambiente di sviluppo. Inoltre evitano il processo di decoration (ovvero le loro template non vengono incluse per default in un layout). Se vuoi avere una vista Ajax decorata, devi specificare `has_layout: true` nel file `view.yml` per tale vista. 
     233> 
     234>Dato che il tempo di risposta è cruciale per interazioni Ajax, se la risposta non è troppo complicata, sarebbe meglio evitare di creare una vista e restituire il risultato direttamente dall'azione. Cosi' puoi usare il metodo `renderText()` nell'azione per evitare il template e velocizzare la richiesta Ajax. 
     235> 
     236>**Novità in symfony 1.1**: la maggior parte delle azioni Ajax finiscono in una template che non fa altro che includere un partial, in quanto il codice della risposta Ajax è già usato per visualizzare la pagina iniziale. Per evitare di creare una template solo per una linea di codice, l'azione può usare il metodo `renderPartial()`. Questo metodo si avvantaggia sia della riusabilità dei partial, che delle loro capacità di caching, nonchè della velocità del metodo `renderText()`. 
     237> 
     238>     [php] 
     239>     public function executeMyAction() 
     240>     { 
     241>       // fai le cose 
     242>       return $this->renderPartial('mymodule/mypartial'); 
     243>     } 
     244> 
     245 
     246### Link Ajax 
     247 
     248I link Ajax costituiscono una grande parte delle interazioni in applicazioni web 2.0. L'helper `link_to_remote()` stampa in output un link che chiama, non sorprendentemente, una funzione remota. La sintassi è molto simile a quella di `link_to()` (a parte il secondo parametro, che in questo caso è un array associativo di opzioni Ajax), come mostrato nel Listato 11-9. 
     249 
     250Listato 11-9 - Link Ajax tramite l'helper `link_to_remote()` 
     251 
     252    [php] 
     253    <div id="feedback"></div> 
     254    <?php echo link_to_remote('Delete this post', array( 
     255        'update' => 'feedback', 
     256        'url'    => 'post/delete?id='.$post->getId(), 
     257    )) ?> 
     258 
     259In questo esempio, cliccando sul link `'Delete this post'`, verra' eseguita in background l'azione `post/delete`. La risposta restituita dal server sara' collocata nell'elemento con `id feedback`. Questo processo è illustrato in Figura 11-1. 
     260 
     261Figura 11-1 - Eseguire un aggiornamento remoto tramite un hyperlink 
     262 
     263![Eseguire un aggiornamento remoto tramite un hyperlink 
     264](http://www.symfony-project.org/images/book/1_0/F1101.png "Eseguire un aggiornamento remoto tramite un hyperlink 
     265") 
     266 
     267Come mostrato dal Listato 11-10, puoi usare un'immagine invece di una stringa per eseguire il link, sostituire la URL con una regola di routing ed aggiungere opzioni al tag `<a>` come terzo argomento. 
     268 
     269Listato 11-10 - Opzioni per l'helper `link_to_remote()` 
     270 
     271    [php] 
     272    <div id="emails"></div> 
     273    <?php echo link_to_remote(image_tag('refresh'), array( 
     274        'update' => 'emails', 
     275        'url'    => '@list_emails', 
     276    ), array( 
     277        'class'  => 'ajax_link', 
     278    )) ?> 
     279 
     280### Form Ajax-driven 
     281 
     282Le form web tipicamente chiamano un'altra azione, ma questo genera il refresh della pagina. La corrispondente di `link_to_function()` per una form sarebbe l'aggiornamento di un solo elemento della pagina con la risposta del server, ovvero l'helper `form_remote_tag()`, la cui sintassi è mostrata dal Listato 11-11. 
     283 
     284Listato 11-11 - Form Ajax con l'helper `form_remote_tag()` 
     285 
     286    [php] 
     287    <div id="item_list"></div> 
     288    <?php echo form_remote_tag(array( 
     289        'update'   => 'item_list', 
     290        'url'      => 'item/add', 
     291    )) ?> 
     292      <label for="item">Item:</label> 
     293      <?php echo input_tag('item') ?> 
     294      <?php echo submit_tag('Add') ?> 
     295    </form> 
     296 
     297L'helper `form_remote_tag()` apre un tag `<form>`, proprio come `form_tag()`. Facendo la submit di tale form verra' chiamata in POST l'azione `item/add` in background, con il campo `item` come parametro di richiesta. La risposta sostituira' il contenuto dell'elemento `item_list`, come illustrato in Figura 11-2. Chiudi una form Ajax con il semplice tag di chiusura `</form>`. 
     298 
     299Figura 11-2 - Eseguire un aggiornamento remoto tramite form 
     300 
     301![Eseguire un aggiornamento remoto tramite form](http://www.symfony-project.org/images/book/1_0/F1102.png "Eseguire un aggiornamento remoto tramite form") 
     302 
     303>**CAUTION** 
     304>Le form Ajax non possono essere multipart, a causa di una limitazione dell'oggetto `XMLHttpRequest`. Cio' significa che non si possono gestire upload di file tramite form Ajax. Ad ogni modo, c'è un modo per aggirare questa limitazione, ad esempio utilizzando un `iframe` nascosto invece di `XMLHttpRequest` (ne puoi trovare un'implementazione su <a href="http://www.air4web.com/files/upload/">http://www.air4web.com/files/upload/</a>). 
     305 
     306Se vuoi permettere ad una form di lavorare in entrambe le modalita', ossia "page mode" ed "Ajax mode", la soluzione migliore è quella di utilizzare una form normale ma con un pulsante (`<input type="button" />`) che faccia la submit in Ajax. Symfony chiama tale pulsante `submit_to_remote()`. Questo aiuta a creare form Ajax con degradazione scalabile. Vedi un esempio nel Listato 11-12. 
     307 
     308Listato 11-12 - Form normale con submit in Ajax 
     309 
     310    [php] 
     311    <div id="item_list"></div> 
     312    <?php echo form_tag('@item_add_regular') ?> 
     313      <label for="item">Item:</label> 
     314      <?php echo input_tag('item') ?> 
     315      <?php if_javascript(); ?> 
     316        <?php echo submit_to_remote('ajax_submit', 'Add in Ajax', array( 
     317            'update'   => 'item_list', 
     318            'url'      => '@item_add', 
     319        )) ?> 
     320      <?php end_if_javascript(); ?> 
     321      <noscript> 
     322        <?php echo submit_tag('Add') ?> 
     323      </noscript> 
     324    </form> 
     325 
     326Un altro esempio di utilizzo combinato di tag submit normali ed Ajax è una form che modifica un articolo. Puo' offrire un pulsante di anteprima in Ajax ed uno di pubblicazione che esegue una submit normale. 
     327 
     328>**NOTE** 
     329>Quando l'utente preme il tasto Enter, la form viene spedita utilizzando l'azione definita nel tag form principale; in questo esempio, quello normale. 
     330 
     331Form moderne possono reagire non solo quando vengono spedite, ma anche quando un utente cambia il valore di qualche campo. In symfony, puoi usare l'helper `observe_field()` a questo scopo. Il Listato 11-13 mostra un esempio di utilizzo di tale helper per mostrare suggerimenti: ogni carattere inserito nel campo `item` scatena un chiamata Ajax che aggiorna il valore dell'elemento `item_suggestion`. 
     332 
     333Listato 11-13 - Chiamata a funzione remota quando un valore cambia con `observe_field()` 
     334 
     335    [php] 
     336    <?php echo form_tag('@item_add_regular') ?> 
     337      <label for="item">Item:</label> 
     338      <?php echo input_tag('item') ?> 
     339      <div id="item_suggestion"></div> 
     340      <?php echo observe_field('item', array( 
     341          'update'   => 'item_suggestion', 
     342          'url'      => '@item_being_typed', 
     343      )) ?> 
     344      <?php echo submit_tag('Add') ?> 
     345    </form> 
     346 
     347Il modulo/azione della regola `@item_being_typed` verra' chiamato ogni volta che l'utente cambia il valore del campo in osservazione (`item`), anche senza la submit della form. L'azione ricevera' il valore corrente di `item` dal parametro di richiesta `value`. Se vuoi passare qualcos'altro oltre al valore del campo in osservazione, lo puoi specificare tramite il parametro `with`. Ad esempio, se vuoi passare all'azione il parametro `param`, riscrivi l'helper `observe_field()` nel modo seguente: 
     348 
     349Listato 11-14 - Passare parametri all'azione remota tramite l'opzione `with` 
     350 
     351    [php] 
     352    <?php echo observe_field('item', array( 
     353        'update'   => 'item_suggestion', 
     354        'url'      => '@item_being_typed', 
     355        'with'     => "'param=' + value", 
     356    )) ?> 
     357 
     358Nota che questo helper non stampa in output un oggetto HTML, bensi' un behavior per l'elemento passato come parametro. Vedrai altri esempi del genere piu' avanti in questo capitolo. 
     359 
     360Se vuoi tenere sotto osservazione tutti i campi di una form, puoi utilizzare l'helper `observe_form()`, che chiama una funzione remota ogni qualvolta uno qualsiasi dei campi della form viene modificato. 
     361 
     362### Chiamate periodiche a funzioni remote 
     363 
     364L'helper `periodically_call_remote()` è un'interazione Ajax eseguita ogni tot secondi. Non è collegata ad alcun elmento HTML, bensì gira trasparentemente in background. Essa puo' essere di grande utilità per tracciare la posizione del mouse, salvare automaticamente il contenuto di una textarea e così via. Il Listato 11-15 ne mostra un esempio di utilizzo. 
     365 
     366Listato 11-15 - Chiamate periodiche a funzioni remote tramite `periodically_call_remote()` 
     367 
     368    [php] 
     369    <div id="notification"></div> 
     370    <?php echo periodically_call_remote(array( 
     371        'frequency' => 60, 
     372        'update'    => 'notification', 
     373        'url'       => '@watch', 
     374        'with'      => "'param=' + $('mycontent').value", 
     375    )) ?> 
     376 
     377Se non specifichi il numero di secondi (`frequency`) di intervallo, viene usato il default, ovvero 10 secondi. Nota che il parametro `with` viene valutato in JavaScript, per cui puoi usare Prototype su di esso, as esempio tramite la funzione dollaro. 
     378 
     379Parametri delle chiamate remote 
     380------------------------------- 
     381 
     382Tutti gli helper Ajax descritti finora possono ricevere altri parametri, in aggiunta a `update` e `url`. L'array associativo di parametri Ajax puo' modificare il comportamento della risposta. 
     383 
     384### Aggiornare elementi diversi a seconda del valore della risposta 
     385 
     386Se l'azione remota fallisce, l'helper remoto puo' aggiornare un elemento diverso da quello che aggiornerebbe in caso di successo. A questo scopo, dividi semplicemente il valore del parametro `update` in un array associativo, ed imposta valori diversi in caso di `success` o `failure`. Questo risulta di grande utilita' se, ad esempio, in una pagina ci sono molte interazioni Ajax ed una zona in cui vengono visualizzati gli errori. Il Listato 11-16 mostra un esempio dell'utilizzo condizionale di `update`. 
     387 
     388Listato 11-16 - Gestire aggiornamenti condizionali 
     389 
     390    [php] 
     391    <div id="error"></div> 
     392    <div id="feedback"></div> 
     393    <p>Hello, World!</p> 
     394    <?php echo link_to_remote('Delete this post', array( 
     395        'update'   => array('success' => 'feedback', 'failure' => 'error') 
     396        'url'      => 'post/delete?id='.$post->getId(), 
     397    )) ?> 
     398 
     399>**TIP** 
     400>Solo gli errori HTTP (500, 404, e tutti gli altri codici che non fanno parte del range 2xx) scateneranno un fallimento, non un'azione che resituisca `sfView::ERROR`. Per cui, se vuoi che la tua azione resituisca un errore Ajax, devi chiamare `$this->getResponse()->setStatusCode(404)` o similari. 
     401 
     402### Aggiornare un elemento a seconda della sua posizione 
     403 
     404Come con l'helper `update_element_function()`, puoi specificare quale sia l'elemento da aggiornare a seconda della sua posizione tramite il parametro `position`. Il Listato 11-17 ne mostra un esempio. 
     405 
     406Listato 11-17 - Utilizzo del parametro `position` 
     407 
     408    [php] 
     409    <div id="feedback"></div> 
     410    <p>Hello, World!</p> 
     411    <?php echo link_to_remote('Delete this post', array( 
     412        'update'   => 'feedback', 
     413        'url'      => 'post/delete?id='.$post->getId(), 
     414        'position' => 'after', 
     415    )) ?> 
     416 
     417Questo inserira' la risposta del server dopo l'elemento `feedback`; ovvero, fra i tag `<div>` e `<p>`. Con questo metodo, puoi fare diverse chiamate Ajax ed accumulare le risposte dopo l'elemento specificato in `update`. 
     418 
     419Il parametro `position` puo' assumere i seguenti valori: 
     420  
     421  * `before`: prima dell'elemento 
     422  * `after`: dopo l'elemento 
     423  * `top`: all'inizio dell'elemento 
     424  * `bottom`: alla fine dell'elemento 
     425 
     426### Aggiornare un elemento secondo una condizione 
     427 
     428Una chiamata remota accetta come parametro addizionale una richiesta di conferma, in modo da inviare effettivamente la richiesta `XMLHttpRequest` come mostrato nel Listato 11-18. 
     429 
     430Listato 11-18 - Chiedere conferma prima di inviare una richiesta remota 
     431 
     432    [php] 
     433    <div id="feedback"></div> 
     434    <?php echo link_to_remote('Delete this post', array( 
     435        'update'   => 'feedback', 
     436        'url'      => 'post/delete?id='.$post->getId(), 
     437        'confirm'  => 'Are you sure?', 
     438    )) ?> 
     439 
     440In questa maniera, dopo aver cliccato il link, si aprira' una finestra di dialogo JavaScript e l'azione `post/delete` verra' chiamata solo se l'utente la confermera' cliccando su OK. 
     441 
     442La richiesta remota puo' essere condizionata anche da un test lato client (in JavaScript), se inserisci il parametro `condition`, come mostrato nel Listato 11-19. 
     443 
     444Listato 11-19 - Chiamata remota condizionata da un test lato client 
     445 
     446    [php] 
     447    <div id="feedback"></div> 
     448    <?php echo link_to_remote('Delete this post', array( 
     449        'update'    => 'feedback', 
     450        'url'       => 'post/delete?id='.$post->getId(), 
     451        'condition' => "$('elementID') == true", 
     452    )) ?> 
     453 
     454### Determinare il metodo di richiesta Ajax 
     455 
     456Per default le richieste Ajax vengono eseguite in POST. Se vuoi fare una chiamata Ajax che non modifica dati, oppure se vuoi visualizzare una form che include la validazione come risultato di una richiesta Ajax, potresti aver bisogno di cambiare il metodo in GET. L'opzione `method` fa esattamente questo, come mostrato nel Listato 11-20. 
     457 
     458Listato 11-20 - Cambiare metodo di richiesta 
     459 
     460    [php] 
     461    <div id="feedback"></div> 
     462    <?php echo link_to_remote('Delete this post', array( 
     463        'update'    => 'feedback', 
     464        'url'       => 'post/delete?id='.$post->getId(), 
     465        'method'    => 'get', 
     466    )) ?> 
     467 
     468### Autorizzare l'esecuzione di script 
     469 
     470Se il codice contenuto nella risposta del server in seguito ad una chiamata Ajax contiene JavaScript, potresti essere sorpreso nel notare che tale codice per default non viene eseguito. Questo serve a ridurre i rischi di attacchi remoti, facendo in modo che l'esecuzione di script sia permessa solo quando lo sviluppatore è certo che il codice sia contenuto nella risposta. 
     471 
     472Questo è il motivo per cui occorre dichiarare esplicitamente la possibilita' di eseguire script nella risposta, tramite l'opzione `script`. Il Listato 11-21 mostra come fare. 
     473 
     474Listato 11-21 - Autorizzare l'esecuzione di script nella risposta Ajax 
     475 
     476    [php] 
     477    <div id="feedback"></div> 
     478    // Se la risposta dell'azione get o post contiene JavaScript, 
     479    // permette al browser di eseguirlo 
     480    <?php echo link_to_remote('Delete this post', array( 
     481        'update' => 'feedback', 
     482        'url'    => 'post/delete?id='.$post->getId(), 
     483        'script' => true, 
     484    )) ?> 
     485 
     486Se il template remoto contiene helper Ajax (come ad esempio `remote_function()`), fai attenzione al fatto che tali funzioni PHP generano codice JavaScript, che non verra' eseguito senza impostare `'script' => true`. 
     487 
     488>**NOTE** 
     489>Anche se abiliti l'esecuzione di script per la risposta remota, non vedrai gli script nel codice remoto, utilizzando uno strumento per vedere il codice generato. Lo script verrà eseguito ma non comparirà nel codice sorgente. Anche se particolare, questo comportamento è perfettamente normale. 
     490 
     491### Creare Callback 
     492 
     493Uno degli svantaggi principali delle interazioni Ajax è che esse sono invisibili all'utente fino a che la zona di aggiornamento non venga effettivamente modificata. Ciò significa che in caso di lentezza di rete o fallimento del server, l'utente potrebbe aspettare una risposta che non arriverebbe mai. Ecco perchè è importante notificare all'utente che le interazioni sono in esecuzione. 
     494 
     495Per default, ogni richiesta remota è un processo asincrono durante il quale diverse callback JavaScript possono essere scatenate (come ad esempio l'indicatore di progesso). Tutte le callback hanno accesso all'oggetto `request`, che gestisce la `XMLHttpRequest` sottostante. Le callback corrispondono agli eventi di qualsiasi interazione Ajax: 
     496 
     497  * `before`: Prima che la richiesta sia iniziata 
     498  * `after`: Immediatamente dopo l'inizio della richiesta e prima del caricamento 
     499  * `loading`: Quando la risposta remota è in caricamento sul browser 
     500  * `loaded`: Quando il browser ha completato il caricamento della risposta remota 
     501  * `interactive`: Quando l'utente può interagire con la richiesta remota, anche se il caricamento non è completato 
     502  * `success`: Quando `XMLHttpRequest` è completato, ed il codice di stato HTTP è nel range 2XX 
     503  * `failure`: Quando `XMLHttpRequest` è completato, ed il codice di stato HTTP non è nel range 2XX 
     504  * `404`: Quando la richiesta restituisce lo stato 404 
     505  * `complete`: Quando XMLHttpRequest è completa (succede dopo `success` o `failure`, se presenti) 
     506 
     507Ad esempio, è molto comune mostrare un indicatore di caricamento quando una richiesta viene inoltrata, per nasconderlo quando viene ricevuta la risposta. Per fare ciò, aggiungi semplicemente i parametri `loading` e `complete` alla chiamata Ajax, come mostrato nel Listato 11-22. 
     508 
     509Listato 11-22 - Utilizzare callback Ajax per mostrare e nascondere un indicatore di attività 
     510 
     511    [php] 
     512    <div id="feedback"></div> 
     513    <div id="indicator">Loading...</div> 
     514    <?php echo link_to_remote('Delete this post', array( 
     515        'update'   => 'feedback', 
     516        'url'      => 'post/delete?id='.$post->getId(), 
     517        'loading'  => "Element.show('indicator')", 
     518        'complete' => "Element.hide('indicator')", 
     519    )) ?> 
     520 
     521I metodi `show` e `hide`, come anche l'oggetto `Element`, sono altre utili aggiunte di Prototype. 
     522 
     523Creare effetti visuali 
     524---------------------- 
     525 
     526Symfony integra gli effetti visuali della libreria script.aculo.us, per permetterti di fare di più che mostrare o nascondere elementi `<div>` nelle tue pagine. Troverai una buona documentazione sulla sintassi degli effetti nel wiki di [http://script.aculo.us/]. Fondamentalmente, la libreria fornisce oggetti e funzioni JavaScript per la manipolazione del DOM, in modo da creare complicati effetti visuali. Ne trovi un piccolo esempio nel Listato 11-23. Il sito di script.aculo.us contiene una gallery in cui puoi vedere gli effetti dinamici in azione. 
     527 
     528Listato 11-23 - Effetti visuali in JavaScript con script.aculo.us 
     529 
     530    [php] 
     531    // Evidenzia l'elemento 'my_field' 
     532    Effect.Highlight('my_field', { startcolor:'#ff99ff', endcolor:'#999999' }) 
     533 
     534    // Crea un effetto "veneziana" su un elemento 
     535    Effect.BlindDown('id_of_element'); 
     536 
     537    // Sfuma un elemento fino a farlo scomparire 
     538    Effect.Fade('id_of_element', { transition: Effect.Transitions.wobble }) 
     539 
     540Symfony incapsula l'oggetto JavaScript `Effect` in un helper chiamato `visual_effect()`, che fa ancora parte del gruppo di helper `Javascript`. Stampa codice JavaScript che può essere usato in un link, come mostrato nel Listato 11-24. 
     541 
     542Listato 11-24 - Effetti visuali nei template tramite l'helper `visual_effect()` 
     543 
     544    [php] 
     545    <div id="secret_div" style="display:none">I was here all along!</div> 
     546    <?php echo link_to_function( 
     547      'Show the secret div', 
     548      visual_effect('appear', 'secret_div') 
     549    ) ?> 
     550    // Eseguirà una chiamata a Effect.Appear('secret_div') 
     551 
     552L'helper `visual_effects()` può anche essere usato in callback Ajax, come mostrato nel Listato 11-25, il quale mostra un indicatore di attività come nel Listato 11-22, ma molto più carino esteticamente. L'elemento `indicator` appare progessivamente quando la chiamata comincia, e scompare sfumando quando arriva la risposta. Inoltre, l'elemento `feedback` viene evidenziato dopo essere stato aggiornato, per attrarre l'attenzione dell'utente in quella zona della pagina. 
     553 
     554Listato 11-25 - Effetti visuali con callback Ajax 
     555 
     556    [php] 
     557    <div id="feedback"></div> 
     558    <div id="indicator" style="display: none">Loading...</div> 
     559    <?php echo link_to_remote('Delete this post', array( 
     560        'update'   => 'feedback', 
     561        'url'      => 'post/delete?id='.$post->getId(), 
     562        'loading'  => visual_effect('appear', 'indicator'), 
     563        'complete' => visual_effect('fade', 'indicator'). 
     564                      visual_effect('highlight', 'feedback'), 
     565    )) ?> 
     566 
     567Nota come puoi combinare effetti visuali concatenandoli in una callback. 
     568 
     569JSON 
     570---- 
     571 
     572JavaScript Object Notation (JSON) è un formato leggero di interscambio dati. Fondamentalmente, non è niente di più di un hash Javascript (v. un esempio nel Listato 11-26) per trasportare informazioni. Ma JSON ha due grandi benefici per le interazioni Ajax: è facile da leggere in JavaScript e può ridurre la dimensione di una risposta web. 
     573 
     574Listato 11-26 - Esempio di oggetto JSON in JavaScript 
     575 
     576    var myJsonData = {"menu": { 
     577      "id": "file", 
     578      "value": "File", 
     579      "popup": { 
     580        "menuitem": [ 
     581          {"value": "New", "onclick": "CreateNewDoc()"}, 
     582          {"value": "Open", "onclick": "OpenDoc()"}, 
     583          {"value": "Close", "onclick": "CloseDoc()"} 
     584        ] 
     585      } 
     586    }} 
     587 
     588Se un'azione Ajax ha bisogno di restituire dati strutturati al chiamante per ulteriori operazioni JavaScript, JSON è il formato giusto per la risposta. È molto utile, ad esempio, se una chiamata Ajax deve aggiornare diversi elementi nella pagina che la chiama. 
     589 
     590Immagina ad esempio che tale pagina chiamante sia fatta come quella del Listato 11-27. Essa possiede due elementi che potresti dover aggiornare. Un helper remoto potrebbe aggiornarne uno solo, non entrambi. 
     591 
     592Listato 11-27 - Esempio di template per aggiornamenti Ajax multipli 
     593 
     594    [php] 
     595    <h1 id="title">Basic letter</h1> 
     596    <p>Dear <span id="name">name_here</span>,</p> 
     597    <p>Your e-mail was received and will be answered shortly.</p> 
     598    <p>Sincerely,</p> 
     599 
     600Per aggiornare entrambi, immagina che la risposta Ajax sia un array JSON contenente: 
     601 
     602     [["title", "My basic letter"], ["name", "Mr Brown"]] 
     603 
     604Così la chiamata remota può interpretare facilmente tale risposta ed aggiornare diversi campi in una riga, con un piccolo aiuto di JavaScript. Il codice del Listato 11-28 mostra cosa può essere aggiunto al Listato 11-27 per raggiungere tale scopo. 
     605 
     606Listato 11-28 - Aggiornare più di un elemento da una risposta remota 
     607 
     608    [php] 
     609    <?php echo link_to_remote('Refresh the letter', array( 
     610      'url'      => 'publishing/refresh', 
     611      'complete' => 'updateJSON(ajax)' 
     612    )) ?> 
     613 
     614    <?php echo javascript_tag(" 
     615    function updateJSON(ajax) 
     616    { 
     617      json = ajax.responseJSON; 
     618      for (var i = 0; i < json.length; i++) 
     619      { 
     620         Element.update(json[i][0], json[i][1]); 
     621      } 
     622    } 
     623    ") ?> 
     624 
     625Il callback `complete` ha accesso ai dati `JSON` della risposta e lo può passare ad una terza funzione. La funzione `updateJSON()` itera i dati ajax e per ogni membro dell'array aggiorna gli elementi che portano il nome contenuto nel primo parametro con il valore del secondo. 
     626 
     627Il Listato 11-29 mostra come l'azione `publishing/refresh` può restituire una risposta JSON. 
     628 
     629Listato 11-29 - Esempio di azione che restituisce dati JSON 
     630 
     631    [php] 
     632    class publishingActions extends sfActions 
     633    { 
     634      public function executeRefresh() 
     635      { 
     636        $this->getResponse()->setHttpHeader('Content-Type','application/json; charset=utf-8'); 
     637        $output = '[["title", "My basic letter"], ["name", "Mr Brown"]]'; 
     638         return $this->renderText('('.$output.')'); 
     639      } 
     640 
     641Usare il content type `application/json` consente a Prototype di valutare automaticamente il JSON passato al corpo della rispota, che è preferibile a restituirlo tramite header, perché l'header HTTP è limitato nella dimensione ed alcuni browser hanno problemi con le risposte che non hanno un body. Usando `->renderText()` il template non viene usato, ottenendo una performance migliore. 
     642 
     643JSON è diventato uno standard nelle applicazioni web. I web services spesso offrono le risposte in JSON invece che in XML, per permettere integrazione del servizio nel client (mashup), invece che nel server. Per cui se ti stai chiedendo quale sia il formato migliore per la comunicazione tra il tuo server ed una funzione JavaScript, probabilmente JSON è la risposta che cerchi. 
     644 
     645>**TIP** 
     646>Dalla versione 5.2, PHP offre due funzioni, `json_encode()` e `json_decode()`, che ti permettono di convertire un array tra la sintassi PHP e quella JSON ([http://www.php.net/manual/en/ref.json.php](http://www.php.net/manual/en/ref.json.php)). Tali funzioni facilitano l'integrazione di array JSON ed Ajax in generale. 
     647> 
     648>    $output = array("title" => "My basic letter", "name" => "Mr Brown"); 
     649     return $this->renderText(json_encode($output)); 
     650 
     651Interazioni complesse con Ajax 
     652------------------------------ 
     653 
     654Fra tutti gli helper Ajax di symfony, ne troverai qualcuno che permette interazioni complesse con una singola chiamata. Essi ti permettono di aumentare la fruibilità delle interazioni rendendole in stile "applicazione desktop" (drag-and-drop, autocompletion, live editing) senza il bisogno di JavaScript complicati. La sezione seguente descrive gli helper per le interazioni complesse e ne mostra alcuni semplici esempi. Parametri addizionali e trucchi sono disponibili nella documentazione di script.aculo.us. 
     655 
     656>**CAUTION** 
     657>Anche se le interazioni complesse sono possibili, esse fabbisognano di tempo extra per renderle "naturali". Usale solo quando sei certo che migliorano l'interattività, ed evitale quando c'è il rischio che disorientino l'utente. 
     658 
     659### Autocompletion 
     660 
     661Un campo di testo che mostri una lista di parole che coincidano con quello che l'utente sta inserendo viene chiamato autocompletion. Con un singolo helper chiamato `input_auto_complete_tag()`, puoi raggiungere tale effetto, premesso che l'azione remota restituisca una risposta formattata come una lista HTML, come quella del Listato 11-30. 
     662 
     663Listato 11-30 - Esempio di risposta compatibile con il tag autocomplete 
     664 
     665    <ul> 
     666      <li>suggestion1</li> 
     667      <li>suggestion2</li> 
     668      ... 
     669    </ul> 
     670 
     671Inserisci l'helper nel template come faresti con un campo di testo normale, come mostrato nel Listato 11-31. 
     672 
     673Listato 11-31 - Utilizzare il tag autocomplete nei template 
     674 
     675    [php] 
     676    <?php echo form_tag('mymodule/myaction') ?> 
     677      Find an author by name: 
     678      <?php echo input_auto_complete_tag('author', 'default name', 
     679        'author/autocomplete', 
     680        array('autocomplete' => 'off'), 
     681        array('use_style'    => true) 
     682      ) ?> 
     683      <?php echo submit_tag('Find') ?> 
     684    </form> 
     685 
     686Questo chiamerà l'azione `author/autocomplete` ogni volta che l'utente inserisce un carattere nel campo `author`. Sta a te scrivere l'azione in modo che trovi una lista di possibili coincidenze con quello che l'utente sta inserendo e che la restituisca in un formato simile a quello del Listato 11-30. L'helper quindi visualizzerà la lista sotto il campo `author`, e cliccare su uno dei suggerimenti o selezionarlo con la tastiera completerà il campo, come mostrato nella Figura 11-3. 
     687 
     688Figura 11-3 - Esempio di auto completamento 
     689 
     690![Esempio di auto completamento](http://www.symfony-project.org/images/book/1_0/F1103.png "Esempio di auto completamento") 
     691 
     692Il terzo argomento di `input_auto_complete_tag()` può assumere i seguenti parametri: 
     693 
     694  * `use_style`: Stili che la risposta utilizza automaticamente. 
     695  * `frequency`: Frequenza della chiamata periodica (default a 0.4 secondi). 
     696  * `tokens`: Permette autocompletamento incrementale "tokenizzato" . Ad esempio, se impostassi questo parametro come virgola , e se l'utente inserisse jane, george, the l'azione riceverebbe solo il valore 'george'. 
     697 
     698>**NOTE** 
     699>L'helper `input_auto_complete_tag()`, come i seguenti, accettano anche le altre opzioni degli helper remoti spiegate precedentemente in questo capitolo. In particolare, è buona abitudine impostare gli effetti visuali `loading` e `complete` per migliorare l'interazione. 
     700 
     701### Drag-and-Drop 
     702 
     703La capacità di afferrare un elemento con il mouse, muoverlo e rilasciarlo da qualche altra parte è familiare in applicazioni desktop ma si vede raramente su un browser. Questo perchè la codifica di tali comportamenti in JavaScript è molto complicata. Fortunatamente, essa richiede solo una linea in symfony. 
     704 
     705Il framework fornisce due helper, `draggable_element()` e `drop_receiving_element()`, che possono essere visti come modificatori di comportamento; essi aggiungono osservatori e capacità agli elementi. Usali per dichiarare un elemento come semovibile, o come ricevitore per uno in movimento. Un elemento semovibile può essere afferrato tramite un click del mouse. Fino a che tieni premuto il tasto del mouse, l'elemento può essere spostato all'interno della finestra. Un elemento ricevente chiama una funzione remota quando un elemento viene rilasciato su di esso. Il Listato 11-32 mostra tale tipo di interazione con un esempio di carrello per la spesa. 
     706 
     707Listato 11-32 - Elementi semovibili e riceventi in un carrello per la spesa 
     708 
     709    [php] 
     710    <ul id="items"> 
     711      <li id="item_1" class="food">Carrot</li> 
     712      <?php echo draggable_element('item_1', array('revert' => true)) ?> 
     713      <li id="item_2" class="food">Apple</li> 
     714      <?php echo draggable_element('item_2', array('revert' => true)) ?> 
     715      <li id="item_3" class="food">Orange</li> 
     716      <?php echo draggable_element('item_3', array('revert' => true)) ?> 
     717    </li> 
     718    <div id="cart"> 
     719      <p>Your cart is empty</p> 
     720      <p>Drag items here to add them to your cart</p> 
     721    </div> 
     722    <?php echo drop_receiving_element('cart', array( 
     723      'url'        => 'cart/add', 
     724      'accept'     => 'food', 
     725      'update'     => 'cart', 
     726    )) ?> 
     727 
     728Ognuno degli elementi di una lista non ordinata può essere afferrato con il mouse e mosso nella finestra. Quando rilasciato, esso ritorna alla propria posizione originale. Se rilasciato sull'elemento `cart`, scatena una chiamata remota all'azione `cart/add`. L'azione sarà capace di determinare quale elemento è stato rilasciato nell'elemento `cart` controllando il parametro di richiesta `id`. Per cui il Listato 11-32 simula una sessione di acquisto reale: prendi oggetti e li metti nel carrello, e poi vai a pagare. 
     729 
     730>**TIP** 
     731>Nel Listato 11-32, gli helpere sono scritti immediatamente dopo l'elemento che modificano, ma questo non è necessario. Potresti raggruppare tutti gli helper `draggable_element()` e `drop_receiving_element()` alla fine del template. La cosa importante è il primo argomento della chiamata all'helper, che specifica l'identificatore del ricevente. 
     732 
     733L'helper `draggable_element()` accetta i seguenti parametri: 
     734 
     735  * `revert`: Se impostato a `true`, quando rilasciato l'elemento tornerà alla sua posizione originale. Può anche essere una chiamata ad una funzione personalizzata, eseguita alla fine del trascinamento. 
     736  * `ghosting`: Clona l'elemento e trascina il clone, lasciando l'originale dov'è fino alla fine del trascinamento. 
     737  * `snap`: Se impostato a `false`, non verrà impostato alcun snapping. Altrimenti, l'elemento può essere trascinato solo in una griglia di intervallo x e y, ed in questo caso, assume la forma `xy` o `[x,y]` o `function(x,y){ return [x,y] `}. 
     738 
     739L'helper `drop_receiving_element()` accetta i seguenti parametri: 
     740 
     741  * `accept`: Una stringa od un array di stringhe che descrivono classi CSS. L'elemento accetterà solo elementi appartenenti ad una o più di tali classi. 
     742  * `hoverclass`: classe CSS aggiunta all'elemento quando un elemento trascinato sopra di esso viene accettato. 
     743 
     744### Liste ordinabili 
     745 
     746Un'altra possibilità offerta dagli elementi trascinabili è quella di ordinare una lista muovendo i suoi elementi con il mouse. L'helper `sortable_element()` aggiunge tale comportamento ad un oggetto, ed il Listato 11-33 è un buon esempio di implementazione di questa funzione. 
     747 
     748Listato 11-33 - Esempio di liste ordinabili 
     749 
     750    [php] 
     751    <p>What do you like most?</p> 
     752    <ul id="order"> 
     753      <li id="item_1" class="sortable">Carrots</li> 
     754      <li id="item_2" class="sortable">Apples</li> 
     755      <li id="item_3" class="sortable">Oranges</li> 
     756      // Nobody likes Brussel sprouts anyway 
     757      <li id="item_4">Brussel sprouts</li> 
     758    </ul> 
     759    <div id="feedback"></div> 
     760    <?php echo sortable_element('order', array( 
     761      'url'    => 'item/sort', 
     762      'update' => 'feedback', 
     763      'only'   => 'sortable' 
     764    )); ?> 
     765 
     766Grazie alla magia dell'helper `sortable_element()`, l'elemento `<ul>` diventa ordinabile, che significa che i suoi figli possono essere riordinati tramite drag-and-drop. Ogni volta che un utente trascina un elemento e lo rilascia per riordinare la lista, viene effettuata una richiesta Ajax con i seguenti parametri: 
     767 
     768    POST /sf_sandbox/web/frontend_dev.php/item/sort HTTP/1.1 
     769      order[]=1&order[]=3&order[]=2&_= 
     770 
     771Tutta la lista viene passata in forma di array (nel formato `order[$rank]=$id`, `$order` comincia da 0 e `$id` dipendentemente da cosa c'è dopo l'underscore (_) nella proprietà `id` dell'elemento della lista). La proprietà `id` dell'elemento ordinabile (nell'esempio `order`) viene utilizzato come nome dell'array. 
     772 
     773L'helper `sortable_element()` accetta i seguenti parametri: 
     774 
     775  * `only`: Una stringa od un array di stringhe che descrivono classi CSS. Solo i figli che possiedono tale classe possono essere spostati. 
     776  * `hoverclass`: Classe CSS aggiunta all'elemento quando il mouse gli passa sopra. 
     777  * `overlap`: Impostalo a `horizontal` se gli oggetto sono visualizzati tutti in una linea, ed a `vertical` (valore di default) quando c'è un elemento per linea (come nell'esempio). 
     778  * `tag`: Se la lista da ordinare non è composta da elementi `<li>`, devi definire quali figli devono diventare ordinabili (ad esempio `div` o `dl`). 
     779 
     780**TIP** 
     781>Da symfony 1.1 puoi anche usare l'helper `sortable_element()` senza l'opzione `url`. Utile se vuoi ritardare la chiamata AJAX su un bottone `salva` o simili. 
     782 
     783### Edit in Place 
     784 
     785Sempre più applicazioni permettono all'utente di modificare il contenuto della pagina senza il bisogno di rivisualizzare una form. Il principio di questa interazione è semplice. Un blocco di testo viene evidenziato quando l'utente ci passa sopra con il mouse. Se l'utente lo clicca, il testo viene convertito in un'area di testo con il contenuto del blocco di testo ed appare un pulsante per il salvataggio. L'utente può modificare il testo dentro la textarea, e dopo che ha salvato, la textarea sparisce ed il testo viene visualizzato come prima nella pagina. In symfony, puoi aggiungere questo comportamento ad un elemento tramite l'helper `input_in_place_editor_tag()`. Il Listato 11-34 mostra come usarlo. 
     786 
     787Listato 11-34 - Esempio di live editing 
     788 
     789    [php] 
     790    <div id="edit_me">You can edit this text</div> 
     791    <?php echo input_in_place_editor_tag('edit_me', 'mymodule/myaction', array( 
     792      'cols'        => 40, 
     793      'rows'        => 10, 
     794    )) ?> 
     795 
     796Quando l'utente clicca sul testo modificabile, esso viene inserito all'interno di un'area di testo che appare. Quando viene salvato (submit della form generata) viene chiamata in Ajax l'azione `mymodule/myaction`, passando il testo nel parametro `value`. Il risultato dell'azione aggiorna l'elemento. È molto veloce da scrivere e potente. 
     797 
     798L'helper `input_in_place_editor_tag()` accetta i seguenti parametri: 
     799 
     800  * `cols` e `rows`: Dimensione dell'area di testo che appare (diventa una `<textarea` se `rows` è maggiore di 1). 
     801  * `loadTextURL`: URI dell'azione da chiamare per visualizzare il testo da modificare. Questo è utile se il contenuto dell'elemento modificabile usa una formattazione speciale e se vuoi che l'utente modifichi il testo senza tale formattazione. 
     802  * `save_text` and `cancel_text`: Il testo sul link di salvataggio (default "ok") e su quello di annullamento (default "cancel"). 
     803 
     804Sommario 
     805-------- 
     806 
     807Se sei stanco di scrivere codice JavaScript nei tuoi template per avere interattività lato client, gli helper JavaScript offrono una semplice alternativa. Non solo essi automatizzano il comportamento normale dei link e l'aggiornamento degli elementi, ma forniscono anche un modo per sviluppare interazioni Ajax velocemente. Con l'aiuto della potenza e dei miglioramenti della sintassi forniti da Prototype e degli effetti visuali forniti da script.aculo.us, anche interazioni complesse non richiedono più di qualche linea da scrivere. 
     808 
     809}}}