Ext JS - Learning Center

Tutorial:Introduction to Ext (Spanish)

From Learn About the Ext JavaScript Library

Revision as of 08:04, 13 October 2007 by Boy0 (Talk | contribs)
(diff) ← Older revision | Current revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Summary: Damos un repaso a la librería Ext e introducimos su uso para completar algunas tareas comunes. Los nuevos usuarios deberían empezar por aquí.
Author: Ricardo J. Barrios Díaz
Published: March 07, 2007
Ext Version: 1.1
Languages: en.png English nl.png Dutch es.png Spanish cn.png Chinese ru.png Russian br.png Portuguese fr.png French

kr.png Korean

Cualquiera que comience a usar la librería Ext o intente aprender más sobre ella ha llegado al lugar correcto. Este tutorial te guiará a través de los conceptos básicos de Ext y te enseñará a crear una página dinámica en muy poco tiempo. Se presupone que tienes alguna experiencia en JavaScript y un conocimiento básico del Modelo de Objetos del Documento (DOM) de HTML.

Contents

Descargar Ext

Si no lo has hecho ya, deberás descargar la última versión de Ext, que siempre podrás encontrar aquí: http://extjs.com/download. Hay varias opciones de descarga, pero probablemente prefieras comenzar con la versión de producción estable más actual.

Una vez que hayas descargado el archivo, deberás descomprimirlo, preferentemente dentro de un directorio al que puedas acceder a través de tu servidor web. Luego de este paso, un buen lugar para comenzar a explorar es el directorio examples.

Comencemos

Vamos a recorrer algunas de las tareas más comunes que la gente tiene que llevar a cabo con JavaScript, y a aprender cómo realizarlas usando Ext. Si quieres experimentar a medida que vas leyendo, deberías descargar los archivos de introducción en IntroToExt.zip, que usaremos para construir una página con código Ext en funcionamiento. Este zip contiene tres archivos: ExtStart.html, ExtStart.js y ExtStart.css. Extráelos en una carpeta ubicada directamente bajo la carpeta donde tengas instalado Ext (por ejemplo, si Ext está en C:\code\Ext\v1.0.1, crea una nueva carpeta en v1.0.1 llamada tutorial). Haz doble click en ExtStart.html para que se abra en tu navegador por defecto, y deberías obtener un mensaje diciendo que todo está configurado correctamente. Si te da un error de JavaScript, sigue por favor las instrucciones de esa página para hacerlo funcionar.

Ahora puedes abrir ExtStart.js en tu IDE o editor de texto favorito y echarle un vistazo:

Ext.onReady(function() {
    alert("Congratulations!  You  have Ext configured correctly!");
});

Ext.onReady es probablemente el primer método que usarás en todas las páginas. Este método es llamado automáticamente una vez que el DOM ha sido cargado por completo, garantizando que cualquier elemento de la página al que puedas querer referenciar ya estará disponible cuando se ejecute el script. Puedes ir y borrar la línea de alert() ahora, para que podamos empezar a añadir un poco de código real que haga algo útil.

Element: el corazón de Ext

Prácticamente todo lo que hagas en JavaScript en algún momento requerirá que hagas referencia a elementos específicos de tu página para que puedas hacer cosas interesantes con ellos. Usando JavaScript tradicional, la selección de un nodo DOM por la ID se hace de esta forma:

var myDiv = document.getElementById('myDiv');

Esto funciona bien, pero el objeto que es devuelto (un nodo DOM) no ofrece mucho en el sentido de utilidad o conveniencia. Para hacer cualquier cosa útil con ese nodo, necesitas aún escribir un montón de código por tu cuenta. Además es tu responsabilidad gestionar las diferentes maneras en las que el nodo es tratado de un navegador a otro, lo que puede llegar a ser una pesadilla.

Aquí entra el objeto Ext.Element (muchas veces llamado simplemente Element, para abreviar). Element es realmente el corazón de Ext, ya que la mayor parte de lo que harás involucra obtener acceso a Elements y realizar acciones sobre ellos. La API de Element es fundamental para toda la librería Ext, y si piensas invertir tu tiempo en aprender bien una sola clase de Ext, ¡ésta debería ser Element!

El código correspondiente para obtener un Element de Ext por su ID tiene este aspecto (la página de inicio ExtStart.html contiene un div con el id "myDiv", así que vuelve a ExtStart.js y añade este código):

Ext.onReady(function() {
    var myDiv = Ext.get('myDiv');  // myDiv es ahora (una referencia a) un objeto Ext.Element
});

Así que ahora estamos obteniendo un objeto Element. ¿Y qué tiene esto de interesante?

  • Element envuelve (wraps) la mayoría de los métodos y propiedades de DOM que necesitarás, proporcionando una interfaz DOM conveniente, unificada y multi-navegador (y aun podrás tener acceso directo al nodo DOM cuando lo necesites, a través de Element.dom).
  • El método Ext.get() proporciona cacheo interno, por lo que múltiples llamadas para recuperar el mismo objeto serán increíblemente rápidas.
  • Las acciones más comunes realizadas sobre nodos DOM están integradas en métodos de Element, directos y multi-navegador (añadir/quitar clases CSS, añadir/quitar manejadores de eventos, posicionamiento, tamaño, animación, arrastrar/soltar, etc.).


Esto significa que puedes hacer todo tipo de cosas útiles con un código mínimo. Aquí van solo unos pocos ejemplos sencillos (lee la documentación de la API de Element para la lista completa de todo lo que puedes hacer). Prueba a añadir alguna de las líneas que siguen en ExtStart.js, luego de la línea anterior en la que accedimos al Element myDiv:

myDiv.highlight();       // El fondo del elemento se resaltará en amarillo y luego retomará el color inicial
myDiv.addClass('red');   // Añade una clase CSS (definida en ExtStart.css)
myDiv.center();          // Centra el elemento en el viewport
myDiv.setOpacity(.25);   // Vuelve el elemento parcialmente transparente

(Naturalmente, cada vez que modifiques el código deberás recargar la página en el navegador para ver su efecto.)

Seleccionando nodos DOM

A veces es poco práctico, o es imposible, seleccionar nodos DOM por su ID. Quizás el ID no exista, o no lo conozcas, o haya demasiados elementos para referenciarlos directamente por ID. Algunas veces puedes querer seleccionar nodos basándote en algo que no sea el ID, como un atributo o el nombre de una clase CSS. Por estas razones, Ext viene con una librería de selectores DOM extremadamente poderosa, llamada DomQuery.

DomQuery puede usarse como una librería independiente, pero a menudo en Ext la usarás en el contexto de seleccionar Elements para que luego puedas actuar sobre ellos a través de la interfaz Element. Por suerte, el objeto Element en sí mismo soporta la búsqueda a través del método Element.select, que internamente usa DomQuery para seleccionar los elementos. Como un ejemplo simple de cómo podrías usar esto, el archivo ExtStart.html contiene varias etiquetas de párrafo (<p>), ninguna de las cuales tiene ID. Si quisieras seleccionar fácilmente todos los párrafos y realizar una acción sobre todos ellos a la vez, podrías hacer algo como esto:

// Resalta cada párrafo
Ext.select('p').highlight();

Este ejemplo demuestra un aspecto muy útil de Element.select: devuelve un CompositeElement, que proporciona acceso a todos los Elements subyacentes a través de la interfaz Element. Esto te permite actuar fácilmente sobre todas las instancias de Element devueltas por Element.select, sin tener que usar un bucle y tocar cada una de forma individual.

DomQuery soporta una amplia variedad de opciones de selección, incluyendo la mayoría de los selectores DOM de la especificación CSS3 del W3C, XPath básico, atributos HTML y mucho más. Por favor, lee la API de DomQuery para los detalles completos sobre esta poderosa librería.

Respondiendo a eventos

Hasta ahora en nuestros ejemplos, todo el código que hemos escrito ha estado directamente dentro de la función onReady, lo que significa que siempre se ejecuta inmediatamente tras la carga de la página. Esto no nos da mucho control—normalmente desearás que tu código se ejecute en respuesta a eventos o acciones específicas que elijas gestionar. Para hacerlo, defines manejadores de eventos (event handlers) que pueden responder a los eventos usando las funciones que tú asignes.

Vamos a empezar con un ejemplo sencillo. Abre ExtStart.js y edítalo de forma que tu código quede así:

Ext.onReady(function() {
    Ext.get('myButton').on('click', function(){
        alert("Has hecho click en el botón");
    });
});

El código todavía se ejecuta cuando se carga la página, pero hay una diferencia importante. La función que contiene el alert() es definida, pero en realidad no es ejecutada inmediatamente—es asignada como el "manejador" del evento click del botón. Dicho en español, este código se leería: Obtén una referencia al elemento con el id 'myButton' y asígnale una función para llamarla cada vez que alguien haga click sobre ese elemento.

No es de sorprender que Element.select te permita hacer lo mismo, pero con un grupo entero de Elements a la vez. Por ejemplo, para mostrar nuestro mensaje cuando se haga click sobre cualquier párrafo de nuestra página de pruebas, podemos hacer lo siguiente:

Ext.onReady(function() {
    Ext.select('p').on('click', function() {
        alert("Has hecho click en un párrafo");
    });
});

En estos dos ejemplos, la función que maneja los eventos es declarada en línea (inline), sin darle un nombre de función. El término para este tipo de función es "función anónima", ya que es declarada y nunca se la nombra. También puedes asignar un evento para que sea manejado por una función con nombre, lo que es especialmente útil si quieres reutilizar la función y hacer que maneje múltiples eventos. Por ejemplo, este código es funcionalmente equivalente al del ejemplo anterior:

Ext.onReady(function() {
    var paragraphClicked = function() {
        alert("Has hecho click en un párrafo");
    }
    Ext.select('p').on('click', paragraphClicked);
});

Hasta aquí hemos visto cómo realizar una acción genérica cuando nuestro evento se produce, pero ¿cómo sabemos qué Element en particular ha lanzado el evento, para que podamos realizar alguna acción sobre él? Resulta ser bastante fácil: el método Element.on pasa tres parámetros extremadamente útiles a la función manejadora del evento (sólo vamos a ver el primero aquí, pero deberías explorar la documentación de la API para aprender más detalles acerca del manejo de eventos). En nuestros ejemplos anteriores la función manejadora del evento ignoraba estos parámetros, pero con un simple cambio podemos proporcionar un nivel adicional de funcionalidad. El primer parámetro, y el más importante, es el evento que ha ocurrido. Este es en realidad un Ext.EventObject, que a la vez está normalizado para funcionar en distintos navegadores, y proporciona más información que el evento estándar del navegador. Por ejemplo, el nodo DOM del objetivo (target) del evento puede ser obtenido con este simple añadido:

Ext.onReady(function() {
    var paragraphClicked = function(e) {
        Ext.get(e.target).highlight();
    }
    Ext.select('p').on('click', paragraphClicked);
});

Ten en cuenta que e.target es un nodo DOM, así que primero obtenemos el correspondiente Element, y luego realizamos cualquier acción que queramos con él. En este caso, estamos resaltando visualmente el párrafo.

Usando widgets

Además de la librería core JavaScript que hemos estado viendo, Ext también incluye uno de los conjuntos de widgets para interfaces en JavaScript más ricos que hay en la actualidad. Hay demasiados para cubrirlos todos en esta introducción, pero echemos un vistazo a un par de los widgets más usados, y notemos lo fácil que es trabajar con ellos.

MessageBox

En vez de una ventana aburrida de "Hola mundo", vamos a hacer un pequeño cambio. Tenemos ya el código que escribimos en la sección anterior que resalta cada párrafo cuando haces click en él. Vamos a modificar el código para mostrar también el texto del párrafo cliqueado en una ventana de mensaje. En la función paragraphClicked anterior, reemplaza la línea:

Ext.get(e.target).highlight();

... por este código:

var paragraph = Ext.get(e.target);
paragraph.highlight( );
 
Ext.MessageBox.show({
    title: 'Párrafo cliqueado',
    msg: paragraph.dom.innerHTML,
    width: 400, 
    buttons: Ext.MessageBox.OK,
    animEl: paragraph
});

Hay un par de conceptos nuevos en este ejemplo que vale la pena discutir. En la primera línea, estamos creando una variable local llamada paragraph que contendrá una referencia al Element que representa el nodo DOM en el que se ha hecho click (en este caso sabemos que siempre será un párrafo, ya que nuestro evento click solamente está asociado a las etiquetas <p>). ¿Por qué hacemos esto? Bien, si miramos hacia adelante un momento, vamos a necesitar una referencia al Element para resaltarlo, y también usaremos el mismo Element para algunos parámetros del MessageBox. En general, es una mala práctica hacer la misma llamada a una función varias veces para obtener el mismo valor o referencia a un objeto, así que al asignarlo a una variable local y reusando la variable ¡estaremos obrando como buenos desarrolladores orientados a objetos!

Ahora, pasemos a la llamada a MessageBox, que demuestra el otro nuevo concepto que vamos a discutir. A primera vista, esto puede parecer simplemente una lista de parámetros pasados a un método, pero si miras detenidamente, tiene una sintaxis muy específica. Lo que en realidad se está pasando en este caso a MessageBox.show() es sólo un parámetro: un literal objeto (object literal) que contiene un conjunto de propiedades y valores. En JavaScript, un literal objeto es un objeto dinámico y genérico que sea crea cada vez que usas los caracteres { y } rodeando una lista de propiedades nombres/valor, y el formato para esas propiedades es [nombre de la propiedad] : [valor de la propiedad]. Verás este patrón usado de forma extensa a través de Ext, así que deberías aprenderlo bien.

¿Por qué usar un literal objeto? La principal razón es la flexibilidad. Nuevas propiedades pueden ser añadidas o eliminadas del literal objeto en cualquier momento, o definidas en cualquier orden, mientras que la firma (signature) del método (el número y tipo de parámetros esperados por un método) no tiene que cambiar nunca. También resulta mucho más conveniente desde la perspectiva del desarrollador final al usar métodos con muchos parámetros opcionales (como en el caso de MessageBox.show). Por ejemplo, digamos que un método ficticio foo.action tiene cuatro parámetros opcionales, pero sólo necesitas pasar uno de ellos. En este caso, tu código podría quedar así: foo.action(null, null, null, 'hello'). Sin embargo, si ese método en cambio usara literales objeto, el código sería algo como: foo.action({param4: 'hello'}). Mucho más fácil de usar y mucho más legible.

Grid

El grid (cuadrícula o rejilla) es uno de los widgets más populares en Ext, y usualmente el primero que la gente quiere ver, así que vamos a ver lo fácil que es tener un grid básico funcionando. Reemplaza el código que tengas en ExtStart.js por este otro:

Ext.onReady(function() {
    // los datos a mostrar en el grid
    var myData = [
        ['Apple', 29.89, 0.24, 0.81, '9/1 12:00am'],
        ['Ext', 83.81, 0.28, 0.34, '9/12 12:00am'],
        ['Google', 71.72, 0.02, 0.03, '10/1 12:00am'],
        ['Microsoft', 52.55, 0.01, 0.02, '7/4 12:00am'],
        ['Yahoo!', 29.01, 0.42, 1.47, '5/22 12:00am']
    ];
 
    // el data store, que se ocupa de leer y formatear los datos
    var ds = new Ext.data.Store({
        proxy: new Ext.data.MemoryProxy(myData),
        reader: new Ext.data.ArrayReader({id: 0}, [
            {name: 'company'},
            {name: 'price', type: 'float'},
            {name: 'change', type: 'float'},
            {name: 'pctChange', type: 'float'},
            {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
        ])
    });
    ds.load();
 
    // el column model, para configurar las columnas del grid
    var colModel = new Ext.grid.ColumnModel([
        {header: "Company", width: 120, sortable: true, dataIndex: 'company'},
        {header: "Price", width: 90, sortable:  true, dataIndex: 'price'},
        {header: "Change",  width: 90, sortable: true, dataIndex: 'change'},
        {header: "% Change", width: 90, sortable: true, dataIndex: 'pctChange'}, 
        {header: "Last Updated", width: 120, sortable: true,
            renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
    ]);
 
    // el grid propiamente dicho
    var grid = new Ext. grid.Grid('grid-example', {ds: ds, cm: colModel});
    grid.render();
    grid.getSelectionModel().selectFirstRow();
});

Si bien esto parece mucho, ¡son sólo 7 líneas de código en total! La primera línea de código crea un array de datos para ser mostrados en el grid. En proyectos reales, seguramente estarías cargando estos datos de alguna fuente dinámica como una base de datos o un servicio web. A continuación, creamos y cargamos un almacén de datos (data store), que le dirá a la librería Ext subyacente cómo leer y formatear los datos. Lo siguiente es definir el modelo de columnas (column model) que simplemente nos permite especificar las opciones de configuración para cada columna del grid. Por último, creamos el widget grid, pasándole el almacén de datos y el modelo de columnas, lo renderizamos y seleccionamos la primera fila. ¿Ves que fácil? Si todo salió bien, deberías tener algo que se parece bastante a esto:

Image:IntroToExt_grid.gif

Notarás que puedes seleccionar una o más filas, modificar el ancho de las columnas, reordenar las filas por el valor de una columna, acceder a un menú contextual desde la cabecera de cada columna, ¡y hasta mover las columnas!

Por supuesto, seguramente habrá algunos detalles sobre este código que puede que no entiendas del todo en este momento (como por ejemplo, ¿qué demonios es un MemoryProxy?). El objetivo de este ejemplo es mostrar cómo es posible crear un componente de interfaz extremadamente rico y visualmente complejo con muy pocas líneas de código—aprender los detalles se dejará como ejercicio para el lector. Hay muchos recursos para ayudarte a aprender a usar el grid, incluyendo las demostraciones interactivas y la documentación de la API del grid.

Y mucho más...

Hasta aquí sólo hemos estado viendo la punta del iceberg. Hay literalmente docenas de widgets a escoger en Ext, incluyendo composiciones automáticas de páginas (page layouts), pestañas (tabs), menúes, barras de herramientas, diálogos, una vista en árbol (tree view) y mucho más. Por favor, explora la sección de ejemplos de la documentación de la API para tener una idea de todo lo que hay disponible.

Usando Ajax

Una vez que tienes tu página creada y sabes cómo interactuar con ella mediante JavaScript, probablemente quieras saber cómo enviar y recibir datos de un servidor remoto, normalmente para cargar y guardar datos desde una base de datos en el servidor. Hacer esto de forma asincrónica a través de JavaScript sin recargar la página se conoce comúnmente como Ajax, y Ext viene con un excelente soporte de Ajax. Por ejemplo, un objetivo común es gestionar una interacción del usuario, enviar algo al servidor de forma asincrónica, y luego actualizar un elemento de la interfaz en respuesta a la acción. Aquí va un ejemplo de un formulario HTML muy simple que contiene un campo de texto, un botón, y un div usado para mostrar un mensaje (Nota: puedes añadir este código a ExtStart.html si quieres seguir el ejemplo, pero deberás tener acceso a un servidor web para poder correr el código de servidor que aparece más abajo):

<div id="msg" style="visibility: hidden"></div>
Name: <input type="text" id="name" /> <br />
<input type="button" id="oKButton" value="OK" />

A continuación agregamos el JavaScript necesario para obtener nuestros datos y enviarlos a un proceso de servidor (reemplaza el código de ExtStart.js con este otro):

Ext.onReady(function(){
    Ext.get('oKButton').on('click', function(){
        var msg = Ext.get("msg");
        msg.load({
            url: [server url], // <-- reemplaza con tu URL, e.g. 'tutorial-ajax.php'
            params: "name=" + Ext.get('name').dom.value,
            text: "Actualizando..."
        });
        msg.show();
    });
});

(Nota: cuando vayas a probar este ejemplo, deberás abrir la página ExtStart.html solicitándola al servidor web, es decir, usando http:// y no file:// en la URL.)

¡Esperamos que el esquema general ya te empiece a resultar familiar! El código está envolviendo el botón okButton con un objeto Element, y asociando una función anónima que maneja el evento si alguien hace click en el botón. Dentro del manejador del evento click, usamos una clase especial de Ext llamada UpdateManager; esta clase hace que enviar una petición Ajax, recibir una respuesta y actualizar otro Element sea algo extremadamente trivial. El UpdateManager puede usarse directamente, o como estamos haciendo aquí, se puede acceder a él a través del Element que queremos actualizar (en este caso el div 'msg'), usando el método Element.load. Cuando se usa Element.load, la respuesta del servidor automáticamente reemplaza el innerHTML del Element. Simplemente pásale la URL del proceso del servidor que manejará la petición, los parámetros de la consulta para procesar (en este caso se le pasa el valor del campo 'name') y el texto a mostrar en el innerHTML del Element mientras se está procesando la petición. Muestra el div 'msg' (ya que comienza oculto por defecto) y ¡ya está! Por supuesto, como sucede con la mayoría de las cosas en Ext, hay muchas más opciones soportadas por UpdateManager, así como diferentes formas de procesar peticiones Ajax en diferentes situaciones, pero esto muestra lo fácil que es tener un ejemplo básico funcionando.

La última pieza del puzzle de Ajax es el proceso en el servidor web que efectivamente maneja las peticiones y devuelve una respuesta a la página. Este proceso puede ser una página del servidor, un servlet, un manejador HTTP, un servicio web, incluso un script de Perl o CGI—prácticamente cualquier cosa que pueda residir en un servidor web y procese peticiones HTTP. Desafortunadamente, debido a esta variedad no hay forma de dar un ejemplo estándar que cubra todas las posibilidades. Aquí van algunos ejemplos en algunos lenguajes comunes para que puedas empezar (este código simplemente repite de vuelta al cliente lo que le pasemos en el campo 'name', agregando al principio el texto 'Del servidor: ', y eso es lo que termina escrito en el div 'msg'):

PHP

<? if(isset($_REQUEST['name'])) {
        echo 'Del servidor: '.$_REQUEST['name'];
    }
?>

ASP.net

protected void Page_Load(object sender, EventArgs e)
{
    if (Request["name"] != null)
    {
        Response.Write("Del servidor: " + Request["name"]);
        Response.End();
    }
}

ColdFusion

<cfif StructKeyExists(url, "name")>
    <cfoutput>Del servidor: #url.name#</cfoutput>
</cfif>

El verdadero desafío al tratar con el procesamiento de Ajax es la cantidad de código requerido para procesar y formatear correctamente datos estructurados reales en el servidor. Hay varios formatos a escoger que son de uso común (normalmente JSON o XML). También hay muchas librerías específicas de un lenguaje disponibles para el procesamiento de Ajax que pueden funcionar bien con Ext, ya que Ext es neutral con respecto al lenguaje empleado en el servidor. Siempre que el resultado se envíe a la página en el formato de datos adecuado, ¡a Ext no le interesa lo que pase en el servidor!

¿Qué es lo siguiente?

Ahora que tienes una primera impresión de lo que es Ext y lo que tiene para ofrecer, hay muchos recursos disponibles para ayudarte a sumergirte en el próximo nivel: