Mostrando entradas con la etiqueta ajax. Mostrar todas las entradas
Mostrando entradas con la etiqueta ajax. Mostrar todas las entradas

viernes, 13 de abril de 2012

ModSecurity y Ajax Upload

Al cambiar de hosting un proyecto me encontré con un problema pues dejó de funcionar mi módulo de subida de archivos.
Con la ayuda de los logs del servidor y del soporte técnico de Dinahosting localizamos que el problema tenía que ver con ModSecurity y, después de un buen rato de investigación, llegué a la conclusión de que la cusa tenía que estar en el código javascript, que en mi caso es el Valums Ajax File Uploader
La solcuión final es realmente curiosa. Hay que evitar que la petición Ajax especifique la cabecera Content-Type.

lunes, 20 de septiembre de 2010

CakePHP y Javascript

En principio, no necesitas hacer nada especial para incorporar código javascript en las vistas de tu aplicación CakePHP, aparte de escribir el código, naturalmente. Simplemente has de insertarlo tal y como lo harías en cualquier documento HTML: utilizando la etiqueta script.


<script type="text/javascript" charset="utf-8">
 // Código
</script>


Por supuesto, en algún momento necesitarás utilizar scripts que se encuentren en archivos .js, convenientemente guardados en la carpeta js del webroot de tu aplicación. Para esta tarea es buena idea recurrir a HtmlHelper en CakePHP 1.3 (o a JavascriptHelper en la versión 1.2), ya que lo enlazará correctamente incluso si tu instalación de Cake está muy personalizada.

Por ejemplo:


<?php echo $this->Html->script('jquery.form', array('inline' => false)); ?>


o bien


<?php echo $javascript->link('ckeditor/ckeditor', NULL, false);  ?>


En estos ejemplos, puedes ver que para llamar al archivo javascript no es necesario incluir la extensión y que si el script se encuentra en una subcarpeta de js, hay que incluirlo en el nombre.

Por otro lado, la opción "inline" = false (en el segundo ejemplo, se correspondería con el tercer parámetro del método link) hace que la llamada a nuestro script se incluya en la cabecera del documento. Más exactamente allí donde hayamos realizado un echo $scripts_for_layout. De no indicar nada o ponerlo en true, el script se incluirá en el lugar de la vista donde realicemos el echo.

Puesto que todo lo que acontece en Javascript está en el lado del cliente, no hay más de lo que debas preocuparte en lo que respecta a la aplicación, exceptuando, claro está, el caso de trabajar con Ajax que veremos dentro de un momento, tras un pequeño inciso.

Los helpers Ajax/Javascript han transmutado en Js

La presencia del JavascriptHelper (y de AjaxHelper) en la versión 1.2 o del JsHelper en la versión 1.3 pueden llevarte a pensar que son de algún modo necesarios para poder trabajar con Javascript en una aplicación CakePHP.

Como decía al principio, esto no es así. Realmente no los necesitas si no quieres usarlos, pero te pueden echar una mano, que para eso están. Estos Helpers están ahí para ayudarte a generar algunos bloques de código más o menos típicos y repetitivos de la manera más sencilla posible.

Con todo, en la versión 1.2 podían resultar hasta un poco estorbo, ya que, el AjaxHelper en particular está basado en la librería Prototype, mientras que mucha gente opta desde hace tiempo por otras como jQuery o MooTools.

A consecuencia de esta constatación, el equipo de CakePHP decidió unificar AjaxHelper y JavascriptHelper en el nuevo JsHelper, con la ventaja añadida de poder definir qué framework Javascript preferimos utilizar. Por otro lado, un par de funciones que eran responsabilidad de JavascriptHelper han pasado a HtmlHelper. En concreto, la JavascriptHelper->link() es ahora HtmlHelper->script(), y JavascriptHelper->codeBlock() pasa a ser HtmlHelper->codeBlock(), lo que tiene bastante lógica.

Ajax

Ajax nos puede plantear algunos problemas particulares, ya que se trata básicamente de Javascript que interacciona con nuestra aplicación en segundo plano. Y, si bien, podemos organizar las cosas de modo que aprovechemos el código, debemos tener en cuenta algunos puntos.

RequestHandler Component

Para empezar, nos interesa recurrir a este componente especializado en gestionar información sobre las peticiones que recibe la aplicación y las respuestas que envía.

En general, suelo ponerlo en AppController, pues me puede interesar su uso en muchos lugares distintos de la aplicación. Aunque para usarlo basta incluirlo en el array de components del controlador que lo necesite.

En el caso que nos ocupa, es decir, procesar peticiones que vienen a través de Ajax, RequestHandler nos permite identificarlas mediante el método isAjax(), que devuelve true en el caso que te puedes imaginar. Además, preselecciona por nosotros el layout Ajax (básicamente un layout vacío que solo mostrará el contenido de la vista que toque).

De este modo, podemos bifurcar una acción para hacer cosas distintas si ha sido solicitada a través de Ajax o no. O también podemos asegurarnos de que una acción sólo se ejecuta si se ha pedido por Ajax.

RequestHandler identifica una petición Ajax cuando viene marcada con una cabecera determinada. Esto puede ser un problema si acción no es solicitada a través del objeto XHttpRequest. Por ejemplo, si se utiliza la técnica de iframes, en principio la petición es indistinguible de una petición estándar. En este caso se pueden llevar a cabo diferentes estrategias, como pueden ser "marcar" de algún modo la petición para interpretarla correctamente en el servidor, o bien tener una acción del controlador específica para procesar esa circunstancia, acción a la que "apuntaría" nuestro iframe.

En cualquier caso, dedicar una o varias acciones a procesar peticiones Ajax puede ser un buen planteamiento aunque depende de los casos y de lo "DRY" que quieras mantener el código.

Ajax y Auth

Otro problema que puede aparecer cuando utilizamos peticiones Ajax es que se produce un problema relacionado con el funcionamiento de AuthComponent y el comportamiento de algunos navegadores.

Si una acción requiere que el usuario esté autentificado, la petición Ajax falla porque Auth no reconoce que el usuario está autentificado y redirige al login.

Para dar como autentificado a un usuario, AuthComponent se basa no sólo en los datos de login almacenado en la sesión, sino que en cada recarga comprueba que la sesión no ha sido "secuestrada" por un nuevo agente de usuario. Si observas el contenido de $_SESSION en una aplicación CakePHP verás una variable Agent que identifica al navegador, junto con las demás variables.

En varios navegadores XHttpRequest genera una nueva identificación de agente lo que provoca que CakePHP considere inválida la información de autentificación almacenada en la sesión y vuelva a solicitar al usuario que se conecte mostrando la vista de login.

Una posible solución es poner en false la variable de configuración "Session.checkAgent" en core.php. También puedes deshabilitar este chequeo de forma temporal en la propia petición sólo si esta se hace a través de Ajax y antes de que Auth entre en acción. En AppController puedes poner:


function beforeFilter() {
    parent::beforeFilter();
    if ($this->RequestHandler->isAjax()) {
        Configure::write('Session.checkAgent', false);
    }
    // debug($this->params);
    $this->Auth->allow('display');
}


Otra técnica consiste en reiniciar a mano la sesión.

Respuestas Ajax

Las respuestas Ajax también pueden necesitar un pequeño ajuste antes de ser enviadas de vuelta al cliente.

Si la respuesta generada y esperada es HTML no tendrás que hacer nada especial, pero si la respuesta es JSON es posible que debas enviar una cabecera adecuada para que el navegador se entere de que se trata de JSON y no de otra cosa. Además, debes evitar que intente descargarlo, cosa que ocurre si envías lo que parece la cabecera propia de JSON: application/json.

En mi caso, la cabecera que ha funcionado es application/javascript.

Para ello, podemos utilizar también RequestHandler, indicando que vamos a enviar Javascript.


$this->RequestHandler->respondAs('js');


(Me surge ahora la dudo de si esto es lo que se considera Literal Javascript).

Debug

En muchos casos, aunque no necesariamente en todos, tendrás que poner el modo de debug de CakePHP a cero para que la respuesta Ajax sea aceptable. De otro modo, la información de debug puede hacer irreconocible la respuesta para el lado del cliente (no suele dar problemas si es una respuesta HTML que vaya a mostrarse en un elmento), pero seguro que los dará si es JSON o XML, que son formatos bien estructurados.

Simplemente, añade la línea


Configure::write('debug',0);


en el código que desarrolla la respuesta Ajax.

En estos casos, lo mejor es que hagas un log con la información que necesites para depuración.

Herramientas

Para comprobar el buen funcionamiento de tu código Javascript asegúrate de instalar FireBug en Firefox o activar las herramientas de Desarrollo en Safari (y otros navegadores basados en Webkit, como Chrome).

En ambos podrás estudiar el funcionamiento del código Javascript (marcando puntos de parada, inspeccionando variables y objetos...), así como las solicitudes y respuestas Ajax, lo cual también te ayudará a comprender cómo funcionan las cosas.

domingo, 19 de septiembre de 2010

Javascript y Ajax para torpes (como yo)

Tengo que confesar que tengo un problema con Javascript. Me cuesta mucho entender este lenguaje y, por tanto, utilizarlo. Claro que, a día de hoy, es ya una herramienta imprescindible.

Gracias a una parte del proyecto en el que estoy ahora mismo trabajando he tenido que empezar a plantearme en serio el uso de javascript en la aplicación y como parte de ese aprendizaje voy a dejar caer por aquí algunas anotaciones al respecto.

Esta primera anotación no es un tutorial, sino más bien una clarificación de conceptos sobre el lenguaje en sí, Ajax y otros temas relacionadas. Así que vamos allá:

Javascript

Para más información consulta la entrada Javascript en Wikipedia.

Javascript es un lenguaje de scripting orientado a objetos que está integrado en navegadores web, de modo que el código reside normalmente (o es incluido desde un archivo externo) en un documento HTML.

Quizá la característica más relevante de Javascript es que el lenguaje nos da acceso a una representación del documento HTML. Esta representación es el DOM (Modelo de Documento-Objeto) y nos permite interactuar de forma directa con los elementos de la página. En otras palabras, podemos obtener sus contenidos y modificarlos.

Parte de las dificultades prácticas de la programación en Javascript residen precisamente en la mayor o menor facilidad que tenemos para acceder a un elemento o grupo de elementos con los que necesitemos trabajar. El objeto document posee el método getElementById() que nos permite obtener un elemento si sabemos su atributo id. Sin embargo, esto a veces no es suficiente, ya que nos puede interesar obtener elementos por su clase, por tipo, o por otra forma de selección.

Esto se puede conseguir en el propio lenguaje escribiendo funciones específicas, lo cual ha dado lugar a que se hayan desarrollado diversos frameworks que complementan el Javascript original.

Frameworks

Para evitar estas dificultades y añadir diversas funcionalidades generales, se han creado frameworks o bibliotecas. Algunos ejemplos son jQuery, MooTools, Prototype...

Uno de los métodos de selección que han aportado estas bibliotecas es el uso de la sintaxis de selectores CSS. Es decir, gracias a estos frameworks podemos hacer selecciones de elementos tal y como lo haríamos en CSS, lo cual nos da acceso a cualquier elemento, o familia de ellos, presente en el documento, de una forma sencilla y reutilizando un conocimiento que ya tenemos.

Además, el uso de estos frameworks proporciona una normalización de acceso a propiedades y métodos que facilita la programación.

XHttpRequest

Una de las adiciones más significativas en Javascript fue la inclusión de la clase XHttpRequest, que proporciona al lenguaje la capacidad de enviar peticiones a servidores a través del protocolo HTTP y utilizar la respuesta recibida.

Estas peticiones se hacen, por así decir, desde "dentro" la página web "programáticamente", sin necesidad de recargarla. Y esto nos lleva a Ajax.

Ajax

Más información sobre Ajax

Ajax es una técnica o conjunto de técnicas que se basan en la comunicación en segundo plano entre una página web y el servidor, enviando o recogiendo información que se utiliza para modificar partes de la propia página.

Ajax presenta varias ventajas, siendo la principal que permite una actualización de contenidos en una página en tiempo real (o cuasi-real) sin necesidad de recargar la totalidad de la página y, por tanto, sin interrumpir la actividad del usuario en la misma.

Así, por ejemplo, es posible proporcionar prestaciones como:


  • Widgets o módulos de contenido que se actualizan en tiempo real, como podría ser un módulo de usuarios conectados, algún tipo de chat, etc.
  • Formularios que realizan cálculos con los datos que va introduciendo el usuario sin que éste tenga que enviarlos (incluso cuando esos cálculos requieran consultas al servidor).
  • Formularios que se autoguardan periódicamente para que el usuario no pierda el contenido introducido.
  • En general, cualquier tipo de interacción con el servidor que deba hacerse sin actividad explícita del usuario y sin recargar la página completa.


Ventajas del uso de Ajax son:


  • No interrumpimos la actividad principal que el usuario está llevando a cabo en la página, ya que la petición y actualización se realizan en segundo plano y sin recargar la totalidad de la página.
  • Ahorramos ancho de banda en las peticiones, ya que la solicitud se hace por una información concreta y se interpreta en el navegador sólo en las partes de la página afectadas, evitando tener que recargar información o contenido que ya estaba en la página.
  • Un comportamiento más ágil de la página y más similar a la experiencia de aplicaciones de escritorio.

La respuesta Ajax

La petición enviada por Ajax nos permite obtener una respuesta del servidor. Lógicamente, nuestra aplicación web tiene que saber recibir la petición y darle una respuesta adecuada. Esta respuesta puede adoptar varios formatos, de los que destacan tres, que se utilizarían según el tipo de manipulación que necesitamos hacer en el lado del cliente:

Si necesitamos actualizar un elemento específico lo mejor sería dar una respuesta HTML, es decir, el servidor obtiene la información y la empaqueta como un fragmento HTML. El código javascript del cliente no tiene más que actualizar la propiedad html del elemento al que vaya dirigida asignándole el contenido de la respuesta. Es la solución ideal para widgets o módulos de página.

Si necesitamos post-procesar la respuesta en la página, bien porque debemos utilizar partes de la misma en distintos elementos, bien porque necesitamos operar de distintas formas con ella, la respuesta adecuada sería en formato JSON. Json es una notación de objetos javascript que puede ser utilizada directamente desde el lenguaje a través de la función eval(), aunque puede utilizarse LJS (Javascript literal) como alternativa si sólo se envían datos, de modo que no se usa eval().

Esto lleva al planteamiento de cuestiones de seguridad, ya que eval() es una coladera para todo tipo de código construido de forma maliciosa, por lo que el uso de JSON en principio debe limitarse a intercambios cliente-servidor "de confianza". En general, no habría problema en entornos de una aplicación web que genera páginas que deben interactuar vía Ajax con el propio servidor.

Por tanto, si la seguridad es una característica crítica, y en particular en interacciones entre servidores (como por ejemplo si expones APIs), la respuesta del servidor debería darse en XML.

Javascript, Ajax y CakePHP lo dejo para la próxima anotación.

miércoles, 12 de noviembre de 2008

$ajax->div sirve para algo

Trabajando hoy en el tema de Ajax me he dado cuenta de que si no utilizas $ajax->div('identificador') para crear los elementos que se han de actualizar mediante peticiones Ajax, las cosas no funcionan bien y se carga la vista entera, con layout y todo, aún con el RequestHandler.

Basta utilizar este método y cerrar con $ajax->divEnd('identificador') para que funcione perfectamente.

lunes, 18 de febrero de 2008

Safari, AjaxHelper y las codificaciones

Safari es un buen navegador, pero a veces tiene sus "cositas".

La última que he descubierto es un problema con las codificaciones y las llamadas Ajax. El caso es que éstas llamadas me volvían con caracteres mal codificados. Sin embargo, hasta que no lo probé en Firefox no caí que era un problema de Safari, y no de mi forma de trabajar con el Ajax Helper de CakePHP.

El problema concreto lo explican en este artículo, y tiene que ver con un fallo de la configuración del servidor donde alojemos la aplicación, combinado con un fallo de Safari a la hora de determinar cómo se codifica el contenido que se devuelve a una petición Ajax.

Sencillamente, si el servidor no tiene como juego de caracteres por defecto UTF-8, Safari tampoco sabe cómo manejar esa situación correctamente. Resultado: la codificación sale mal.

La solución:

Si tienes acceso a la configuración del servidor, o al htaccess de la raíz de la aplicación, añade esta línea:

AddDefaultCharset UTF-8


Si no, pide al adminsitrador del servidor que lo haga o que te prepare el servidor para servir contenido UTF-8.

Y con esto funciona estupendamente. (Hay pseudosoluciones a base de enviar cabeceras desde la aplicación, pero a mí no me ha funcionado ninguna de ellas).

miércoles, 13 de junio de 2007

Más cornás da el Ajax (¿o era el hambre...?) (Muy actualizado)

Llevo todo el día dándome cabezazos contra una tontería que al final no tiene que ver con Ajax (o eso creo).

Resulta que en mi experimento de formulario + tabla, el formulario se empeñaba en mantener lo escrito con una constancia digna de mayor causa. Eso no es malo, lo malo es que se mantenía incluso cuando no lo necesitaba, o sea, cuando los datos habían sido enviados, validados y guardados. Se supone que $('formulario').reset() (una función de prototype) tendría que hacer el trabajo. Pero, ¡que si quieres arroz Catalina!

Así que me he pasado horas intentando entender ¿por qué? sin que haya conseguido una respuesta clarificadora. En algún lugar encontré una referencia a la necesidad de asegurarse de mantener el contenido tecleado en un formulario incluso entre refrescos de páginas. Es de agradecer que Cake? Ajax? (no lo sé todavía?) lo mantengan, pero no había conseguido vaciar los campos del formulario recorriendo a Ajax o Javascript.

[... Mala solución borrada por el autor ...]

¡Borra Controller::data, idiota!

La solución final viene por vía de Cake y gracias a Geoff Ford en el grupo Google de CakePHP, así que ¡gracias Geoff!

La solución, por supuesto, es trivial:

Cuando enviamos un formulario cubierto pulsando el botón Submit correspondiente, CakePHP puebla la variable Controller::data (el $this->data que le pasamos a Model::save) con los datos procedentes de POST. Esto es lo normal.

Pero resulta que yo estoy pidiendo que se vuelva a mostrar el formulario justo en el mismo ciclo que cuando salvamos los datos, por lo tanto, Controller::data sigue llevando los datos de POST y, en consecuencia, cuando se dibuja la vista ahí siguen los datos.

Tan sólo hay que vaciar Controller::data para que no se pase ningún valor al formulario. Tan simple como eso.

Dos cosas más
  1. Controller::data es el mecanismo que usa Cake para que no se pierdan los datos existentes en el formulario si éstos no validan y tiene que redibujar el formulario en el mismo ciclo.
  2. Hay persistencia de los datos en el formulario incluso recargando la página. Eso es muy bueno.
  3. En el planteamiento "típico" en que el formulario de añadir datos se retira de la vista al enviarlo, los datos del Post se pierden una vez utilizados. Al volver a llamar al formulario, este se muestra vacío... porque estamos en otro ciclo.
  4. Ajax no tenía nada que ver en esto.

martes, 12 de junio de 2007

Organizando las vistas para Ajax

Siguiendo con el ejercicio anterior he descubierto unas cuantas cosas más. Por ejemplo, los problemas que supone la validación CakePHP interaccionando con un planteamiento "ajaxiano" de la vista.

La solución que he encontrado es la siguiente:

De lo general a lo particular

Lo primero sería hacer un croquis general de lo que voy a necesitar poner en la vista. En mi caso, por ejemplo, un título, un formulario y una tabla. Hay que tener en cuenta las partes que se van a tener que actualizar solas, en un momento dado, o las que habrá que actualizar globalmente.

Lo mejor parece ser descomponer la vista en partes, valorando si necesitan ser incluidas en una div, y crear elements para generar cada una de ellas. De este modo dispondremos de piezas de construcción para generar las vistas definitivas. Procura ponerles nombres bien descriptivos a los elementos.

Preparando las vistas

Con los elements ya preparados generamos las vistas que nos haga falta, aprovechando el método This::Element ('elemento').

La idea es crear tantas vistas como podamos necesitar. Intentaré explicarlo:

Normalmente la primera petición para cierta página será una petición normal, sin Ajax ni cosas raras. Entonces tendremos que tener una vista que muestre todo lo necesario. En mi ejemplo, una vista que muestre el título, el formulario y la tabla. Esa podría ser index.ctp, si mi acción es index.

Como mi tabla tiene enlaces Ajax para ordenar los resultados y éstos piden que se actualice sólo la div que contiene la tabla, necesitaré una vista que sólo muestre la tabla. La llamaré tabla.ctp.

El formulario envía una petición Ajax al servidor para añadir entradas sin actualizar toda la página. El resultado del formulario debería actualizar la tabla, pero puede ocurrir que tenga que actualizarse también el propio formulario, por ejemplo si hay errores en la validación en CakePHP. En este caso, podría crear una nueva plantilla, aunque veo que index.ctp me sirve para esto sin tener que duplicar el trabajo.

También podría preparar una vista específica para cuando se solicita la acción con una petición no Ajax.

Y luego están las vistas para las demás acciones que programemos, por supuesto. En ellas hay que considerar los mismos aspectos acerca de si es posible que sean solicitadas a través de Ajax y qué contenido deben proporcionar.

En el controlador

Ahora bien, en el controlador tenemos que determinar qué tipo de petición está entrando y qué contenido tenemos que devolver. Tenemos dos armas:

RequestHandler->isAjax() es el método que nos permite saber si la petición es Ajax y hacer cosas diferentes en cada caso.

Controller::Render ('vista') nos permite especificar una vista concreta con la que mostrar el resultado de la acción.

Usándolas en combinación, podemos hacer que nuestra acción sepa qué contenido debe entregar a la petición Ajax (o de cualquier otro tipo) y mediante qué vista.

No te olvides de generar el contenido

Eso sí, hay que tener presente qué contenido es el que vamos a actualizar, porque las cosas pueden ser un poco diferentes que en el uso normal.

Por ejemplo, en este caso de la combinación de formulario de entrada más tabla de datos, he decidido que al añadir una entrada hay que actualizar la vista que contiene tanto el formulario como la tabla. Por lo tanto, la acción add, cuando es llamada mediante Ajax, tiene que lidiar no sólo con tomar los datos y hacer lo que haga falta con ellos, sino también obtener el listado para mostrar como si fuera una acción index y enviárselos a la vista index, en vez de a la vista por defecto (add).

Alternativamente, la versión "no Ajax" de la acción podría usar una vista diferente y necesitar información diferente.

Otros beneficios

Algunas de las ideas expuestas aquí, aparte de ser útiles e incluso necesarias para integrar Ajax, tienen algunos beneficios colaterales.

Al descomponer una vista, o una familia de vistas, en elementos reutilizables es más fácil, por ejemplo tener un único formulario para añadir y editar. Estamos siguiendo eso que llaman la metodología DRY (Don't Repeat Yourself).

Otro beneficio es que si una parte de una vista es relativamente complicada, al empaquetarla en un element podemos mantener controlada esa complejidad.

lunes, 11 de junio de 2007

Ajax... qué lío

Acabo de hacer algo intencionadamente con Ajax. Quiero decir que no es como el PaginatorHelper, que te lo hace todo. O sea: que me he planteado un pequeño ejercicio con Ajax y me ha salido.

Eso sí, con cierto esfuerzo. Voy a intentar poner aqui las ideas que han ido surgiendo, aunque no creo que ponga código, al menos de momento. Entre otras cosas, porque no está conseguido todo lo necesario para considerarlo completo.

El ejercicio

Consistía en combinar un formulario para añadir entradas en un tabla (citas o frases célebres y su autor) con la propia tabla. Al escribir una nueva frase en el formulario y pulsar el botón de enviar tendría que actualizarse la tabla.

La función de las técnicas Ajax aquí es enviar los datos del formulario al servidor, elicitar la acción add correspondiente en el controlador y recoger el nuevo contenido de la tabla

Suena bien. Hacerlo tiene truco.

Lo primero es planificar un poco la página que se va a generar y ver cuántas zonas (div) necesitamos establecer. En principio, aquí debería llegarnos con una para el formulario y otra para la tabla.

Luego habría que tener vistas para generar el contenido de cada una de estas partes, más una vista que las combine todas. Las vistas de partes serían para actualizar cada div cuando toque, la vista combinada sería para usar la primera vez.

Esta es una parte que no tengo del todo clara cómo organizar. El tutorial que he seguido está basado en la versión 1.1 de CakePHP y algunas cosas no son exactamente iguales.

Por una parte, es posible utilizar Controller::render($vista, 'ajax') para explicitar la vista que queremos mostrar usando el modo "Ajax". Combinando eso con una consulta Controller::ResquestHandler->isAjax () para ver si la petición nos la hace Ajax, podemos hacer que un mismo controlador extraiga los datos necesarios y decida si debe devolver la vista "normal" o la actualización "ajax". No sé si me explico.

Ejemplo. La acción index podría tener una view asociada, llamada también index, que genere tanto el formulario como la tabla de datos (¿me sigues?) y que usaría ante una petición normal. Por otro lado, podríamos escribir una view para actualizar sólo la parte de la tabla y que se usaría para atender una petición Ajax.

Nos quedaría algo así:


function index () {
$data = $this->Paginate ();
$this->set ('frases', $data);
if ($this->RequestHandler->isAjax()) {
$this->render ('tabla');
}
}
No sé si se aprecia bien. El último if nos permite indicar una view específica que genera el contenido que queremos devolver.

Recuerda que tenemos que usar el component RequestHandler y llamar a su método startup en beforeFilter para que funcionen bien estas peticiones Ajax (de otro modo, se empeña en devolverlas con layout y esto es un despiporre).

Las acciones implicadas tienen que saber qué actualizan

Esto me hizo rascarme la cabeza un montón hasta que cai de la burra. Resulta que en mi ejercicio todo funcionaba bien hasta que añadía una entrada a la tabla y trataba de ordenar ésta. Bueno, pues se añadían más entradas, y se generaba un error del layout y no salía la tabla.

Bien. Resulta que el boton de enviar el formulario llamaba a la acción add del controlador. Correcto. Pero la acción add, aparte de añadir el nuevo registro, tiene que volver a pedir los datos para mostrar la tabla. Eso por un lado.

(Nota: lo que no he mirado es si sería más adecuado y económico llamar a la acción index...).

Por otro lado, hay que controlar que la acción add dibuje la vista que genera el contenido de la tabla (en el ejemplo de arriba, es tabla.ctp, en lugar de su add.ctp que dibujaría normalmente), al menos cuando es llamada por Ajax. Si no es llamada por Ajax debería dibujar su vista normal, o hacer algo que le explique al usuario qué pasa o qué puede hacer.

Y, por último...

Más cosillas a las que prestar atención

Al generar enlaces o botones que hagan llamadas Ajax hay que asegurarse de que llaman a la acción adecuada del controlador adecuado. Es posible que tengas que especificar explícitamente la acción y no dejar que sea CakePHP el encargado.

Esto es así porque si dibujamos una vista desde una acción que no es la "propia" (como en el apartado anterior que dibujábamos tabla desde index, pero también desde add, Cake interpreta que esos enlaces se dirigen a la acción "generadora", si no hemos indicado otra.

En mi ejemplo, debo especificar en las opciones del paginador de la tabla, que la acción a la que llaman los enlaces Ajax que ordenan la tabla ha de ser siempre index.

Ya puestos, vamos con Ajax

Un artículo recopila enlaces sobre Ajax y CakePHP. Ya contaré cómo me va.

Una de Axaj: haciendo que los Ajax Request no recarguen todo

CakePHP incluye un Helper para Ajax y cosas como el PaginatorHelper hacen uso de Ajax.

Yo no es que tenga mucha idea del asunto, pero al hacer mis primeros experimentos de paginación me encontré con el problema de que en vez de actualizarse los listados, se me actualizaba toda la página en el espacio del listado.

La solución es básicamente decirle al controlador que cuando reciba una petición desde Ajax que genera la vista teniendo eso en cuenta. Después de reinventar la rueda varias veces, resulta que lo único que hay que hacer es añadir esto a los controladores que tengan vistas que usan Ajax:


var $components = array ('RequestHandler');

function beforeFilter () {
$this->RequestHandler->startup ($this);
}


Y, si aún así, necesitas controlar peticiones Ajax en algún punto del controlador o en alguna acción, no tienes más que hacer un simple:


if ($this->RequestHandler->isAjax ()) {
// Es Ajax
} else {
// Es otra cosa
}