Ejemplo 2 de Ajax con Prototype: implementando las acciones con AJAX (I)

Introducción.

Para terminar este mini-tutorial se deben implementar las acciones que corresponden con los requerimientos pendientes de los capítulos anteriores.

La implementación de estas acciones se va a realizar del lado del servidor utilizando AJAX mediante Prototype y PHP y la infraestraestructura recién creada del lado del servidor.  Respecto a AJAX se van a implementar las tres modalidades que permite Prototype.

  1. Ajax.Request.  Realiza la solicitud asíncrona y recibe la respuesta del servidor permitendo manipularla y procesarla según se requiera.  Es posible determinar el éxito o fracaso de la comunicación con el servidor.
  2. Ajax.Updater.  Es un subcaso del método anterior.  Realiza el llamado asíncrono y actualiza automáticamente el contenido de un componente XHTML con la respuesta obtenida del servidor.
  3. Ajax.Request con JSON.  Realiza la solicitud asíncrona y recibe la respuesta del servidor en formato JSON facilitando su manipulación.

Si se reucerda las acciones que quedaron pendientes de implementación fueron las siguientes.

  • Agregar un registro.
  • Editar un registro.
  • Eliminar un registro.
  • Actualizar el listado de contactos.
  • Cargar un contacto específico.

La primera de las acciones que se va a implementar es la de agregar registros ya que le permitirá al usuario empezar a poblar la base de datos.  La implementación de cada acción incluirá modificaciones a los archivos del lado del cliente (JavaScript) y del lado del servidor (PHP).

Agregando registros.

En el lado del cliente.

Se debe actualizar el manejo del evento que sucede ante la solicitud del usuario de agregar un nuevo registro de un Contacto, para esto editamos el archivo jsfunciones.js y modificamos el contenido de la función enAgregarRegistro.

La función debe realizar las siguientes actividades.

  • Realizar las validaciones necesarias para garantizar que los datos se encuentran dispuestos para ejecutarse la acción solicitada.
    • Verificar que todos los campos tengan contenido, es decir, el contenido de ninguno de los campos puede ser vacío.
    var camposVacios = new Array();

    $('formulario').select('.CampoEstilo').each(function (elemento)
    {
        if(elemento.value.strip().length == 0)
        {
            camposVacios.push(elemento.title);
        }
    });

    if(camposVacios.length > 0)
    {
        alert('Los siguientes campos se encuentran vacíos,n' +
              'por favor complemente su información: nn' +
              camposVacios.toString());

        return false;
    }
  • Realizar el llamado asíncrono a la acción agregar.php para adicionar a la base de datos la información contenida en el formulario.
    • En caso de ser exitosa la ejecución de la acción se deberá mostrar en color verde (.MensajeBien) la respuesta obtenida del servidor y actualizar el listado de los clientes registrados donde se deberá reflejar la adición del nuevo registro.
    • En caso de ser fallida la ejecución, se deberá mostrar en color rojo (.MensajeMal).
    new Ajax.Request('agregar.php',
    {
        method:     'post',

        parameters: $('formulario').serialize(true),

        onSuccess: function(transport)
        {
            ponMensajeBien('<b>' + transport.responseText + '</b>');

            enActualizarBusqueda(null);
        },

        onFailure: function(transport)
        {
            ponMensajeMal('<b>' + transport.responseText + '</b>');
        }
    });

    return true;

En el lado del servidor.

Se define la implementación en el archivo agregar.php en el directorio raíz de la aplicación web.

Las actividades realizadas por esta acción se relacionan a continuación.

  • Establecer la conexión con la base de datos.
include('config.php');
include_once('basededatos.php');
include_once('contacto.php');

$bd = new BaseDeDatos(BaseDeDatos::crearDSN($bdInfo));
  • Obtener la información enviada por el cliente.  Esta información viene a través del método POST y los nombres de las variables suministradas corresponden con los nombres de los campos del formulario.
$tNombres     = filter_var($_POST['tNombres'],     FILTER_SANITIZE_STRING);
$tApellidos   = filter_var($_POST['tApellidos'],   FILTER_SANITIZE_STRING);
$tCorreo      = filter_var($_POST['tCorreo'],      FILTER_SANITIZE_EMAIL);
$tFNacimiento = filter_var($_POST['tFNacimiento'], FILTER_SANITIZE_STRING);
  • A partir de la información recién obtenida se crea una instancia del objecto Contacto y almacena su información utilizando su método agregar.
$contacto = new Contacto();

$contacto -> ponNombres($tNombres);
$contacto -> ponApellidos($tApellidos);
$contacto -> ponCorreo($tCorreo);
$contacto -> ponFechaDeNacimiento($tFNacimiento);

$control = $contacto -> agregar($bd);

$bd -> desconectar();
  • Según el resultado de la operación (valor de $control) se define si la ejecución fue exitosa o fallida y se envía al cliente el mensaje y código HTTP apropiado.
if($control > 0)
{
    echo utf8_encode("Registro agregado");

    header("Status: 200 OK", false, 200);
}
else
{
    echo utf8_encode("El registro no pudo ser agregado");

    header("Status: 400 Bad request", false, 400);
}

Listando contactos registrados.

Esta acción permitirá que se verifique si efectivamente la adición de registros anterior se encuentra funcionando correctamente o no al desplegar en la interfaz (6) el listado de contactos existente en la base de datos de acuerdo con el filtro de búsqueda seleccionado.

En el lado del cliente.

La misión de esta acción es la de actualizar al div Resultados con la información de la base de datos de acuerdo con los criterios contenidos en los campos sLetra y sCampo.  Se utiliza el Ajax.Updater para este fin.

    new Ajax.Updater('Resultados',
             'listar.php',
             {
                parameters: $('sLetra').serialize(true) + "&" + $('sCampo').serialize(true),

                method: 'post'
             });

En el lado del servidor.

Se realiza la implementación del archivo listar.php en el cual desarrollan las siguientes actividades.

  • Establecer la conexión con la base de datos.
include('config.php');
include_once('basededatos.php');
include_once('contacto.php');

$bd = new BaseDeDatos(BaseDeDatos::crearDSN($bdInfo));
  • Obtener el valor del campo sCampo y verificar que sea válido, es decir, sea nom o ape.
$campos = array('nom' => 'nombres',
                'ape' => 'apellidos');

$sCampo = filter_var($_POST['sCampo'], FILTER_SANITIZE_STRING);

if(!isset($campos[$sCampo]))
{
    echo utf8_encode("<span class='MensajeMal'>Los parámetros de búsqueda especificados son inválidos.</span>");

    header("Status: 400 Bad request", false, 400);

    exit;
}
  • Obtener el valor del campo sLetra.
$campo = $campos[$sCampo];

$sLetra = filter_var($_POST['sLetra'], FILTER_SANITIZE_STRING);
  • Crear la condición de filtro de búsqueda y obtener el listado de los Contactos que cumplen con dicho criterio.
$letra1 = (($sLetra == 'todos' ) ? "" : strtoupper($sLetra[0])) . "%";
$letra2 = (($sLetra == 'todos' ) ? "" : strtolower($sLetra[0])) . "%";

$where = $campo . " LIKE '{$letra1}' OR " . $campo . " LIKE '{$letra2}'";

$listado = Contacto::listar($bd, $where);
  • Generar la presentación del listado (XHTML) para ser enviado hacia el cliente para que sea ubicado en el contenedor apropiado de la página web.
echo "<table><tbody>";

echo "<tr><td class='RegistroTitulo'>Apellidos</td>" .
     "<td class='RegistroTitulo'>Nombres</td>" .
     "<td class='RegistroTitulo'>Correo</td>" .
     "<td class='RegistroTitulo'>FNacimiento</td></tr>";

foreach($listado as $registro)
{
    $id          = $registro['id'];
    $nombres     = urldecode($registro['nombres']);
    $apellidos   = urldecode($registro['apellidos']);
    $correo      = urldecode($registro['correo']);
    $fnacimiento = urldecode($registro['fnacimiento']);

    $e1 = "<a href='#' onClick='enCargarRegistro({$id}); return false;'>";
    $e2 = "</a>";

    echo "<tr><td class='RegistroListado'>{$e1}{$apellidos}{$e2}</td>" .
         "<td class='RegistroListado'>{$e1}{$nombres}{$e2}</td>" .
         "<td class='RegistroListado'>{$e1}{$correo}{$e2}</td>" .
         "<td class='RegistroListado'>{$e1}{$fnacimiento}{$e2}</td></tr>";
}

echo "</tbody></table>";

$bd -> desconectar();

Cargando registros.

El usuario puede seleccionar a uno de los Contactos registrados haciendo clic sobre sus datos en el componente (6), esta acción invoca a la función enCargarRegistro que conociendo el ID del Contacto debe obtener toda su información para ser desplegada en el formulario apropiado.

Esta acción requiere poder manipular de manera discreta e individual a la información retornada por el servidor ya que cada valor corresponderá con un campo diferente del Contacto seleccionado, lo cual es diferente a por ejemplo la acción anterior, la obtención del listado de Contactos, en la cual todo lo obtenido del servidor (XHTML) es transferido directamente y sin procesamiento a un div específico; por este motivo se involucrará el uso de JSON en la respuesta del llamado asíncrono.

En el lado del cliente.

  • La función enCargarRegistro recibe el ID del Contacto a obtener el cual se convierte en parámetro para la acción recuperar.php.
    new Ajax.Request('recuperar.php',
    {
        parameters: 'id=' + id,

        method: 'post',
  • Se especifica que el resultado de esta acción deberá ser del tipo Application/JSON.
        requestHeaders:
        {
            Accept: 'application/json'
        },
  • En caso de fracasar el llamado asíncrono se mostrará un mensaje indicándolo.
        onFailure: function(transport)
        {
            ponMensajeMal('<b>No fue posible recuperar el registro ' + id + '</b>: ' + transport.responseText);
        }
  • En caso de tener éxito el llamado asíncrono se ejecutarán las siguientes actividades.
  • Se evalúa la respuesta del servidor como un objeto JSON convirtiéndo la respuesta en un objeto JavaScript.
            var json = transport.responseText.evalJSON(true);
  • Se llenan los camps del formulario con la información recibida del servidor.
            $('tId').value          = json.id;
            $('tNombres').value     = json.nombres;
            $('tApellidos').value   = json.apellidos;
            $('tCorreo').value      = json.correo;
            $('tFNacimiento').value = json.fechaNacimiento;
  • Se modifica la acción del formulario a Editar ya que se cuenta con un registro seleccionado.
            $('bAccion').value = 'Editar';
  • Se muestra un mensaje de éxito.
            ponMensajeBien('<b>Registro recuperado: ' + json.id + '</b>');

En el lado del servidor.

La lógica de la acción se implementa en el archivo recuperar.php ubicado en la raíz de la aplicación web y en ella se desarrollan las siguientes actividades.

  • Establecer la conexión con la base de datos.
include('config.php');
include_once('basededatos.php');
include_once('contacto.php');

$bd = new BaseDeDatos(BaseDeDatos::crearDSN($bdInfo));
  • Obtener el identificador del Contacto enviado desde el cliente.
$tId = filter_var($_POST['id'], FILTER_SANITIZE_STRING);
  • Crear una instancia de la clase Contacto y a través de ella recuperar la información del contacto especificado por el usuario.
$contacto = new Contacto();

$control = $contacto -> recuperar($bd, $tId);

$bd -> desconectar();
  • A partir de la respuesta obtenida ($control) determinar si la acción fue realizada exitosa o fallidamente y realizar los procedimientos apropiados para informárselo al cliente.
  • En caso de éxito:
    • Enviar al cliente el objeto resultante en formato JSON.
    • Informar al cliente que el tipo de contenido enviado es Application/JSON.
    • Enviar el código HTTP de éxito.
if($control === true)
{
    echo "/*-secure-n";

    echo json_encode($contacto -> toArray());

    echo "n*/";

    header('Content-type: application/json');

    header("Status: 200 OK", false, 200);
}
  • En caso de fracaso:
    • Enviar al usuario el motivo del error con un mensaje informativo.
    • Enviar el código HTTP de fracaso.
else
{
    echo utf8_encode("El registro no pudo ser agregado");

    header("Status: 400 Bad request", false, 400);
}

10 thoughts on “Ejemplo 2 de Ajax con Prototype: implementando las acciones con AJAX (I)”

  1. perfecto, sabes la verdad solo me faltaba saber la funcion json_encode :S por q siempre hacia muchas cosas tontas, pero ahora me sale perfecto 😀 gracias

  2. Hola amigo.. muchas gracias por tu aportacion, me sacaste de un gran poblema que tenia con ajax jejeje y aparte aprendi como implementar json!!! gracias nuevamente.

  3. Hola Jorge, antes que todo Gracias por tu apreciable artículo, yo lo trate de implementar pero no puedo ejecutar la función de enCargarRegistro, al momento de crear la variable var json = transport.responseText.evalJSON(true); no devuelve ni medio mensage, menos los registros.
    Me podrias ayudar porfavor 🙁 ME URGE

  4. Hola Jorge, ¿cómo estamos?, espero que bien, te cuento que pude corregir el error que tenía gracias a tu sugerencia a otro usuario de usar firebug, así pude ver el error y corregir.
    Por otro lado implentare este demo tuyo en Mysql, si tengo algún problema te molesto :D. Gracias por tu atención Master.

  5. Jorge te molesto, disculpame la ignorancia 🙁 pero como modifico los archivos config.php y basededatos.php para que pueda acceder a mi Base de datos llamada “liga” dentro de mysql en mi apache ????
    Ya trate agregando la conexión a mi servidor $cn = mysql_connect(‘localhost’,’root’,’root’), pero no funciona, además como recibo en la función crearDSN ya que retorna
    return ‘sqlite:’ . $informacion[‘ruta’];
    Me puedes ayudar porfa 🙁 porfa porfa porfa

  6. Hola Jorge te comento que hice los cambios, según yo pertinentes :(, en el codigo de los archivos config.php y basededatos.php para poder ejecutarlo en la base de datos de mysql donde cree la base de contactos.
    en config. php quedo
    $bdInfo = array (‘class’ => ‘CDbConnection’,’connectionString’ => ‘mysql:host=localhost;dbname=liga’,’username’ => ‘root’,’password’ => ‘root’);
    en basededatos.php quedo
    return ‘mysql:’ . $informacion[‘bdInfo’];

    No me manda error pero tampoco me ejecuta las consultas 🙁 me puedes decir en que estoy mal :S Gracias

  7. Saludos Erika, en rigor tendrías que realizar los siguientes cambios.

    En config.php:

    $bdInfo = array(
    	'host' => 'www.servidor.com',
    	'name' => 'MiBaseDeDatos',
    	'user' => 'MiUsuario',
    	'pass' => 'MiContraseña'
    );

    En basededatos.php modifica las siguientes secciones:

    (1)

    public static function crearDSN($informacion)
    {
    	return array(
    		"mysql:host={$informacion['host']};dbname={$informacion['name']}",
    		$informacion['user'],
    		$informacion['pass']
    	);
    }

    (2)

    public function conectar($dsn)
    {
    	$this -> enlace = new PDO($dsn[0], $dsn[1], $dsn[2]);
    
    	return $this -> enlace;
    }

    En este momento no tengo la posibilidad de probar estas modificaciones así que te agradecería que nos contaras como te va con ellas.

    Saludos.

Leave a Reply

Your email address will not be published. Required fields are marked *