¿Qué es un store y cómo funciona?

http://www.quizzpot.com/2009/04/que-es-un-store-y-como-funciona/

El tema de hoy es fundamental ya que el objeto Store es utilizado por los componentes que necesitan comunicarse con el servidor para mostrar la información, en este tema daré un vistazo rápido a lo más importante de este componente.

Un Store es un componente que almacena temporalmente información mediante registros, es utilizado como caché. Es importante mencionar que el Store contiene a otro componente capaz de leer e interpretar la información recibida, este lector es configurado antes de solicitar la información local o al servidor.

Material de apoyo

Para este tema el material de apoyo es un HTML y un JS donde estaremos trabajando, así que es necesario descargarlo y copiarlos dentro de la carpeta “ajax” que creamos en el tema anterior la cual está dentro de la carpeta “curso” en el servidor Web que instalamos en el primer capítulo de este curso.

Encapsulando el tutorial

Antes de comenzar con el ejemplo tenemos que encapsular el código que estaremos escribiendo para evitar coaliciones.

  1. //El namespace para este tutorial
  2. Ext.ns(‘com.quizzpot.tutorial’);
  3. com.quizzpot.tutorial.Store = {
  4.     //Información dummy irá aquí
  5.     init: function(){
  6.         //esto será ejecutado cuando el DOM esté listo
  7. //crear el store aquí
  8.         //cargar la información en el store aquí
  9.         //crear los “listeners” de los botones aquí
  10.     }
  11.     //crear el método “orderAsc” aquí
  12.     // crear el método “orderDesc” aquí
  13.     // crear el método “filter” aquí
  14.     // crear el método “query” aquí
  15.     // crear el método “count” aquí
  16.     // crear el método “find” aquí
  17.     // crear el método “log” aquí
  18. }
  19. //disparamos la función “init” cuando el DOM esté listo
  20. Ext.onReady(com.quizzpot.tutorial.Store.init,com.quizzpot.tutorial.Store);

He comentado el lugar donde escribiremos el código del tutorial, con la intención de que tengas una idea global de la estructura final del código.

La información

Para este ejemplo vamos a tomar la información de un arreglo, es importante mencionar que debemos crear un arreglo bidimensional el cual será “procesado” por el store que crearemos más adelante, este arregló estará al inicio del objeto “com.quizzpot.tutorial.Store” de la siguiente manera:

  1. data: [ //información dummy para el ejemplo
  2.     [1,’Crysfel’,’Software developer’,’m’,25],
  3.     [2,’Sasha’,’Figure skater’,’f’,23],
  4.     [3,’Jack’,’Software Architect’,’m’,35],
  5.     [4,’John’,’Javascript developer’,’m’,24],
  6.     [5,’Sara’,’Tester’,’f’,31]
  7. ],

La información está contenida en un arreglo el cual contiene otros arreglos con la información, cada arreglo interno será un registro donde la posición cero es el “identificador” del registro, la posición uno es el “nombre” de una persona, la posición dos la “ocupación”, la posición tres es el “género” de la persona y la posición número cinco es la “edad”.

Crear un Store con información local

Ahora vamos a crear un “SimpleStore” con el que estaremos trabajando en este tutorial, esto lo hacemos de la siguiente manera:

  1. //creamos una instancia del SimpleStore
  2. this.store = new Ext.data.SimpleStore({
  3.     fields: [ //definimos los campos que tendrá…
  4.         {name:’name’,mapping:1}, //cada registro…
  5.         {name:’occupation’,mapping:2}, // y lo relacionamos…
  6.         {name:’gender’,mapping:3},// con una posición en el…
  7.         {name:’age’,mapping:4}//arreglo que tiene la información
  8.     ],
  9.     id: 0 //definimos la posición del ID de cada registro
  10. });

Hasta este punto hemos creado el store, aún no tiene información pero ya es capaz de leer el arreglo que definimos anteriormente, la propiedad “fields”, que esta en la configuración del store, es donde se define el nombre de las propiedades de los registros mediante la propiedad “name” y se relaciona al arreglo con la información mediante la propiedad “mapping”, en este caso la propiedad mapping se le asigna la posición en el arreglo de donde sacará su contenido.

Cargar la información en el Store

Introducir la información en el Store es muy fácil ya que estamos usando información local contenida en un arreglo. Para que el store pueda consumir el arreglo definido lo hacemos de la siguiente manera:

  1. //cargar la información del arreglo
  2. this.store.loadData(this.data);

Si todo ha salido bien ya podremos usar la información contenida en el store.

Crear los “listeners” de los botones

Lo siguiente que haremos es crear los “listeners” del evento clic de cada botón que hay en el documento html.

  1. Ext.fly(‘personBtn’).on(‘click’,this.find,this);
  2. Ext.fly(‘txt’).on(‘keyup’,function(event,cmd){
  3.     if(event.getKey() === event.ENTER){ //cuando sea la tecla ENTER
  4.         this.find(); // realizamos la búsqueda
  5.     }
  6. },this);
  7. Ext.fly(‘ascBtn’).on(‘click’,this.orderAsc,this);
  8. Ext.fly(‘descBtn’).on(‘click’,this.orderDesc,this);
  9. Ext.fly(‘older2030Btn’).on(‘click’,this.query,this);
  10. Ext.fly(‘older30Btn’).on(‘click’,this.filter,this);
  11. Ext.fly(‘countBtn’).on(‘click’,this.count,this);

El código anterior ya es familiar para nosotros, de no ser así te recomiendo darle un repaso a los temas anteriores donde se habló al respecto, lo más importante a resaltar es que las funciones que se han asignado a cada evento no las hemos definido.

Ordenar los registros

Ordenar la información es muy importante, y podemos hacerlo de una manera muy sencilla utilizando el método “sort”.

  1. , //nota la coma separadora XD
  2. orderAsc: function(){
  3.     this.store.sort(‘name’,’ASC’); // ordenar en forma ascendente
  4.     this.store.each(function(record){//por cada registro…
  5.         this.log(record.get(‘name’)); //imprime la propiedad “nombre”
  6.     },this);
  7.     this.log(‘___________________________________’);
  8. }, // <— esta coma es importante
  9. orderDesc: function(){
  10.     this.store.sort(‘name’,’DESC’); //Ordenar en forma descendente
  11.     this.store.each(function(record){ // por cada registro…
  12.         this.log(record.get(‘name’)); //imprime la propiedad “nombre”
  13.     },this);
  14.     this.log(‘___________________________________’);
  15. }

El método “sort” recibe como primer parámetro la propiedad por la que serán ordenados los registros y como segundo parámetro el tipo de orden, ascendente o descendente; una vez que se han ordenado se pueden recorrer los registros utilizando el método “each” del store, el cual itera sobre los registros.

El método “log” no ha sido definido aún, lo haremos más adelante, por ahora puedes poner un “console.debug” para imprimir en la consola de Firebug.

Filtrar registros en el store

En ocasiones es necesario filtrar la información contenida en el Store dependiendo algún criterio dado, en este ejemplo voy a realizar un filtro de las personas cuya edad sea mayor de 30 años; esto lo haré utilizando el método “filterBy”.

  1. , // <— La coma separadora
  2. filter: function(){
  3.     //filtrar a las personas…
  4.     this.store.filterBy(function(record,id){
  5.         return record.get(‘age’) >= 30; //mayores a 30 años
  6.     });
  7.     //por cada registro…
  8.     this.store.each(function(record){
  9.         //imprimir en el “log”
  10.         this.log(record.get(‘name’)+’ is older than 30 ‘+(record.get(‘gender’)==’f’?’she’:’he’)+’ is ‘+record.get(‘age’));
  11.     },this);
  12.     //limpiar los filtros
  13.     this.store.clearFilter();
  14.     this.log(‘___________________________________’);
  15. }

El método “filterBy” acepta como primer parámetro una función que será ejecutada por cada registro del store, ahí es donde se ha definido la condición deseada (edad mayor a 30 años), cuando la función retorne “true” el registro será tomado en cuenta y cuando retorne “false” el registro será descartado.

Luego de aplicar el filtro al store se ejecuta la función “each”, es importante mencionar que la función “each” únicamente será ejecutada sobre los registros que han sido filtrados anteriormente ya que se le ha aplicado un filtro al store.

Por último mediante la función “clearFilter” se limpian los filtros aplicados al store, permitiendo que todos los registros puedan ser utilizados nuevamente.

Buscar registros

El método anterior nos proporciona un manera de buscar registros descartando los registros que no necesitamos, el método “queryBy” hace algo semejante pero la diferencia es que regresa los registros encontrados en una colección, esto nos puede ser más útil o quizás más claro que el método anterior.

  1. ,//<— La coma separadora
  2. query: function(){
  3.     //buscar gente mayor a 20 y menor que 30 años
  4.     var collection = this.store.queryBy(function(record,id){
  5.         return record.get(‘age’) >20 && record.get(‘age’)<30;
  6.     });
  7.     //por cada item en la colección
  8.     collection.each(function(item,index){
  9.         //imprime su nombre y edad
  10.         this.log(item.get(‘name’)+’ is ‘+item.get(‘age’)+ ‘ and ‘+(item.get(‘gender’)==’f’?’she’:’he’)+’ is younger than 30′);
  11.     },this);
  12.     this.log(‘___________________________________’);
  13. }

Como puedes notar es muy semejante (por no decir igual) que el método anterior, la única diferencia es que regresa una colección con los registros que cumplen la condición especificada.

Buscar por una propiedad

Si queremos buscar un registro único podemos utilizar el método “find” el cual recibe como primer parámetro la propiedad sobre la cual queremos realizar la búsqueda, como segundo parámetro recibe un “String” o una expresión regular con el criterio de búsqueda, el tercer parámetro es opcional y es el número de registro donde comenzará a realizar la búsqueda, en el cuarto parámetro que también es opcional definimos si la búsqueda será ejecutada en cualquier parte del texto y el quinto parámetro define si queremos que ignore las mayúsculas y minúsculas.

  1. //propiedad: name
  2. //value: Crys
  3. //comienza en: 0
  4. //sobre cualquier parte del valor del registro
  5. //no toma en cuenta mayúsculas y minúsculas
  6. this.store.find(‘name’, ‘Crys’,0,true,false);

Lo que regresa el método “find” es el índice donde encuentra la primera coincidencia, en caso de no encontrar nada regresará un “-1”.

  1. ,
  2. find: function(){
  3.     //tomamos lo que se introdujo en la caja de texto
  4.     var value = Ext.fly(‘txt’).getValue();
  5. //si no hay nada salimos de esta función
  6.     if(Ext.isEmpty(value)) return;
  7.     //realizamos la búsqueda sobre la propiedad “name”
  8.     var index = this.store.find(‘name’,value,0,true,false);
  9.     //si en encontró algo
  10.     if(index>=0){
  11.         //tomamos el registro por medio del índice…
  12.         var record = this.store.getAt(index);
  13.         //e imprimimos la información encontrada
  14.         this.log(record.get(‘name’)+’ work as a ‘+record.get(‘occupation’)+’ and ‘+(record.get(‘gender’)==’f’?’she’:’he’)+’ is ‘+record.get(‘age’)+’ years old’);
  15.     }else{
  16.         //si nada fue encontrado se le avisa al usuario
  17.         this.log(‘<strong>’+value+’ not found!</strong>’);
  18.     }
  19. }

Puedes ver que se ha utilizado el método “getAt” para tomar el registro completo dándole el índice que necesitamos.

Si sabemos el ID del registro podemos sacarlo inmediatamente utilizando el método “getById”, lo que vamos a hacer es verificar si el usuario introdujo un número en la caja de texto, de ser así utilizaremos el ID, si es texto entonces ejecutaremos el código anterior.

  1. , //<—
  2. find: function(){
  3.     //tomamos lo que se introdujo en la caja de texto
  4.     var value = Ext.fly(‘txt’).getValue();
  5. //si no hay nada salimos de esta función
  6.     if(Ext.isEmpty(value)) return;
  7.     //si el valor es númerico
  8.     if(/^\d+$/.test(value)){
  9.         //buscamos por ID
  10.         var record = this.store.getById(value);
  11.         if(!Ext.isEmpty(record)){
  12.             //si se encontró algo se imprime
  13.             this.log(record.get(‘name’)+’ work as a ‘+record.get(‘occupation’)+’ and ‘+(record.get(‘gender’)==’f’?’she’:’he’)+’ is ‘+record.get(‘age’)+’ years old’);
  14.         }else{
  15.             //si nada fue encontrado se avisa al usuario
  16.             this.log(‘<strong>Record with id: ‘+value+’ was not found!</strong>’);
  17.         }
  18.     }else{
  19.         //realizamos la búsqueda sobre la propiedad “name”
  20.         var index = this.store.find(‘name’,value,0,true,false);
  21.         //si en encontró algo
  22.         if(index>=0){
  23.             //tomamos el registro por medio del índice…
  24.             var record = this.store.getAt(index);
  25.             //e imprimimos la información encontrada
  26.             this.log(record.get(‘name’)+’ work as a ‘+record.get(‘occupation’)+’ and ‘+(record.get(‘gender’)==’f’?’she’:’he’)+’ is ‘+record.get(‘age’)+’ years old’);
  27.         }else{
  28.             //si nada fue encontrado se le avisa al usuario
  29.             this.log(‘<strong>’+value+’ not found!</strong>’);
  30.         }
  31.     }
  32. }

El código anterior decide si la búsqueda será realidad por ID o por la propiedad especificada (en este caso “name”).

Contar los registros del store

Para contar los registros que actualmente están en el store es muy fácil, únicamente utilizamos el método “getCount”.

  1. ,
  2. count: function(){
  3.     //imprime el total de registros
  4.     this.log(‘<strong>Total records: ‘+this.store.getCount()+'</strong>’);
  5. }

Notar que este método solo regresa los registros que actualmente están en el store.

El Log

Por último vamos a definir el método “log” que hemos estado usando para desplegar los mensajes.

  1. ,
  2. log: function(txt){
  3.     var el = Ext.get(‘response’); // get the LOG
  4.     el.select(‘p.newest’).removeClass(‘newest’); // quitar la última actualización
  5.     Ext.DomHelper.append(el,'<p class=”newest”>’+txt+'</p>’); //actualizar el log
  6.     el.scrollTo(‘top’,el.dom.scrollHeight); //scroll abajo
  7.     el.select(‘p.newest’).highlight(‘F5FC49’,{duration:0.5}); //resaltar el ultimo mensaje
  8. }

Lo que hicimos en el código anterior es tomar el nodo “response” y agregarle párrafos con el texto que recibe, luego hacemos que destelle en color amarillo.

Conclusiones

Es importante que sepamos como buscar información contenida en un store, ya que este componente es muy usado para manipular información, es fundamental conocerlo para una mejor comprensión del Framework.

En este tema vimos un store muy sencillo que toma la información de un arreglo definido con JavaScript, en el mundo real la información viene de una base de datos, de una servicio Web o de algún otro lugar, en los siguientes temas veremos como realizar esto.

Si tienes alguna duda o pregunta déjalas en los comentarios con gusto las responderé y recuerda seguirnos en Twitter para estar al tanto de las actualizaciones o bien inscribirte a las Feeds.