Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Web Development

Haciendo uso de jQuery UI Widget Factory

by
Difficulty:IntermediateLength:LongLanguages:

Spanish (Español) translation by CYC (you can also view the original English article)

Durante mucho tiempo, la única forma de escribir controles personalizados en jQuery era extender el espacio de nombres $.fn. Esto funciona bien para widgets simples, sin embargo, a medida que comienzas a construir widgets con más estado, rápidamente se vuelve engorroso. Para ayudar en el proceso de creación de widgets, el equipo de jQuery UI presentó Widget Factory, que elimina la mayor parte del estándar que normalmente se asocia con la administración de un widget.

La fábrica de widgets, parte de jQuery UI Core, proporciona una forma orientada a objetos para administrar el ciclo de vida de un widget. Estas actividades del ciclo de vida incluyen:

  • Crear y destruir un widget
  • Cambiar las opciones del widget
  • Hacer llamadas "super" en widgets subclase
  • Notificaciones de eventos

Exploremos esta API, a medida que construimos un widget gráfico simple llamado 'bullet'.


El widget gráfico llamado Bullet

Antes de construir este widget, comprendamos algunos de los componentes básicos del widget. El Bullet Chart es un concepto introducido por Stephen Few como una variación en el gráfico de barras.

Bullet ChartBullet ChartBullet Chart

El gráfico consiste en un conjunto de barras y marcadores superpuestos entre sí para indicar el rendimiento relativo. Hay una escala cuantitativa para mostrar el rango real de valores. Al apilar las barras y marcadores de esta manera, se puede transmitir más información sin comprometer la legibilidad. La leyenda dice el tipo de información que estamos tramando.

El HTML de esta tabla se ve así:

Nuestro widget, que llamaremos jquery.bulletchart, generará dinámicamente este HTML a partir de los datos proporcionados. El widget final se puede ver en la página de demostración, que puedes descargar desde GitHub. La llamada para crear el widget debería verse así:

Todos los valores están en porcentajes. La opción size se puede usar cuando desees tener varios gráficos bullet's colocados uno al lado del otro con tamaño relativo. La opción ticks se usa para poner las etiquetas en la escala. Los marcadores y las barras se especifican como una matriz de literales de objetos con propiedades title, value y css.


Construyendo el Widget

Ahora que conocemos la estructura del widget, vayamos a construirlo. Un widget se crea llamando a $.widget() con el nombre del widget y un objeto que contiene sus métodos de instancia. La API exacta se ve así:

jQuery.widget(name[, base], prototype)

Por ahora, trabajaremos solo con los argumentos de nombre y prototipo. Para el bulletchart, nuestro apéndice de widget básico tiene el siguiente aspecto:

Se recomienda que siempre nombres el namespace de tu widget. En este caso, estamos usando 'nt.bulletchart'. Todos los widgets de jQuery UI están bajo el espacio de nombres 'ui'. Aunque estamos asignando espacios al widget, la llamada para crear un widget en un elemento no incluye el espacio de nombre. Por lo tanto, para crear un gráfico de viñetas o un 'bulletchart', simplemente llamaríamos a $('#elem').bulletchart().

Las propiedades de la instancia se especifican siguiendo el nombre del widget. Por convención, todos los métodos privados del widget deben tener el prefijo '_'. Hay algunas propiedades especiales que espera la fábrica de widgets. Esto incluye, options_create_destroy y _setOption.

  • options: estas son las opciones predeterminadas para el widget
  • _create: la fábrica de widgets llama a este método la primera vez que se crea una instancia del widget. Esto se usa para crear el DOM inicial y adjuntar cualquier manejador de eventos.
  • _init: después de la llamada a _create, la fábrica llama a _init. Esto generalmente se usa para restablecer el widget al estado inicial. Una vez que se crea un widget, llamar al constructor del widget simple, por ejemplo: $.bulletchart(), también restablecerá el widget. Esto internamente llama _init.
  • _setOption: se llama cuando establece una opción en el widget, con una llamada como: $('#elem').bulletchart('option', 'size', 100). Más adelante veremos otras formas de configurar opciones en el widget.

Creando el DOM inicial con _create

Nuestro widget de viñetas cobra vida en el método _create. Aquí es donde construimos la estructura básica para el cuadro. La función _create se puede ver a continuación. Notarás que aquí no sucede mucho además de crear el contenedor de nivel superior. El trabajo real de crear el DOM para barras, marcadores y ticks ocurre en el método _setOption. Esto puede parecer contradictorio para empezar, pero hay una razón válida para eso.

Ten en cuenta que las barras, los marcadores y las marcas también se pueden cambiar configurando opciones en el widget. Si mantuviéramos el código para su construcción dentro de _create, nos estaríamos repitiendo dentro de _setOption. Al mover el código a _setOption e invocarlo desde _create se elimina la duplicación y también se centraliza la construcción.

Además, el código anterior muestra otra forma de configurar opciones en el widget. Con el método _setOptions (ten en cuenta el plural), puedes establecer varias opciones de una sola vez. Internamente, la fábrica realizará llamadas individuales a _setOption para cada una de las opciones.

El método _setOption

Para el gráfico de viñetas, el método _setOption es el caballo de batalla. Maneja la creación de los marcadores, barras y ticks y también cualquier cambio realizado a estas propiedades. Funciona borrando todos los elementos existentes y recreándolos en función del nuevo valor.

El método _setOption recibe tanto la clave de opción como un valor como argumentos. La clave es el nombre de la opción, que debe corresponder a una de las claves en las opciones predeterminadas. Por ejemplo, para cambiar las barras en el widget, harías la siguiente llamada:

El método _setOption para la viñeta parece así:

Aquí, creamos un hash simple de option-name  para la función correspondiente. Usando este hash, solo trabajamos en opciones válidas e ignoramos silenciosamente las inválidas. Hay dos cosas más que suceden aquí: una llamada a _super() y disparando la opción evento cambiado. Los veremos más adelante en este artículo.

Para cada una de las opciones que cambia el DOM, llamamos a un método de ayuda específico. Los métodos auxiliares, createBars, createMarkers y createTickBar se especifican fuera de las propiedades de la instancia del widget. Esto se debe a que son los mismos para todos los widgets y no es necesario crearlos individualmente para cada instancia de widget.

Todas las funciones de creación operan en porcentajes. Esto asegura que el diagrama se rediseña bien cuando cambia el tamaño del elemento que lo contiene.

Las opciones predeterminadas

Sin ninguna opción especificada al crear el widget, los valores predeterminados entrarán en juego. Esta es la función de la propiedad de opciones. Para el gráfico de viñetas, nuestras opciones predeterminadas (options) se ven así:

Comenzamos con un tamaño del 100%, sin barras y marcadores y con marcas colocadas cada 10%. Con estos valores predeterminados, nuestro gráfico de viñetas debería verse así:

Default Bullet ChartDefault Bullet ChartDefault Bullet Chart

Hasta ahora, hemos visto cómo crear el widget usando _create y actualizarlo usando _setOption. Hay otro método de ciclo de vida, que se llamará cuando destruyas un widget. Este es el método _destroy. Cuando llamas $('#elem').bulletchart('destroy'), la fábrica de widgets llama internamente _destroy a tu instancia de widgets. El widget es responsable de eliminar todo lo que introdujo en el DOM. Esto puede incluir clases y otros elementos DOM que se agregaron en el método _create. Este también es un buen lugar para desvincular a cualquier controlador de eventos. El _destroy debería ser exactamente lo opuesto al método _create.

Para el widget gráfico de viñetas, _destroy es bastante simple:


Subclases, eventos y más

Nuestro widget de viñetas está casi completo, a excepción de una última característica: la leyenda. La leyenda es bastante esencial, ya que dará más significado a los marcadores y barras. En esta sección, agregaremos una leyenda al lado del gráfico.

En lugar de agregar esta característica directamente al widget de viñetas, crearemos una subclase, bulletchart2, que tendrá soporte para la leyenda. En el proceso, también veremos algunas de las características interesantes de la herencia de Widget Factory.

Agregando una leyenda

Chart with LegendChart with LegendChart with Legend

Widget Factory admite subclases de un widget para crear versiones más especializadas. Anteriormente en el artículo, vimos la API para $.widget(), que tenía tres argumentos:

jQuery.widget(name[, base], prototype)

El segundo parámetro nos permite elegir una clase base para nuestro widget. Nuestro widget bulletchart2, con subclases de bulletchart, tendrá la siguiente firma:

Hay algunas cosas interesantes para notar aquí:

  • Continuamos el namespace del nombre de nuestro widget: nt.bulletchart2.
  • La fábrica de widgets coloca automáticamente el widget bajo el espacio de nombres $.nt. Por lo tanto, para hacer referencia a nuestro widget anterior, usamos $.nt.bulletchart. Del mismo modo, si tuviéramos que subclasificar uno de los widgets jQuery UI estándar, los haríamos referencia con $.ui.widget-name.
  • El widgetEventPrefix es una propiedad nueva que no hemos visto antes. Llegaremos a eso cuando hablemos de eventos. El resto de las propiedades de la instancia deberían ser familiares.

Dado que estamos agregando más elementos DOM con la leyenda, tendremos que anular el método _create. Esto también significa que debemos anular _destroy, para ser simétricos.

Aquí, nuevamente, vemos el mismo patrón que nuestro anterior método _create. Creamos el contenedor para la leyenda y luego llamamos a _setOption para construir el resto de la leyenda. Dado que estamos anulando el _create, debemos asegurarnos de llamar a la base _create. Hacemos esto con la llamada a _super. Del mismo modo, en _destroy, también vemos la llamada a _super.

Ahora te estarás preguntando: ¿cómo sabe el widget a qué supermétodo llamar con una simple invocación de _super no calificada? La inteligencia para eso yace en las entrañas de la fábrica de widgets. Cuando se subclasifica un widget, la fábrica configura la  referencia _super de manera diferente para cada una de las funciones de instancia. Por lo tanto, cuando llamas a _super desde tu método de instancia, siempre apunta al método _super correcto.

Notificaciones de eventos

Como la viñeta admite cambiar marcadores y barras, la leyenda debe estar sincronizada con esos cambios. Además, también le ayudaremos a alternar la visibilidad de marcadores y barras haciendo clic en los elementos de la leyenda. Esto se vuelve útil cuando tienes varios marcadores y barras. Al ocultar algunos de los elementos, puedes ver los otros más claramente.

Para admitir la sincronización de la leyenda con los cambios en marcadores y barras, el widget bulletchart2 debe recibir los cambios que se produzcan en esas propiedades. La viñeta base ya activa un evento de cambio cada vez que cambian sus opciones. Aquí está el fragmento correspondiente del widget base:

Cada vez que se establece una opción, se dispara el evento _setOption. Los datos del evento contienen el valor anterior y el nuevo para la opción que se modificó.

Al recibir este evento en el widget subclasificado, puedes saber cuándo cambian los marcadores o las barras. El widget bulletchart2 se suscribe a este evento en su método _create. La suscripción a eventos de widgets se logra con la llamada a this.element.on(). this.element apunta al elemento jQuery en el que se creó la instancia del widget. Debido a que el evento se activará en el elemento, nuestra suscripción al evento debe ocurrir al respecto.

Ten en cuenta el nombre del evento utilizado para suscribirse: 'bulletchart:setoption'. Como política, la fábrica de widgets adjunta un prefijo de evento para eventos disparados desde el widget. De forma predeterminada, este prefijo es el nombre del widget, pero se puede cambiar fácilmente con la propiedad widgetEventPrefix. El widget base bulletchart lo cambia a 'bulletchart:'.

También necesitamos suscribirnos a eventos "click" en los elementos de la leyenda para ocultar/mostrar el marcador o la barra correspondiente. Hacemos esto con el método _on. Este método toma un resumen de la firma del evento para la función del controlador. El contexto del manejador (this) está configurado correctamente en la instancia del widget. Otra conveniencia con _on es que la fábrica de widgets desvincula automáticamente a los eventos en destroy.


Más consejos

La fábrica de Widget incluye algunos otros detalles que debes tener en cuenta.

Hacer referencia a la instancia del widget

Hasta ahora, solo hemos visto una forma de invocar métodos en el widget. Hicimos esto con $('#elem).bulletchart('method-name'). Sin embargo, esto solo permite llamar a métodos públicos como  'option', 'destroy', 'on' y  'off'. Si deseas invocar esos métodos directamente en la instancia del widget, hay una forma de hacerlo. La fábrica de widgets adjunta la instancia del widget al objeto data() del elemento. Puedes obtener esta instancia así:

Además, si deseas obtener todos los widgets de bulletchart en la página, también hay un selector para eso:

Algunos métodos especiales

Hay algunos métodos especiales que debes tener en cuenta, que se utilizan con menos frecuencia: _getCreateEventData() y _getCreateOptions(). El primero se usa para adjuntar datos de eventos para el evento 'crear' que se dispara después de finalizar la llamada a _create.

_getCreateOptions es para adjuntar opciones predeterminadas adicionales para el widget o anular las existentes. Las opciones proporcionadas por el usuario anulan las opciones devueltas por este método, que a su vez anula las opciones de widget predeterminadas.


Resumen

¡Esa es una introducción! Si deseas explorar más a fondo, las siguientes referencias te servirán bastante bien. Por supuesto, la mejor fuente de información siempre será el código fuente, en sí mismo. Yo recomendaría leer la fuente jquery.ui.widget en GitHub.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.