Ejecutar después de un efecto con Scriptaculous

Algunas veces es necesario ejecutar cierta acción exactamente después de que se ejecute un efecto sobre la interfaz de usuario, por ejemplo, resaltar la fila que se va a remover y solamente después de terminado el efecto, se remueve efectivamente la fila.

Con Scriptaculous se debe utilizar el callback afterFinish ya que de lo contrario las instrucciones se ejecutarán de manera serial interfiriéndose mutuamente provocando que la fila sea removida casi de inmediato y el efecto no pueda ser apreciado.

A continuación se muestra un pequeño fragmento de código que ejemplifica la implementación descrita anteriormente.

var op = $('fila_a_remover');

op.puff({
    afterFinish: function()
    {
        op.remove();
    }
});

Enlace: Effect.Puff API.

Autocompletador con Prototype/Scriptaculous – Parte II

Como complemento a la primera parte, en este artículo se ampliará el concepto del Autocompleter de Prototype/Scriptaculous a su versión mas flexible que hace uso del envío de mensajes asíncronos mejor conocidos como AJAX.

Para su implementación se requieren de dos partes las cuales se analizarán en el orden expuesto a continuación.

  • Un formulario HTML con el campo que incluye la autocompletación.
  • Una aplicación PHP que recibe y procesa la solicitud de información y genera los resultados de manera dinámica.

El formulario es igual al anterior, incluye el text donde el usuario escribirá el criterio que se autocompletará cuyo identificador es t_criterio y un espacio, cuyo identificador es resultado, donde se desplegarán las posibles sugerencias arrojadas por la aplicación PHP basada en el criterio antes especificado.

<div id='contenedor'>
    <div id='criterio'>
        Criterio
        <input type='text' id='t_criterio' size='50' maxlength='200' />
    </div>
    <div id='resultado'>
        No hay resultados que mostrar.
    </div>
</div>
Ejemplo de Ajax.Autocompleter
Ejemplo de Ajax.Autocompleter

Para activar el autocompletado del campo t_criterio se ejecuta el método estático Ajax.Autocompleter tan pronto como el árbol DOM de la página ha sido cargado de la siguiente manera.

new Ajax.Autocompleter('t_criterio',
                       'resultado',
                       'fuente.php',
                       {
                           paramName: 'criterio',
                           method: 'post',
                           parameters: 'estatico1=valor1&estatico2=valor2',
                           callback: function(editor, paramText) {
                               return paramText + '&time=' + new Date().getTime();
                           },
                           select: 'm_nombre',
                           afterUpdateElement: function (inputField, suggestion) {
                               inputField.value = suggestion.down('span.m_nombre').innerHTML + " / " + suggestion.down('span.m_departamento').innerHTML;
                           }
                       });

Los parámetros que recibe el método se describen a continuación, de los cuales sólo los tres primeros son obligatorios.

  • Id del text con el criterio de búsqueda para la autocompletación.
  • Id del área donde se van a mostrar las opciones sugeridas.
  • URL donde se ubica a la aplicación dinámica que va a procesar la búsqueda de sugerencias a través de AJAX.
  • Hash con opciones adicionales.
    • paramName: nombre del parámetro que se enviará a la aplicación dinámica con el contenido del texto especificado por el usuario.  Si no se especifica este parámetro, se utilizará el atributo name del campo de texto del formulario.
    • method: método a través del cual se enviará la información a la aplicación web: post o get.
    • parameters: parámetros estáticos para ser enviados adicionalmente.
    • callback: función ejecutada antes de ser invocada la aplicación PHP y que permite manipular de manera dinámica los parámetros enviados.
    • select: campo de la sugerencia elegida que es mostrado en el campo de texto cuando la sugerencia es seleccionada.  El valor de este campo se relaciona con el selector CSS donde se encuentra ubicada la información.
    • afterUpdateElement: función invocada justo después de que el usuario ha seleccionado a una de las opciones presentadas.  Permite componer de manera dinámica un valor para ser mostrado como la selección del usuario.  Es mas elaborado y sobreescribe lo especificado en el parámetro select.

Adicionalmente las opciones adicionales minChars y frequency se encuentran también disponibles y operan de igual manera que en el autocompletador local.

La aplicación dinámica (fuente.php) por su parte, desarrollada en PHP para este ejemplo, realiza las siguientes acciones.

Obtiene el valor del criterio de búsqueda especificado por el usuario.  La forma de recuperarlo depende del método (method) utilizado por el formulario.

$criterio = $_POST['criterio'];

Se realiza una consulta a la base de datos y/o un procesamiento de la información lo que constituye el carácter dinámico de la aplicación.  Para este ejemplo, se consulta la base de datos (SQLite utilizando PDO) de la división geopolítica de Colombia y se buscan los municipios cuyos nombres contengan a la subcadena especificada.

$link = new PDO('sqlite:data/database.sqlite');

$sql = "SELECT m.nombre AS nombre, d.nombre AS departamento,
               m.latitud AS latitud, m.longitud AS longitud
        FROM municipios m, departamentos d
        WHERE m.id_departamento = d.id_departamento AND
              m.nombre LIKE '%{$criterio}%'";

$result = $link -> query($sql);

El resultado enviado al formulario está constituído por la salida estándar (echo/print/etc.) de la aplicación PHP.  Su estructura es la de una lista no ordenada: <ul><li>…</li>…</ul>.

Para finalizar, se construye la lista no ordenada con la información obtenida de la base de datos.

$str = "<ul>n";

foreach ($result as $row)
{
    $str .= "<li>n";
    $str .= "<div class='titulo'>Título: <span class='m_nombre'>" . utf8_decode($row['nombre']) . "</span></div>";
    $str .= "<div class='titulo'>Departamento: <span class='m_departamento'>" . utf8_decode($row['departamento']) . "</span></div>";
    $str .= "<div class='titulo'>Latitud: <span class='m_latitud'>" . utf8_decode($row['latitud']) . "</span></div>";
    $str .= "<div class='titulo'>Longitud: <span class='m_longitud'>" . utf8_decode($row['longitud']) . "</span></div>";
    $str .= "</li>n";
}

$str .= "</ul>n";

echo utf8_encode($str);

La información almacenada e impresa en la variable $str es la que será mostrada en el área de sugerencias: #resultado.

Enlaces:

Autocompletador con Prototype/Scriptaculous – Parte I

Prototype, al igual que otros frameworks de JavaScript, permite implementar fácilmente comportamientos que que serían dispendiosos de crear a partir del JavaScript básico y convencional.  El hermanito Scriptaculous viene a ayudarnos aún mas con sus efectos y ayudantes.

Un ejemplo de estas posibilidades de rápida implementación es la simulación del autocompletar de un campo de texto.

El objeto Autocompleter acepta dos fuentes de datos diferentes.

  1. Una local como un arreglo de JavaScript.
  2. Una remota y mas dinámica a través de solicitudes AJAX.

En este artículo se va a realizar la demostración del uso de un Autocompleter.local.  Para esto se requieren dos componentes.

  • Un campo de texto donde el usuario escribe el criterio de búsqueda.
  • Una sección de sugerencias donde el Autocompleter despliega las coincidencias basadas en el criterio de búsqueda.
Ejemplo de Autocompleter.local
Ejemplo de Autocompleter.local

Para el ejemplo anterior cuenta con los siguientes elementos.

  • t_criterio: campo de texto para el criterio de búsqueda.
  • resultado: es el div donde se  desplegarán las sugerencias encontradas.
  • departamentos: es un arreglo JavaScript con la información local y estática para las opciones de búsqueda, en este caso el listado de los departamentos de Colombia.

Para activar el autocompletado sobre t_criterio basado en los valores de departamentos, se ejecuta la siguiente instrucción JavaScript.

var ac = new Autocompleter.Local('t_criterio',
                 'resultado',
                 departamentos,
                 {
                     autoSelect     : false,
                     frequency      : 0.4,
                     minChars       : 1,
                     choices        : 10,
                     paritialSearch : false,
                     paritialChars  : 2,
                     fullSearch     : true,
                     ignoreCase     : true
                 });

Los parámetros especificados al método Local son descritos a continuación.

  1. Id del campo de texto con el criterio de búsqueda.
  2. Id del contenedor de los resultados obtenidos.
  3. Arreglo con la información disponible.
  4. Hash con las opciones de configuración del autocompletador.  Todos estos valores son opcionales y los mostrados corresponden con los valores por defecto.

A continuación se describen las opciones de configuración disponibles.

  • autoSelect: Acepta automáticamente la primera sugerencia cuando sólo hay una.
  • frecuency: Tiempo en segundos entre dos intentos de autocompletar.
  • minChars: Cantidad mínima de carácteres necesarios para que se active el autocompletar.
  • choices: Cantidad máxima de opciones sugeridas a mostrarse.
  • paritialSearch: Tomar en cuenta para la búsqueda el comienzo de cada palabra o sólo el comienzo del texto.
  • paritialChars: Cantidad mínima de carácteres necesarios para que se active la búsqueda parcial.
  • fullSearch: Tomar en cuenta cualquier subcadena de las opciones o sólo los comienzos (palabra o línea).
  • ignoreCase: Tomar o no en cuenta la diferencia entre mayúsculas/minúsculas.

Enlaces:

Editor de operaciones con Prototype

Uno de los proyectos que estoy desarrollando para la Fundación consiste en parte en la definición de fórmulas que están formadas a su vez por una o mas operaciones.

Lo primero que se me vino a la mente fue representarlas con un documento XML que simulara al árbol de precedencia de expresiones de la operción con etiquetas anidadas.  El primer problema que apareció cuando lo discutimos es como hacer el usuario final, no ingeniero de sistemas, pudiera posteriormente y con éxito, implementar sus propias fórmulas.  El XML era una buena solución para la persistencia pero no para la interacción con el humano.

Pensando un poco y revisando los muy pocos antecedentes que encontré en el mercado, realicé un diseño para el editor de fórmulas donde cada fila sería una operación que tendría un nombre como identificador y que podría ser utilizado como atributo o parámetro de cualquier otra operación.  Se establecieron las siguientes operaciones.

  1. Operaciones aritméticas (suma, resta, multiplicación y división).
  2. Valor constante.
  3. Valor definido por el usuario.
  4. Sumatoria.
  5. Función externa.

Quería que la interfaz del editor fuera lo mas dinámica posible y elegí para su implementación el uso de Prototype y Scriptaculous.

La primera versión la implementé a principio de este año y era en realidad, mi primera aproximación a estas librerías de JavaScript por lo que su código no explota todas las ventajas de estas librerías.

Versión 0.1.
Versión 0.1.

Como prototipo fue muy interesante y entretenido de desarrollar.  Los colores por supuesto eran para diferenciar rapidamente los diferentes divs de cada operación.

Durante este mes estuve implementando una nueva versión del editor basado en las conclusiones que obtuvimos al mostrarle al cliente nuestro prototipo.  Algunas funcionalidades del prototipo no fueron incluídas en la siguiente versión (al menos en esta iteración) al no aportar grandes beneficios al resultado final.

  • La mayoría de efectos gráficos (muy interesantes).
  • La posibilidad de reordenar a una operación hacia cualquier fila según el índice especificado.
  • El reordenamiento de parámetros de una función.
  • La especificación del tipo de una operación a medida que se determinan sus elementos.

Esta nueva versión incluye varios cambios a nivel conceptual pero en mayor medida incluye muchas mejoras a nivel de código, lo que la hace ahora compatible con IE7.  En especial gracias a las facilidades que traen consigo estas librerías para trabajar manipulando los elementos DOM sobre clases CSS en lugar de los IDs específicos de los elementos.

Versión 0.2.
Versión 0.2.

Esta nueva versión incluye algunas características como las siguientes.

  • Interfaz de usuario mas limpia y clara.
  • Colores para identificar facilmente el tipo de operación.
  • Fácil reordenamiento de operaciones con sólo arrastrar y soltar las mismas.
  • Agregar operaciones (de un tipo definido) y remover las operaciones seleccionadas.
  • Actualización automática de las opciones de atributos y parámetros tan pronto como se desea su modificación y algún nombre de operación se ha modificado o introducido nuevo.
  • Las funciones pueden tener cero o mas parámetros los cuales pueden ser especificados dinámicamente.

El proyecto que estoy desarrollando es muy interesante y aún falta mucho de su implementación, inclusive en mi imaginación tengo muchas ideas para mejorar a este editor: validadores de datos (que tienen un problema interesante de resolver), asistentes WYSIWYG para los diferentes tipos de valores de datos, buscador de funciones (definidas del lado del servidor), ayuda en línea para las funciones, etc.  Desafortunadamente el editor es sólo una pequeña parte de un cuarto del proyecto por lo que tendré que postergar a estas mejoras para lo que espero sea una próxima iteración.

JavaScript, como todo lo que aprendo y disfruto en la vida, entre mas aprendo, mas me doy cuenta que nada se, sin embargo también he notado que estos frameworks de JavaScript facilitan enormemente el trabajo encapsulando la mayor parte sucia, en particular, facilitandome el trabajo con la independencia de navegadores.

Hasta ahora he probado a MooTools y a Prototype/Scriptaculous con amplio éxito.  Hay muchos otros por experimentar: JQuery, ExtJS, Dojo, YUI, etc.  Como siempre, las ganas sobran, el tiempo es el que falta 😉