Chapter 11 - Integração com Ajax
Interações no lado cliente, efeitos visuais complexos, e comunicação assíncrona são comuns em aplicações Web 2.0. Todas estas requerem o JavaScript, mas implementar estas na mão é frequentemente árduo, e lento para debugar. Felizmente, symfony automatiza vários dos usos comuns do JavaScript nos templates com um conjunto completo de auxiliares. Vários dos comportamentos no lado cliente podem ser implementados sem uma única linha de código em JavaScript. Desenvolvedores precisam apenas se preocupar com o efeito que eles desejam obter, e symfony irá lidar com a sintaxe complexa e problemas de compatibilidade.
Este capítulo descreve as ferramentas fornecidas pelo symfony para facilitar o desenvolvimento de scripts no lado cliente:
-
Os auxliares básicos do JavaScript produzem como saída marcadores de
<script>padronizadas e compatíveis nos templates do symfony, para atualizar um elemento do Modelo de Documento Objeto ou DOM(Document Object Model) ou lançar um script com uma ligação de página(link). - Prototype é uma biblioteca JavaScript integrada no symfony, que aumenta a velocidade de desenvolvimento de scripts no lado cliente adicionando novas funções e métodos ao núcleo do JavaScript.
- Os auxiliares do Ajax permitem ao usuário atualizar algumas partes de uma página clicando em uma ligação, enviando um formulário, ou modificando um elemento de formulário.
- As várias opções, que estes auxiliares provêem, garantem ainda mais flexibilidade e poder, notadamente pelo uso de funções de evento.
- Script.aculo.us é uma outra biblioteca do JavaScript, também integrada no symfony, que adiciona efeitos visuais dinâmicos para aperfeiçoar a interface e a experiência do usuário.
- A Notação de Objeto do JavaScript (JSON: JavaScript Object Notation) é um padrão usado para realizar a comunicação entre um servidor e um script cliente.
- Interações complexas do lado cliente, combinando todos os elementos mencionados anteriormente, são possíveis nas aplicações com symfony. Autocompletar, arrastar e soltar, listas ordenáveis, e texto editável todos podem ser implementados com uma linha única de PHP -- uma chamada para um auxiliar do symfony.
Auxiliares Básicos do JavaScript
JavaScript foi considerada há muito tempo como tendo pouco uso real em aplicações web profissionais, devido a falta de compatibilidade entre navegadores diferentes. Hoje, os problemas de compatibilidade estão (em sua maioria) resolvidos, e bibliotecas mais robustas nos permitem programar interações complexas em JavaScript sem a necessidade de linhas incontáveis de código e a perca de horas em processo de procurra de erros. O avanço mais popular é chamado de Ajax, que é discutido na seção "Auxiliares do Ajax" mais tarde neste capítulo.
Paradoxicalmente, você verá muito pouco código em JavaScript neste capítulo. Isto é porque symfony tem uma maneira original para criação de scripts no lado cliente: Ele empacota e abstrai os comportamentos do JavaScript em auxiliares(helpers), para que então seus templates terminem exibindo nenhum único código em JavaScript. Para o desenvolvedor, adicionar um comportamento para um elemento na página requere apenas uma linha de PHP, mas esta chamada ao auxiliar produz código em JavaScript, e inspecionando as respostas produzidas irá revelar toda a complexidade encapsulada. Os auxiliares lidam com consistência entre navegadores, casos de limites complexos, extensibilidade, e assim em diante, então a quantidade de código em JavaScript que eles contêem pode ser muito importante. Portanto, este capítulo irá ensinar-lhe como não usar JavaScript para realizar efeitos que você costumava construir com JavaScript.
Todos os auxiliares descritos aqui estão disponíveis em templates, contanto que você declare o uso do grupo auxiliar do Javascript.
<?php use_helper('Javascript') ?>
Como você irá aprender em breve, alguns destes auxiliares produzem código em HTML, e alguns deles produzem código em JavaScript.
JavaScript em Templates
Em XHTML, os blocos de código em JavaScript devem estar contidos dentro de declarações CDATA. Porém páginas que requerem múltiplos blocos de código em JavaScript podem tornar-se enfadonhos para escrever. É por esta razão que o symfony provê um auxiliar javascript_tag(), que transforma uma string em marcador de <script> compatível com XHTML. A listagem 11-1 demonstra a usagem deste auxiliar.
Listagem 11-1 - Inserindo JavaScript com o auxiliar javascript_tag()
<?php echo javascript_tag(" function foobar() { ... } ") ?> => <script type="text/javascript"> //<![CDATA[ function foobar() { ... } //]]> </script>
Mas o uso mais comum do JavaScript, mais do que blocos de código, é em uma hiperligação que inicia um script em particular. O auxiliar link_to_function() faz exatamente isto, como exibido na Listagem 11-2.
Listagem 11-2 - Iniciando JavaScript através de uma ligação com o auxiliar link_to_function()
<?php echo link_to_function('Clique em mim!', "alert('foobar')") ?> => <a href="#" onClick="alert('foobar'); return none;">Clique em mim!</a>
Da mesma forma que com o auxiliar link_to(), você pode adicionar opções para o marcador <a> no terceiro argumento.
NOTA Exatamente como o auxiliar
link_to()tem o irmãobutton_to(), você pode iniciar JavaScript a partir de um botão (<input type="button">) através de uma chamada ao auxiliarbutton_to_function(). E se você preferir uma imagem clicável, apenas chamelink_to_function(image_tag('minhaimagem'), "alert('foobar')").
Atualizando um elemento DOM
Uma tarefa comum em interfaces dinâmicas é a atualização de um elemento na página. Isto é algo que você escreve com frequência, como exibido na Listagem 11-3.
Listagem 11-3 - Atualizando um elemento em JavaScript
<div id="indicador">Início do processamento de dados</div> <?php echo javascript_tag(" document.getElementById("indicador").innerHTML = "<strong>Processamento de dados completo</strong>"; ") ?>
Symfony provê um auxiliar que produz JavaScript, não HTML, para este propósito, e é chamado update_element_function(). A Listagem 11-4 demonstra o seu uso.
Listagem 11-4 - Atualizando um elemento em JavaScript com o auxiliar update_element_function()
<div id="indicador">Início do processamento de dados</div> <?php echo javascript_tag( update_element_function('indicador', array( 'content' => "<strong>Processamento de dados completo</strong>", )) ) ?>
Você pode estar perguntando-se porque este auxiliar é tão útil em particular, já que é no mínimo tão longo quanto o código real em JavaScript. É, na verdade, apenas uma questão de facilidade de leitura. Por exemplo, você pode querer inserir conteúdo antes ou depois de um elemento, remover um elemento ao invés de apenas atualizá-lo, ou até mesmo não fazer nada respeitando uma determinada condição. Nestes casos, o código em JavaScript torna-se meio confuso, mas o update_element_function() mantém o template bastante legível, como você pode ver na Listagem 11-5.
Listagem 11-5 - Opções do auxiliar update_element_function()
// Insira conteúdo exatamente após o elemento 'indicador' update_element_function('indicador', array( 'position' => 'after', 'content' => "<strong>Processamento de dados completo</strong>", )); // Remova o elemento antes do 'indicador', e apenas se $condition é verdade update_element_function('indicador', array( 'action' => $condition ? 'remove' : 'empty', 'position' => 'before', ))
O auxiliar torna seus templates mais fáceis de entender que qualquer código em JavaScript, e você tem uma única sintaxe para comportamentos similares. Este é o pôrque do nome do auxiliar ser tão extenso: Ele torna o código auto-suficiente, sem a necessidade de comentários extras.
Degradação suave
O marcador <noscript> permite a você especificar algum código HTML que é exibido somente por navegadores que não tem suporte ao JavaScript. Symfony complementa isto com um auxiliar que funciona de maneira inversa: Ele qualifica algum código para que então só alguns navegadores que tem suporte real ao JavaScript executem-no. Os auxiliares if_javascript() e end_if_javascript() facilitam a criação de aplicações que degradam suavemente, como demonstrado na Listagem 11-6.
Listagem 11-6 - Usando o auxliar if_javascript() para permitir Degradação suave
<?php if_javascript(); ?> <p>Você está com o JavaScript ativo.</p> <?php end_if_javascript(); ?> <noscript> <p>Você não está com o JavaScript ativo.</p> </noscript>
NOTA Você não precisa incluir
echoquando estiver chamando os auxiliaresif_javascript()eend_if_javascript().
Prototype
Prototype é uma ótima biblioteca em JavaScript que expande as possibilidades da linguagem de script do cliente, adiciona as funções pendentes que você sempre sonhou, e oferece novos mecanismos para manipular o DOM. O projeto do website é http://prototypejs.org/.
Os arquivos do Prototype estão juntos com o framework do symfony e acessíveis em cada novo projeto symfony, em web/sf/prototype/. Isto significa que você pode usar Prototype adicionando o seguinte código a sua ação:
$prototypeDir = sfConfig::get('sf_prototype_web_dir'); $this->getResponse()->addJavascript($prototypeDir.'/js/prototype');
ou adicionando-o no arquivo view.yml:
all:
javascripts: [%SF_PROTOTYPE_WEB_DIR%/js/prototype]
NOTA A partir dos auxiliares Ajax no symfony, descritos na próxima seção, confie no Prototype, a biblioteca Prototype já está incluída automaticamente a partir do momento que você use um deles. Isto significa que você não precisará adicionar manualmente o JavaScript do Prototype para sua resposta se o seu template chamar um auxiliar
_remote.
Uma vez que a biblioteca Prototype estiver carregada, você pode tomar vantagem de todas as novas funções que ela adiciona ao núcleo do JavaScript. O propósito deste livro não é descrever elas todas, mas você irá descobrir ótima documentação sobre Prototype na Web, incluindo as seguintes páginas web:
- Particletree: http://particletree.com/features/quick-guide-to-prototype/
- Sergio Pereira: http://www.sergiopereira.com/articles/prototype.js.html
- Script.aculo.us: http://wiki.script.aculo.us/scriptaculous/show/Prototype
Uma das funções Prototype adiciona ao JavaScript a função dollar, $(). Basicamente, esta função é um simples atalho para document.getElementById(), mas um pouco mais poderoso. Veja a Listagem 11-7 para um exemplo do seu uso.
Listagem 11-7 - Usando a função $() para retornar um Elemento pelo ID em JavaScript
node = $('elementID'); // Significa o mesmo que node = document.getElementById('elementID'); // Ele também pode retornar mais de um elemento por vez // E, neste caso, o resultado é um vetor de elementos DOM nodes = $('firstDiv', 'secondDiv');
Prototype também provê uma função, que realmente faz falta no núcleo do JavaScript, que retorna um vetor de todos os elementos DOM que tem uma classe passada como argumento:
nodes = document.getElementByClassName('minhaClasse');
Contudo, você irá raramente usá-lo, por que Prototype provê uma função ainda mais poderosa chamada dollar duplo, $$(). Esta função retorna um vetor de elementos DOM baseado em um seletor CSS. Então a chamada anterior também pode ser escrita como a seguir:
nodes = $$('.minhaClasse');
Graças ao poder dos seletores CSS, você pode interpretar o DOM pela classe, ID, e relações de filho-pai e anterior-próximo ainda mais facilmente do que você iria com uma expressão XPath. Você pode até mesmo acessar os elementos com um seletor complexo combinando todos estes:
nodes = $$('body div#main ul li.last img > span.legend');
Um último exemplo das melhorias na sintaxe providas pelo Prototype é o iterador para cada vetor. Ele provê a mesma concisão que em PHP, adicionou a habilidade de definir funções anônimas e closures(escopos fechados) em JavaScript. Você irá provavelmente usar ele muito se você implementar com JavaScript na mão.
var vegetais = ['Cenouras', 'Alface', 'Alho']; vegetais.each(function(comida) { alert('Eu amo ' + comida); });
Por que programar em JavaScript com Prototype é muito mais divertido do que fazer na mão, e por que ele também é uma parte do symfony, você realmente deveria gastar alguns minutos para ler a documentação associada.
Auxiliares Ajax
Que tal se você quisesse atualizar um elemento na página, não com JavaScript como na Listagem 11-5, mas com um script em PHP executado pelo servidor? Isto daria a você a oportunidade de mudar parte da página de acordo com a resposta do servidor. O auxiliar remote_function() faz exatamente isto, como demonstrado na Listagem 11-8.
Listagem 11-8 - Usando o auxiliar remote_function()
<div id="minhazona"></div> <?php echo javascript_tag( remote_function(array( 'update' => 'minhazona', 'url' => 'meumodulo/minhaacao', )) ) ?>
NOTA O parametro
urlpode conter tanto uma URI interna (modulo/accao?chave1=valor1&...) ou um nome de uma regra de redirecionamento, exatamente como em umurl_for()comum.
Quando chamado, este script irá atualizar o elemento de id minhazona com a resposta ou a requisição da ação meumodulo/minhaacao. Este tipo de interação é chamado de Ajax, e é o coração de aplicações web altamente interativas. Aqui está como a Wikipedia (http://en.wikipedia.org/wiki/AJAX) descreve-o:
Ajax torna as páginas web mais dinâmicas trocando pequenos pedaços de dados com o servidor por debaixo dos panos, para que como resultado a página web inteira não precise ser recarregada cada vez que o usuário fizer uma alteração. Isto significa um aumento na interatividade, velocidade e usuabilidade da página web.
Ajax conta com XMLHttpRequest, um objeto JavaScript que comporta-se como um quadro(frame) escondido, que você pode atualizar de uma requisição do servidor e reusá-lo para manipular o resto de sua página web. Este objeto é de um nível bastante baixo, e diferentes navegadores lidam com ele de maneiras diferentes, então lidar com requisições Ajax manualmente, frequentemente, significa escrever grandes porções de código. Felizmente, Prototype encapsula todo o código necessário para lidar com Ajax e provê um objeto Ajax mais simples, e symfony conta com este objeto. É por isto que a biblioteca Prototype é automaticamente carregada uma vez que você use um auxiliar Ajax em um template.
CUIDADO Os auxiliares Ajax não irão funcionar se a URL de uma ação remota não pertencer ao mesmo domínio do que a página atual. Esta restrição existe por razões de segurança, e confia que as limitações dos navegadores não podem ser ultrapassadas.
Uma interação Ajax é feita de três partes: um acionador (uma ligação, um botão, um formulário, um relógio, ou qualquer outro controle que o usuário manipula para lançar uma ação), uma ação do servidor, e uma área na página para exibir as respostas da ação. Você pode construir interações mais complexas, se a ação remota retornar dados a serem processados por uma função JavaScript no lado cliente. Symfony provê múltiplos auxiliares para inserir a interação Ajax em seus templates, todos contendo a palavra remote nos seus nomes. Eles também compartilham uma sintaxe comum--um vetor associativo com todos os parâmetros Ajax nele. Tenha em mente que os auxiliares Ajax produzem código em HTML, e não em JavaScript.
BARRA LATERAL E quanto as ações Ajax?
Ações chamadas como funções remotas são ações comuns. Elas seguem o direcionamento, podem determinar a vista que determina a resposta com seus
return, passar variáveis para os templates, e alterar o modelo exatamente como outras ações.Contudo, quando chamada pelo Ajax, ações retornam
truea seguinte chamada:
$isAjax = $this->getRequest()->isXmlHttpRequest();
Symfony sabe quando a ação está em um contexto Ajax e pode adaptar a resposta processando de acordo. Portanto, por padrão, as ações Ajax não incluem a barra de ferramentas de debug web no ambiente de desenvolvimento. Também, eles pulam o processo de decoração(o seu template não está incluído no leiaute por padrão). Se você quiser que uma vista Ajax seja de decoração, você precisa especificar explicitamente
has_layout: truepara esta vista no módulo do arquivoview.yml.Mais uma coisa: Já que o tempo de resposta é crucial em interações Ajax, se a resposta não for muito complexa, talvez seja uma boa idéia evitar a criação de uma vista e ao invés disso retornar a resposta diretamente a partir da ação. Então você pode usar o método
renderText()na ação para pular o template e aumentar as requisições Ajax.
Ligação Ajax
As ligações Ajax formam uma grande parte das interações Ajax disponíveis em aplicações Web 2.0. O auxiliar link_to_remote() produz uma ligação que chama, não supreendentemente, uma função remota. A sintaxe é bastante similar ao da link_to() (exceto que o segundo parâmetro é o vetor associativo das opções Ajax), como exibido na Listagem 11-9.
Listing 11-9 - Ligação Ajax com o auxiliar link_to_remote()
<div id="retorno"></div> <?php echo link_to_remote('Delete este post', array( 'update' => 'retorno', 'url' => 'post/delete?id='.$post->getId(), )) ?>
Neste exemplo, clicando na ligação 'Delete este post' irá enviar uma chamada a ação post/delete no segundo plano. A resposta devolvida pelo servidor irá aparecer no elemento de id retorno. Este processo é ilustrado na Figura 11-1.
Figura 11-1 - Disparando uma atualização remota com uma hiperligação
Você pode usar uma imagem ao invés de uma linha de texto para carregar a ligação, use um nome de uma regra ao invés de uma URL interna modulo/accao, e adicione as opções para o marcador <a> no terceiro argumento, como mostrado na Listagem 11-10.
Listagem 11-10 - Opções do auxiliar link_to_remote()
<div id="emails"></div> <?php echo link_to_remote(image_tag('recarregar'), array( 'update' => 'emails', 'url' => '@lista_emails', ), array( 'class' => 'ajax_link', )) ?>
Formulários ao estilo Ajax
Formulários Web tipicamente chamam outra ação, mas isto causa com que toda a página seja recarregada. A correspondência do link_to_function() para um formulário seria que a submissão do formulário apenas atualizaria um elemento na página com a resposta do servidor. Isto é o que o auxiliar form_remote_tag() faz, e sua sintaxe é demonstrada na Listagem 11-11.
Listagem 11-11 - Formulário Ajax com o auxiliar form_remote_tag()
<div id="lista_de_itens"></div> <?php echo form_remote_tag(array( 'update' => 'lista_de_itens', 'url' => 'item/add', )) ?> <label for="item">Item:</label> <?php echo input_tag('item') ?> <?php echo submit_tag('Add') ?> </form>
Um form_remote_tag() abre um <form>, exatamente como o auxiliar comum form_tag(). Submeter este formulário irá enviar um pedido POST para a ação item/add no segundo plano, com o campo item como o parâmetro de requisição. A resposta irá substituir o conteúdo do elemento lista_de_itens, como ilustrado na Figura 11-2. Termine um formulário Ajax com a marcação de término comum </form>.
Figura 11-2 - Lançando uma atualização remota com um formulário
CUIDADO Formulários Ajax não podem ter partes múltiplas(multipart). Isto é uma limitação do objeto
XMLHttpRequest. Isto significa que você não pode lidar com carregamento ou envio de arquivos através de um formulário Ajax. Existem maneiras de contornar a questão, apesar disto--por exemplo, usando umiframeescondido ao invés de umXMLHttpRequest(veja uma implementação em http://www.air4web.com/files/upload/).
Se você quiser permitir que um formulário trabalhe tanto em modo de página como em modo Ajax, a melhor solução é defini-lo como um formulário comum, para prover, em adição ao botão de submissão comum, um segundo botão (<input type="button" />) para submeter o formulário em Ajax. Symfony chama este botão de submit_to_remote(). Isto irá ajudá-lo a construir interações Ajax que degradam suavemente. Como o exemplo na Listagem 11-12.
Listagem 11-12 - Um formulário com submissão comum e Ajax
<div id="lista_de_itens"></div> <?php echo form_tag('@item_add_regular') ?> <label for="item">Item:</label> <?php echo input_tag('item') ?> <?php if_javascript(); ?> <?php echo submit_to_remote('ajax_submit', 'Add in Ajax', array( 'update' => 'lista_de_itens', 'url' => '@item_add', )) ?> <?php end_if_javascript(); ?> <noscript> <?php echo submit_tag('Add') ?> </noscript> </form>
Um outro exemplo de uso combinado de marcadores de submissão comum e remota é um formulário que edita um artigo. Ele pode oferecer um botão de previsão em Ajax e um botão de publicar que realiza a submissão normal.
NOTA Quando o usuário pressiona a tecla Enter, o formulário é submetido usando a ação definida no marcador principal
<form>--neste exemplo, uma ação comum.
Formulários modernos podem reagir não apenas quando submetidos, mas também quando o valor de um campo está sendo atualizado pelo usuário. Em symfony, você usa o auxiliar observe_field() para isto. A Listagem 11-13 mostra um exemplo do uso deste auxiliar para construir uma sugestão de característica: Cada carácter digitado em um campo item dispara uma chamada Ajax recarregando o elemento item_suggestion na página.
Listagem 11-13 - Chamando uma função remota quando o valor de um campo se altera com o observe_field()
<?php echo form_tag('@item_add_regular') ?> <label for="item">Item:</label> <?php echo input_tag('item') ?> <div id="sugestao_de_item"></div> <?php echo observe_field('item', array( 'update' => 'sugestao_de_item', 'url' => '@item_being_typed', )) ?> <?php echo submit_tag('Add') ?> </form>
O módulo/acção escrita na regra @item_being_typed irá ser chamado toda vez que o usuário alterar o valor do campo observado (item), mesmo sem submeter o formulário. A ação será capaz de pegar o valor atual do item a partir do parâmetro requerido value. Se você quiser passar algo mais do que o valor do campo observado, você pode especificá-lo com uma expressão JavaScript no parâmetro with. Por exemplo, se você quiser que a ação para pegar o parâmetro param, escreva o auxiliar observe_field() como mostrado na Listagem 11-14.
Listagem 11-14 - Passando seus próprios parâmetros para a ação remota com a opção with
<?php echo observe_field('item', array( 'update' => 'item_suggestion', 'url' => '@item_being_typed', 'with' => "'param=' + value", )) ?>
Note que este auxiliar não produz um elemento HTML, mas ao invés disso produz um comportamento para o elemento passado como um parâmetro. Você irá ver mais exemplos dos auxiliares JavaScript determinando comportamentos mais tarde neste capítulo.
Se você quiser observar todos os campos de um formulário, você deverá usar o auxiliar observe_form(), que chama uma função remota toda vez que um dos campos do formulário é modificado.
Chamando Funções Remotas Periodicamente
Por último mas não menos importante, o auxiliar periodically_call_remote() é uma interação Ajax disparada a cada poucos segundos. Não é ligada a um controle HTML, mas roda transparentemente em segundo plano, como o comportamento da página inteira. Isto pode ser de grande uso para seguir e manter a posição do mouse, salvar automaticamente o conteúdo de uma grande área de texto, e assim por diante. A Listagem 11-15 mostra um exemplo de uso deste auxiliar.
Listagem 11-15 - Chamando uma função remota periodicamente com periodically_call_remote()
<div id="notificacao"></div> <?php echo periodically_call_remote(array( 'frequency' => 60, 'update' => 'notificacao', 'url' => '@watch', 'with' => "'param=' + $('meuconteudo').value", )) ?>
Se você não especificar a quantidade de segundos (frequency) para esperar entre duas chamadas consecutivas para a função remota, o valor padrão de 10 segundos é usado. Note que o parâmetro with é avaliado em JavaScript, então você pode usar as funções do Prototype nele, como a função dollar, $().
Parâmetros de Chamadas Remotas
Todos os auxiliares Ajax descritos nas secções anteriores podem receber outros parâmetros, em adição aos parâmetros update e url. O vetor associativo dos parâmetros Ajax podem alterar e ajustar o comportamento de chamadas remotas e o processamento de sua resposta.
Atualizando Elementos Distintos de Acordo com o Status da Resposta
Se a ação remota falhar, os auxiliares remotos podem escolher atualizar um outro elemento além daquele atualizado por uma resposta bem sucedida. Para este propósito, apenas divida o valor do parâmetro update em um vetor associativo, e defina valores diferentes para o elemento atualizar em casos de success(sucesso) e failure(fracasso). Isto é de grande utilidade se, por exemplo, existem várias interações Ajax em uma página e uma área de retorno de erros. A Listagem 11-16 demonstra como lidar com uma atualização condicional.
Listagem 11-16 - Lidando com uma Atualização Condicional
<div id="erro"></div> <div id="retorno"></div> <p>Olá, Mundo!</p> <?php echo link_to_remote('Delete este post', array( 'update' => array('success' => 'retorno', 'failure' => 'erro') 'url' => 'post/delete?id='.$post->getId(), )) ?>
DICA Somente códigos de erro HTTP (500, 404, e todos os códigos que não estão na faixa 2XX) irão disparar a atualização de erro, e não as ações que retornam
sfView::ERROR. Então se você quiser fazer com que uma ação retorne um erro Ajax, ela deve chamar$this->getResponse()->setStatusCode(404)ou similar.
Atualizando um Elemento de Acordo com a Posição
Exatamente como com o auxiliar update_element_function(), você pode especificar o elemento para atualizar como relativo a um elemento específico adicionando um parâmetro position(posição). A Listagem 11-17 mostra um exemplo.
Listagem 11-17 - Usando o Parâmetro Position para Mudar a Localização de Resposta
<div id="retorno"></div> <p>Olá, Mundo!</p> <?php echo link_to_remote('Delete este post', array( 'update' => 'retorno', 'url' => 'post/delete?id='.$post->getId(), 'position' => 'after', )) ?>
Isto irá inserir a resposta da chamada Ajax depois do elemento retorno; isto é, entre o <div> e o <p>. Com este método, você pode fazer várias chamadas Ajax e ver as respostas acumulando depois do elemento update.
O parâmetro position pode receber os seguintes valores:
-
before: Antes do elemento -
after: Depois do elemento -
top: No topo do conteúdo do elemento -
bottom: No final do conteúdo do elemento
Atualizando um Elemento de Acordo com uma Condição
Uma chamada remota pode receber um parâmetro adicional para permitir confirmação pelo usuário antes de submeter de verdade o XMLHttpRequest, como exibido na Listagem 11-18.
Listagem 11-18 - Usando o Parâmetro Confirm para Pedir uma Confirmação Antes de Chamar uma Função Remota
<div id="retorno"></div> <?php echo link_to_remote('Delete este post', array( 'update' => 'retorno', 'url' => 'post/delete?id='.$post->getId(), 'confirm' => 'Você tem certeza?', )) ?>
Uma caixa de diálogo JavaScript exibindo "Você tem certeza?" aparecerá na tela quando o usuário clicar na ligação, e a ação post/delete irá ser chamada apenas se o usuário confirmar sua escolha clicando em OK.
A chamada remota pode também ser condicionada por um teste realizado no lado do navegador (em JavaScript), se você prover um parâmetro condition, como exibido na Listagem 11-19.
Listagem 11-19 - Chamando uma Função Remota Condicionalmente de Acordo com um Teste no Lado Cliente
<div id="retorno"></div> <?php echo link_to_remote('Delete este post', array( 'update' => 'retorno', 'url' => 'post/delete?id='.$post->getId(), 'condition' => "$('elementID') == true", )) ?>
Determinando o Método de Requisição Ajax
Por padrão, as requisições Ajax são feitas com o método POST. Se você quer fazer uma chamada Ajax que não modifica dados, ou se você quer exibir um formulário que tem validação agregada(built-in) como o resultado de uma chamada Ajax, você pode precisar mudar o método de requisição Ajax para GET. A opção method altera o método de requisição Ajax, como exibido na Listagem 11-20.
Listagem 11-20 - Mudando o Método de Requisição Ajax
<div id="retorno"></div> <?php echo link_to_remote('Delete este post', array( 'update' => 'retorno', 'url' => 'post/delete?id='.$post->getId(), 'method' => 'get', )) ?>
Autorizando a Execução de um Script
Se o código de resposta da chamada Ajax (o código enviado pelo servidor, inserido em um elemento update) contém JavaScript, você pode ficar surpreso ao perceber que estes scripts não são executados por padrão. Isto serve para reduzir riscos de ataque remoto e para permitir a execução de um script apenas quando o desenvolvedor conhece com exatidão o código que está na resposta.
É por esta razão que você precisa declarar explicitamente a capacidade de executar scripts nas respostas remotas, com a opção script. A Listagem 11-21 fornece um exemplo de uma chamada Ajax declarando que o JavaScript a partir da resposta remota pode ser executado.
Listagem 11-21 - Autorizando a Execução de um Script na Resposta Ajax
<div id="retorno"></div> // Se a resposta da ação post/delete contém JavaScript, // permita que esta seja executada pelo navegador <?php echo link_to_remote('Delete this post', array( 'update' => 'retorno', 'url' => 'post/delete?id='.$post->getId(), 'script' => true, )) ?>
Se o template remoto contém auxiliares Ajax (como o remote_function()), esteja atento que estas funções PHP produzem código JavaScript, e elas não irão executar, ao não ser que você adicione a opção 'script' => true.
NOTA Mesmo se você ativar a execução de scripts para uma resposta remota, você não verá realmente os scripts no código remoto, se você usar uma ferramenta para verificar o código gerado. Os scripts irão executar, mas não irão aparecer no código. Apesar de peculiar, este comportamento é perfeitamente normal.
Criando Eventos
Uma desvantagem importante das interações Ajax é que elas são invisíveis ao usuário até que a área a ser atualizada seja de fato alterada. Isto significa que em casos de uma rede lenta ou falha no servidor, usuários podem acreditar que sua ação foi levada adiante, quando na verdade ela não foi processada. Esta é a razão por que é importante notificar o usuário dos eventos na interação Ajax.
Por padrão, cada requisição remota é um processo assíncrono durante o qual vários eventos em JavaScript podem ser acionados (para indicadores de progresso e similares). Todos os eventos tem acesso ao objeto request, que contém implícitamente o XMLHttpRequest. Os eventos correspondem aos eventos de qualquer interação Ajax:
-
before: Antes da requisição ser iniciada -
after: Imediatamente depois da requisição ser iniciada e antes do loading -
loading: Quando a resposta remota está sendo carregada pelo navegador -
loaded: Quando o navegador terminou de carregar a resposta remota -
interactive: Quando o usuário pode interagir com a resposta remota, apesar de não ter sido carregada completamente -
success: Quando oXMLHttpRequestestá completo, e o código de status HTTP está na faixa 2XX -
failure: Quando oXMLHttpRequestestá completo, e o código de status HTTP não está na faixa 2XX -
404: Quando a requisição retorna um status 404 -
complete: Quando oXMLHttpRequestestá completo (funciona depois de umsuccessoufailure, se eles estiverem presentes)
Por exemplo, é muito comum mostrar um indicador de carregamento(loading) quando uma chamada remota é iniciada, e escondê-la uma vez que a resposta foi recebida. Para conseguir isto, simplesmente adicione loading(carregando) e complete(completo) aos parâmetros da chamada Ajax, como exibido na Listagem 11-22.
Listagem 11-22 - Usando Eventos do Ajax para Exibir e Esconder um Indicador de Atividade
<div id="retorno"></div> <div id="indicador">Carregando...</div> <?php echo link_to_remote('Delete este post', array( 'update' => 'retorno', 'url' => 'post/delete?id='.$post->getId(), 'loading' => "Element.show('indicador')", 'complete' => "Element.hide('indicador')", )) ?>
Os métodos show(exibir) e hide(esconder), assim como o objeto Element em JavaScript, são outras adições úteis do Prototype.
Criando Efeitos Visuais
Symfony integra os efeitos visuais da biblioteca script.aculo.us, para permitir que você faça mais do que exibir e esconder elementos <div> em suas páginas web. Você irá encontrar ótima documentação sobre a sintaxe dos efeitos no wiki em http://script.aculo.us/. Basicamente, a biblioteca provê objetos em JavaScript e funções que manipulam o DOM de maneira a realizar efeitos visuais complexos. Veja alguns exemplos na Listagem 11-23. Já que o resultado é uma animação visual de algumas áreas da página web, é recomendado que você teste os efeitos você mesmo para compreender o que eles fazem realmente. A página web do script.aculo.us oferece uma galeria, em que você pode ter uma idéia dos efeitos fantásticos.
Listagem 11-23 - Efeitos Visuais em JavaScript com Script.aculo.us
// Realça o elemento 'meu_campo' Effect.Highlight('meu_campo', { startcolor:'#ff99ff', endcolor:'#999999' }) // Esconde um elemento para baixo Effect.BlindDown('id_do_elemento'); // O elemento desaparece Effect.Fade('id_do_elemento', { transition: Effect.Transitions.wobble })
Symfony encapsula o objeto Effect do JavaScript em um auxiliar chamado visual_effect(), ainda parte do grupo de auxiliares do Javascript. Ele produz JavaScript que pode ser usado em uma ligação comum, como exibido na Listagem 11-24.
Listagem 11-24 - Efeitos Visuais em Templates com o auxiliar visual_effect()
<div id="div_secreto" style="display:none">Eu estava aqui o tempo todo!</div> <?php echo link_to_function( 'Exiba o div secreto', visual_effect('appear', 'div_secreto') ) ?> // Irá fazer uma chamada ao Effect.Appear('div_secreto')
O auxiliar visual_effects() pode também ser usado em eventos Ajax, como exibido na Listagem 11-25, que exibe um indicador de atividade como a Listagem 11-22, mas é visualmente mais agradável. O elemento indicador aparece progressivamente quando a chamada Ajax inicia, e desaparece progressivamente quando a resposta conclui. Em adição, o elemento retorno é realçado depois de ser atualizado pela chamada remota, para atrair a atenção do usuário para esta parte da janela.
Listagem 11-25 - Efeitos Visuais em Eventos Ajax
<div id="retorno"></div> <div id="indicador" style="display: none">Carregando...</div> <?php echo link_to_remote('Delete este post', array( 'update' => 'retorno', 'url' => 'post/delete?id='.$post->getId(), 'loading' => visual_effect('appear', 'indicador'), 'complete' => visual_effect('fade', 'indicador'). visual_effect('highlight', 'retorno'), )) ?>
Perceba como você pode combinar efeitos visuais concatenando-os em um evento.
NOJS
Notação Objeto JavaScript (NOJS ou JSON: JavaScript Object Notation) é um formato de troca de dados leve. Basicamente, não é nada mais do que um hash em JavaScript (veja o exemplo na Listagem 11-26) usado para levar informações do objeto. mas NOJS tem duas grandes vantagens para as interações Ajax: É fácil ler em JavaScript, e ele pode reduzir o tamanho da resposta da página web.
Listagem 11-26 - Um simples objeto NOJS em JavaScript
var meusDadosNojs = {"menu": { "id": "arquivo", "value": "Arquivo", "popup": { "menuitem": [ {"value": "Novo", "onclick": "CreateNewDoc()"}, {"value": "Abrir", "onclick": "OpenDoc()"}, {"value": "Fechar", "onclick": "CloseDoc()"} ] } }}
Se uma ação Ajax precisa retornar dados estruturados para uma página chamada para processamento extendido em JavaScript, NOJS é um bom formato para a resposta. Isto é muito útil se, por exemplo, uma chamada Ajax precisa atualizar vários elementos na página chamada.
Por exemplo, imagine uma página chamada que parece com a Listagem 11-27. Ela tem dois elementos que podem precisar ser atualizados. Um auxiliar remoto poderia atualizar apenas um dos elementos da página (ou no titulo ou no nome), mas não nos dois.
Listagem 11-27 - Exemplo de Template para Múltiplas Atualizações Ajax
Carta básica
Querido(a) nome_aqui,
Seu e-mail foi recebido e irá ser respondido em breve.
Sinceramente,
Para atualizar ambos, imagine que a resposta Ajax pode ser um cabeçalho NOJS contendo o seguinte vetor:
[["título", "Minha carta básica"], ["nome", "Sr Pedro"]]
Então a chamada remota pode facilmente interpretar esta resposta e atualizar vários campos em uma linha, com uma pequena ajuda do JavaScript. O código na Listagem 11-28 mostra o que poderia ser adicionado ao template da Listagem 11-27 para conseguirmos este efeito.
Listagem 11-28 - Atualizando Mais de Um Elemento a partir de uma Resposta Remota
<?php echo link_to_remote('Recarregar a carta', array( 'url' => 'publishing/refresh', 'complete' => 'atualizarNOJS(request, json)' )) ?> <?php echo javascript_tag(" function atualizarNOJS(request, nojs) { var nElementosNaResposta = nojs.length; for (var i = 0; i < nElementosNaResposta; i++) { Element.update(nojs[i][0], nojs[i][1]); } } ") ?>
O evento complete tem acesso ao cabeçalho nojs da resposta e pode repassá-lo para uma outra função. A função própria atualizarNOJS() itera sobre o cabeçalho NOJS e para cada membro do vetor, atualiza o elemento nomeado pelo primeiro parâmetro com o conteúdo do segundo parâmetro.
A Listagem 11-29 mostra como a ação publishing/refresh pode retornar uma resposta NOJS.
Listagem 11-29 - Exemplo de Ação Retornando um Cabeçalho NOJS
class publicandoAcoes extends sfActions { public function executaRecarregar() { $saida = '[["título", "Minha carta básica"], ["nome", "Sr Pedro"]]'; $this->getResponse()->setHttpHeader("X-JSON", '('.$saida.')'); return sfView::HEADER_ONLY; }
O protocolo HTTP permite que o NOJS seja armazenado em um cabeçalho de resposta. Como a resposta não possui nenhum conteúdo, a ação envia-o imediatamente como apenas um cabeçalho. Isto ultrapassa a camada de visão completamente e é tão rápido quanto um ->renderText(), mas com uma resposta ainda menor.
CUIDADO Existe uma limitação severa a aproximação exibida na Listagem 11-29: o tamanho máximo de um cabeçalho HTTP. Não existe limitação oficial, mas cabeçalhos grandes podem não ser transferidos ou interpretados pelo navegador corretamente. Isto significa que se o seu vetor NOJS é grande, a ação remota deverá retornar uma resposta normal, com o NOJS como um vetor JavaScript.
NOJS tornou-se um padrão entre as aplicações web. Serviços Web frequentemente propõem respostas em NOJS ao invés de XML para permitir a integração de serviços no cliente (mashup), ao invés do servidor. Então se você estiver perguntando-se qual formato usar para a comunicação entre o seu servidor e uma função JavaScript, NOJS é provavelmente sua melhor escolha.
DICA A partir da versão 5.2, PHP oferece duas funções,
json_encode()ejson_decode(), que permite que você converta um vetor entre a sintaxe do PHP e a sintaxe do NOJS, e vice versa (http://www.php.net/manual/en/ref.json.php). Estas facilitam a integração dos vetores NOJS e Ajax em geral.
Realizando Interações Complexas com Ajax
Entre os auxiliares Ajax no symfony, você também irá encontrar algumas ferramentas que constroem interações complexas com uma única chamada. Eles irão permitir a você melhorar a experiência do usuário através de interações similares a aplicações desktop (arrastar e soltar, autocompletar, e edição instantânea) sem a necessidade de JavaScript complexos. As seguintes seções descrevem os auxiliares para interações complexas e mostra exemplos simples. Parâmetros adicionais e aperfeiçoamentos são descritos na documentação do script.aculo.us.
CUIDADO Se interações complexas são possíveis, elas necessitam de tempo extra para aperfeiçoar sua apresentação e para fazê-las parecer natural. Use-as apenas quando você tem certeza que elas melhoram a experiência do usuário. Evite-as quando existir o risco de que elas desorientem os usuários.
Autocompletar
Um componente de entrada de texto que exibe uma lista de palavras que correspondem a entrada do usuário enquanto o usuário digita é chamado de autocompletar. Com um único auxiliar chamado input_auto_complete_tag(), você pode conseguir este efeito, provido que a ação remota retorne uma resposta formatada como uma lista de itens HTML similar ao exemplo exibido na Listagem 11-30.
Listagem 11-30 - Exemplo de Resposta Compatível com o Marcador Autocomplete
- sugestão1
- sugestão2 ...
Insira o auxiliar no template como você faria com uma entrada de texto comum, seguindo o exemplo mostrado na Listagem 11-31.
Listagem 11-31 - Usando o Marcador Auxiliar Autocomplete em um Template
<?php echo form_tag('meumodulo/minhaacao') ?> Encontre um autor pelo nome: <?php echo input_auto_complete_tag('autor', 'nome padrão', 'autor/autocomplete', array('autocomplete' => 'off'), array('use_style' => true) ) ?> <?php echo submit_tag('Find') ?> </form>
Isto irá chamar a ação autor/autocomplete toda vez que o usuário digitar um carácter no campo autor. Cabe a você construir a ação para que esta determine uma lista de possíveis correspondências de acordo com o parâmetro de requisição autor e retorná-los em um formato similar a Listagem 11-30. Este auxiliar irá, então, exibir a lista abaixo do marcador autor, e clicando em uma das sugestões ou selecionando-as com o teclado irá completar a entrada, como exibido na Figura 11-3.
Figura 11-3 - Um exemplo de autocompletar
O terceiro argumento do auxiliar input_auto_complete_tag() pode receber os seguintes parâmetros:
-
use_style: Aplica um estilo a lista de respostas automaticamente. -
frequency: Frequência da chamada periódica (o padrão é 0.4s). -
tokens: Permite que o autocompletar seja incremental de acordo com um marco. Por exemplo, se você definir este parâmetro para
,e se o usuário escreverjanaina, leitão, a ação receberia apenas o valor'leitão'.
NOTA O auxiliar
input_auto_complete_tag(), como os que vierem a seguir, também aceitam as opções de auxiliar remoto comuns descritas mais cedo neste capítulo. Em particular, é um bom hábito definir os efeitos visuaisloadingecompletepara fornecer ao usuário uma experiência melhor.
Arrastar e Soltar
A abilidade para pegar um elemento com o mouse, movê-lo, e soltá-lo em algum outro lugar é comum em aplicações desktop mas raro em navegadores web. Isto é por que implementar tal comportamento em JavaScript pleno é muito complicado. Felizmente, ele requere apenas uma linha em symfony.
O framework provê dois auxiliares, draggable_element() e drop_receiving_element(), que podem ser vistos como modificadores de comportamento; eles adicionam observadores e abilidades ao elemento a que eles destinam-se. Use-os para declarar um elemento como arrastável ou como um elemento receptor para elementos arrastáveis. Um elemento arrastável pode ser pego através de um clique sobre ele com o mouse. Até que o botão do mouse seja solto, o elemento pode ser movido, ou arrastado, através da janela. Um elemento receptor chama uma função remota quando um elemento arrastável é solto sobre ele. A Listagem 11-32 demonstra este tipo de interação com um carrinho de compras recebendo um elemento.
Listagem 11-32 - Elementos Arrastáveis e Elementos Receptores de Soltura em um Carrinho de Compras
<ul id="itens"> <li id="item_1" class="comida">Cenoura</li> <?php echo draggable_element('item_1', array('revert' => true)) ?> <li id="item_2" class="comida">Maçã</li> <?php echo draggable_element('item_2', array('revert' => true)) ?> <li id="item_3" class="comida">Laranja</li> <?php echo draggable_element('item_3', array('revert' => true)) ?> </li> <div id="carrinho"> <p>Seu carrinho de compras está vazio</p> <p>Arraste itens aqui para adicioná-los ao seu carrinho</p> </div> <?php echo drop_receiving_element('carrinho', array( 'url' => 'carrinho/add', 'accept' => 'comida', 'update' => 'carrinho', )) ?>
Cada um dos itens de uma lista não ordenada podem ser pegos pelo mouse e arrastados através da janela. Quando soltos, eles retornam para a sua posição original. Quando soltos sobre o elemento carrinho, eles disparam uma chamada remota para a ação carrinho/add. A ação irá ser capaz de determinar qual item foi solto no elemento carrinho olhando através do parâmetro de requisição id. Então a Listagem 11-32 simula uma sessão real de compras: Você pega itens e solta-os no carrinho, e então segue para o caixa na saída.
DICA Na Listagem 11-32, os auxiliares são escritos exatamente após o elemento que eles modificam, mas isto não é um requisito. Você poderia muito bem agrupar todos os auxiliares
draggable_element()edrop_receiving_element()ao final do template. A coisa mais importante é o primeiro argumento da chamada do auxiliar, que especifica o identificador do elemento que receberá o comportamento.
O auxiliar draggable_element() aceita os seguintes parâmetros:
-
revert: Se definido comotrue(verdade), o elemento irá retornar a sua posição original quando solto. Também pode receber uma função de referência arbitrária, chamada quando o processo de arrastar termina. -
ghosting: Clona o elemento e arrasta o clone, deixando o original no lugar até que o clone seja solto. -
snap: Se definido comofalse(falso), não ocorre saltos. Caso contrário, o elemento arrastável pode ser arrastado apenas para as interseções de uma grade de intervalo x e y, e neste caso, ele recebe a formaxyou[x,y]oufunction(x,y){ return [x,y] }.
O auxiliar drop_receiving_element() aceita os seguintes parâmetros:
-
accept: Um texto ou um vetor de texto descrevendo as classes CSS. O elemento irá aceitar apenas elementos arrastáveis que tem um ou mais destas classes CSS. -
hoverclass: Uma classe CSS adicionada ao elemento, quando o usuário arrasta um elemento arrastável aceito sobre ele.
Listas Ordenáveis
Uma outra possibilidade oferecida por elementos arrastáveis é a abilidade de ordenar uma lista movendo seus itens com o mouse. O auxiliar sortable_element() adiciona o comportamento de ordenação para um item, e a Listagem 11-33 é um bom exemplo de uma implementação desta característica.
Listagem 11-33 - Exemplo de Lista Ordenável
<p>O que você gosta mais?</p> <ul id="ordem"> <li id="item_1" class="ordenavel">Cenouras</li> <li id="item_2" class="ordenavel">Maçãs</li> <li id="item_3" class="ordenavel">Laranjas</li> // Ninguém gosta de Couve-de-bruxelas de qualquer forma <li id="item_4">Couve-de-bruxelas</li> </ul> <div id="retorno"></div> <?php echo sortable_element('ordem', array( 'url' => 'item/sort', 'update' => 'retorno', 'only' => 'ordenavel'; )) ?>
Através de mágica do auxiliar sortable_element(), o elemento <ul> torna-se ordenável, o que significa que seus filhos podem ser reordenados pelo Arrastar e Soltar. Cada vez que o usuário arrasta um item e solta-o para reordenar a lista, uma requisição Ajax é feita com os seguintes parâmetros:
POST /sf_sandbox/web/frontend_dev.php/item/sort HTTP/1.1
ordem[]=1&ordem[]=3&ordem[]=2&_=
A lista completamente ordenada é passada como um vetor (com o formato ordem[$ranque]=$id, o $ranque começando em 0, e o $id baseado no que vem depois do sublinhado ou traço baixo (_) na propriedade id do elemento da lista). A propriedade id dos elementos ordenáveis (ordem no exemplo) é usado para nomear o vetor de parâmetros.
O auxiliar sortable_element() aceita os seguintes parâmetros:
-
only: Um texto ou um vetor de texto descrevendo classes CSS. Apenas os elementos filhos do elemento ordenável com esta classe podem ser movidos. -
hoverclass: classe CSS adicionada ao elemento quando o mouse é passado sobre ele. -
overlap: Defina-o comohorizontalse os itens são exibidos em uma linha, e comovertical(o valor padrão) quando existe um item por linha (como no exemplo). -
tag: Se a lista a ser ordernada não é um conjunto de elementos<li>, você deve definir quais elementos filhos do elemento ordenável devem se tornar arrastáveis (por exemplo,divoudl).
Editar no Local
Mais e mais aplicações web permitem aos usuários editar os conteúdos das páginas diretamente na página, sem a necessidade de exibir outra vez o conteúdo em um formulário. O princípio desta interação é simples. Um bloco de texto é realçado quando o usuário passa o mouse sobre ele. Se o usuário clica dentro do bloco, o texto pleno é convertido em uma área de texto preenchida com o texto do bloco, e um botão de salvar aparece. O usuário pode editar o texto dentro da área de texto, e uma vez que ele o salva, a área de texto desaparece e o texto é exibido em formulário pleno. Com symfony, você pode adicionar este comportamento editável para um elemento com o auxiliar input_in_place_editor_tag(). A Listagem 11-34 demonstra o uso deste auxiliar.
Listagem 11-34 - Exemplo de Texto Editável
<div id="me_edite">Você pode editar este texto</div> <?php echo input_in_place_editor_tag('me_edite', 'meumodulo/minhaacao', array( 'cols' => 40, 'rows' => 10, )) ?>
Quando o usuário clica no texto editável, ele é substituído por uma área de entrada de texto, preenchida com o texto, a qual pode ser editada. Quando o formulário é submetido, a ação meumodulo/minhaacao é chamada no Ajax com o valor editado definido como o parâmetro value. O resultado desta ação atualiza o elemento editável. É muito rápido de escrever e muito poderoso.
O auxiliar input_in_place_editor_tag() aceita os seguintes parâmetros:
-
colserows: O tamanho da área de entrada de texto que aparece para edição (torna-se um<textarea>serowsé maior do que 1). -
loadTextURL: O URI de uma ação que é chamada para exibir o texto para editar. Isto é bastante útil, se o conteúdo do elemento editável usar formatação especial e se você quiser que o usuário possa editar o texto sem a formatação. -
save_textecancel_text: O texto na ligação para salvar (o padrão é "ok") e na ligação para cancelar (o padrão é "cancel").
Sumário
Se você está cansado de escrever JavaScript em seus templates para conseguir comportamentos no lado cliente, os auxiliares JavaScript oferecem uma alternativa simples. Não apenas eles automatizam o comportamento básico de uma ligação e a atualização de elementos, mas eles também provêem uma maneira de desenvolver interações Ajax em um instante. Com a ajuda de poderosas melhorias na sintaxe providas pelo Prototype e os excelentes efeitos visuais providos pelo script.aculo.us, até mesmo interações complexas não precisam mais do que algumas linhas para serem escritas.
A partir do momento que fazer uma aplicação altamente interativa é tão fácil quanto fazer páginas estáticas com symfony, você pode considerar que quase todas as interações de aplicações desktop estão agora disponíveis em aplicações web.
Attachments
- F1101.png (1.8 kB) -
Disparando uma ação remota com uma hiperligação
, added by rafastv on 06/17/08 20:20:45. - F1102.png (2.5 kB) -
Lançando uma atualização remota com um formulário
, added by rafastv on 06/17/08 20:21:29. - F1103.png (2.1 kB) -
Um exemplo de autocompletar
, added by rafastv on 06/17/08 20:22:08.


