Blog

ComponentQuery y los Selectores Blog

Tags: JavaScript Ext JS 4
Una de las mejoras que se introdujeron en la versión 4 de Ext JS es la clase ComponentQuery, esta utilería nos permite realizar búsquedas dentro del árbol de componentes que hemos creado, estas búsquedas las podemos hacer mediante el uso de selectores.

Es importante mencionar que cada que creamos un componente, una referencia a este componente se guarda en el Component Manager, si nuestro componente es un Container que contiene otros componentes entonces se va creando una estructura de árbol sobre la cual podemos realizar búsquedas para tomar la instancia de cualquier componente que hayamos creado.

Uso de Indentificadores

A lo largo de mi experiencia con Ext JS he visto muchos ejemplos, proyectos y snippets donde el desarrollador utiliza el identificador para obtener un componente de la siguiente manera:
var cmp = Ext.getCmp('my-awesome-component');
cmp.show();
El código anterior es una muy mala práctica que debemos evitar, ya que al utilizar identificadores en nuestros componentes existe un alto riesgo de que podamos duplicarlos, y por lo tanto tendremos problemas muy extraños pues estaremos modificando o ejecutando métodos de algún otro componente. Ahora bien, posiblemente se preguntarán ¿porque existe el método getCmp en la librería si es una mala práctica utilizarlo? La realidad es que ese método es muy útil a la hora de debuguear algún problema, ya que Ext JS internamente genera identificadores dinámicos y nos garantiza que no existirá duplicación. El ID de cada componente lo podemos ver en el nodo del DOM que representa ese componente visualmente, una vez que sabemos el ID del componente que necesitamos manipular podemos obtenerlo (usando el FireBug o el Chrome Developer Tools) para inspeccionarlo y encontrar un posible error de manera más sencilla.

Component Query al Rescate

Ya que el uso de identificadores no es recomendable entonces la solución es utilizar el Component Query para hacer búsquedas mediante selectores. Supongamos que tenemos el siguiente código donde mostramos algunos componentes anidados para poder realizar algunas búsquedas con el ComponentQuery.
Ext.onReady(function(){
        Ext.create('Ext.container.Viewport',{
            items   : [{
                xtype : 'container',
                height: 100,
                items : [{
                    xtype : 'panel',
                    itemId: 'mypanel',
                    title : 'A container',
                    layout  : 'hbox',
                    bodyPadding: 10,
                    items : [{
                        xtype : 'panel',
                        flex  : 1,
                        title : 'First Panel',
                        html  : 'This is a test'
                    },{
                        xtype       : 'panel',
                        title       : 'Testing',
                        html        : 'A panel',
                        collapsible : true,
                        flex        : 1
                    }]
                }]
            },{
                xtype : 'panel',
                itemId: 'mypanel',
                html  : 'Testing',
                title : 'One more'
            }]
        });


    });
Para crear un selector usamos el xtype de cada componente para referirnos a un componente en específico. Para buscar el contenedor principal podemos hacer lo siguiente:
var panels = Ext.ComponentQuery.query('viewport panel');
console.log(panels);
Con ese selector tendremos todos los paneles que sean descendientes del viewport, es decir que estén dentro del arreglo items del mismo viewport o de alguno de sus hijos. También podemos usar el itemId que es un identificador contextual, es decir que podemos tener identificadores repetidos en otros niveles y no tendremos problemas.
var panels =  Ext.ComponentQuery.query('viewport #mypanel');
console.log(panels);
En el ejemplo anterior vemos que para referirnos a un identificador contextual (también aplica para un ID normal) usamos el simbolo numeral, almuadilla, gatito (#). El resultado del código anterior es que nos regresará un arreglo con dos elementos, esto es porque tenemos dos componentes con el mismo identificador, si quisieramos tomar uno solo tendríamos que ser más específicos en nuestro selector.
var panels =  Ext.ComponentQuery.query('viewport container #mypanel');
console.log(panels);
Vemos que ahora solo obtenemos uno, esto es porque en el selector le indicamos que queremos el componente que esta dentro de un contenedor. Un consejo que les daría es que siempre utilicen selectores lo más específico posible, esto para evitar seleccionar componentes no deseados. También podemos usar alguna de las propiedades dentro de nuestro selector como en el siguiente ejemplo.
var panels =  Ext.ComponentQuery.query('viewport container #mypanel panel[collapsible=true]');
console.log(panels);
Como se puede observar usamos los corchetes para referirnos a las propiedades, así podemos referirnos a cualquier propiedad, inclusive podemos definir nuevas propiedades a un objeto y referirnos a ellas en el selector.

Búsquedas ascendentes y descendentes

Cada componente tiene tres métodos definidos que utilizan internamente la clase ComponentQuery, estos métodos nos sirven para realizar búsquedas a partir del componente que tenemos y no desde el principio del árbol. Si quisiéramos buscar algún hijo o descendiente de algún componente del cual ya tenemos la instancia, lo haríamos usando el método down.
var panel = Ext.ComponentQuery.query('viewport container #mypanel')[0];
var child = panel.down('panel[collapsible=true]');
console.log(child);
Mediante el uso del método down podemos obtener los hijos del componente en cuestión, es importante mencionar que este método no regresa un arreglo de elementos, por el contrario siempre retornará la primera coincidencia. De la misma manera en que tenemos el método down para buscar de manera descendente, tenemos el método up para buscar de manera ascendente.
var panel = Ext.ComponentQuery.query('viewport container #mypanel')[0];
var parent = panel.down('container');
console.log(parent);

Conclusión

La clase ComponentQuery es muy útil a la hora que requerimos obtener las instancias de nuestros componentes, esta clase se utiliza mucho dentro de los controladores, y es como podemos tener acceso a nuestras vistas desde un controlador de una manera muy sencilla. Recuerda que puedes seguir al autor en Twitter (@crysfel) o darnos un like en Facebook para estar al tanto de nuevos tutoriales.

Se el primero en comentar!

Instructor del curso

Crysfel3

Autor: Crysfel Villa

Soy un geek que disfruta crear y compartir cosas en internet! Sígueme en twitter @crysfel