jueves, 8 de septiembre de 2011

Sobre el reenvío de formularios via POST


A todo el mundo le ha pasado que en una aplicación web hay un formulario, la data se envía por POST, se realiza alguna acción con esa data, se muestra algo al usuario, el usuario pincha un link para ir a otra página del sitio, luego le da al botón Atrás y... ¡PUM! El navegador muestra al usuario ese horrible mensaje de que debe reenviar la información del formulario. Pasa en eztv.it, por ejemplo.

No es un bug de la aplicación, ni del navegador, pero es simplemente es desastroso para la imagen de nuestra aplicación frente al cliente.

Solución 1

Existen diversas formas de tratar el problema. La solución obvia, es no usar POST, sino GET. Particularmente no me gusta el método GET, pero si enviamos la data del formulario por esta via, no tendremos el problema, pues va en la propia URL.

Solución 2

Usar POST, pero con Ajax. Simple y elegante. Enviamos via AJAX nuestra mensaje POST a un método que nos devuelva el código HTML de la data que queremos y lo incrustamos en el DIV que tengamos destinados para mostrar la data. Con JQuery, por ejemplo hacer esto es realmente sencillo.

Ejemplo

Voy a mostrar un pequeño ejemplo, utilizando la librería KumbiaPHP con JQuery. Queremos una página para buscar (y listar) clientes de una tabla de clientes en BD. En la vista tenemos un campo input para que el usuario introduzca la palabra clave y un botón de submit

El controlador cliente_controller.php:

<?php
Load::models('cliente');

class ClienteController extends AppController
{
	public function index()
	{
		$cliente = new cliente();

		if(Input::hasPost('search_key'))
		{
			$search_key = Input::post('search_key');
			$this->clientes = $cliente->selectClienteByCedulaLike($search_key);
			View::select('p_clientes');
			View::template(null);
		}
		else
		{
			$this->clientes = null;
		}
	}
}
?>

La vista index.phtml:

<script type="text/javascript">
$(function() {
	$('#validateform').submit(function() {
		var url = $(location).attr('href');
		var key = $('#cedula').val();
		$.post( url,
		{ search_key: key },
			function(data){
			var capa = $('#tablecontainer');
			capa.html(data);
		});
		return false;
	});
});
</script>

<div id="content">

	<div id="page-heading"><h1>Gestión de Clientes</h1></div>

	<!--  start searchForm  -->
	<?php echo Form::open('','post','id="validateform"'); ?>
	<table>
	<tr>
	<td><?php echo Form::text('cedula','class="inp-form"') ?></td>
	<td><?php echo Form::submit('Buscar', 'class="form-search"') ?></td>
	</tr>
	</table>
	<?php echo Form::close() ?>
	<!--  end searchForm -->

	<div> </div>
	<div class="clear"></div>

	<!--  start client-table -->
	<div id="tablecontainer">
	<!--  Aqui es donde ira el contenido que luego incluiremos via Ajax -->
	</div>
	<!--  end client-table -->
</div>

La vista en la que crearemos la tabla p_clientes.phtml:

<table border="0" width="100%" cellpadding="0" cellspacing="0" id="client-table">
<tr>
	<th class="table-header-repeat line-left minwidth-1"><a href="">Cedula</a></th>
	<th class="table-header-repeat line-left minwidth-1"><a href="">Nombre</a></th>
	<th class="table-header-repeat line-left"><a href="">Telefono</a></th>
</tr>


<?php if($clientes != null) foreach ($clientes as $cliente) : ?>
<tr>
	<?php echo "<tr>"; ?>
	<td><?php echo $cliente->Cedula ?></td>
	<td><?php echo $cliente->nombre ?></td>
	<td><?php echo $cliente->telefono ?></td>
</tr>
<?php endforeach; ?>
</table>

Y eso es todo. Cada vez que el usuario de click al botón buscar, se ejecutará una petición POST con la palabra clave que introdujo el usuario, con el resultado de la búsqueda se construirá una tabla en la vista p_clientes.phtml, que será incrustada dentro del div "tablecontainer" de nuestra vista index.phtml.

No incluí el modelo, porque no lo considero relevante para lo que se quiere mostrar aquí.

Préstese especial atención al script que se encarga de sustituir la data. Es una simple función que se ejecuta cada vez que el usuario presiona el boton de enviar. Obsérvese además que esa función retorna false, pues no queremos que el post sea enviado tradicionalmente. Por supuesto, para mayor detalle, acudir a la documentación oficial de jQuery.


No hay comentarios: