Comunidad de diseño web y desarrollo en internet online

Ordenar y filtrar datos de los componentes de Flex

Cuando se desarrollan aplicaciones que deben mostrar un gran número de datos al usuario, es necesario que estén organizados de la mejor manera posible, de modo que el usuario invierta el menor tiempo posible en encontrarlos. La arquitectura de los componentes de Flex y el lenguaje ActionScript 3 pueden ayudarnos en esta tarea.

En primer lugar, veamos cómo funcionan los dataProvider de los componentes de Flex: tanto el dataProvider de un componente relativamente sencillo, como List, como el de un componente bastante más avanzado, como el DataGrid, es una función getter/setter que convierte los datos que le pasamos en cualquier formato a un objeto que extiende a la clase ListCollectionView (básicamente XMLListCollection si proviene de datos con formato XML y ArrayCollection en otro caso), que proporciona funcionalidades muy interesantes para manejar los datos. Por tanto, si tengo en Flex algo como esto:

Código :

<mx:List id="lista" width="205">
            <mx:dataProvider>
               <mx:Array>
                  <mx:String>unoZ</mx:String>
                  <mx:String>dosY</mx:String>
                  <mx:String>tresX</mx:String>
                  <mx:String>cuatroW</mx:String>
                  <mx:String>cincoV</mx:String>
                  <mx:String>seisU</mx:String>
                  <mx:String>sieteT</mx:String>
                  <mx:String>ochoS</mx:String>
                  <mx:String>nueveR</mx:String>
               </mx:Array>
            </mx:dataProvider>
         </mx:List>


al pedirle el dataProvider se comportará como un ArrayCollection, en vez de como un Array. Por ejemplo, no funcionará lista.dataProvider.push(item), pero sí lista.dataProvider.addItem(item).

Bueno, una vez entendido esto, podemos ver que ListCollectionView tiene una propiedad filterFunction. Ésta es una función que obligatoriamente ha de tener la siguiente sintaxis:

Código :

private function funcionParaFiltrar (itemParaFiltrar : Object) : Boolean

Esta función se repite con cada uno de los elementos de la lista. Si devuelve true el elemento permanece, y si devuelve false es filtrado. Cada vez que la función de filtrado cambia, hay que llamar al método refresh del ListCollectionView, para poder ver los cambios.

Yo encuentro muy útiles esas cajas de texto que hay sobre una lista (por ejemplo la biblioteca de Winamp) que filtran los datos, y dejan sólo los que empiezan por la misma cadena que el texto que hay escrito. Para que entiendan, lo que hace el SuggestComboBox. Hacer eso en Flex es bastante fácil, con algo como esto basta:

Código :

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
   <mx:Script>
      <![CDATA[
         private function filtrar (ev : Event) : void
         {
            lista.dataProvider.filterFunction = filtroTexto;
            lista.dataProvider.refresh();
         }

//
//
         private function filtroTexto (item : Object) : Boolean
         {
                                //Conviene utilizar siempre la función toString() y poner el data type de item a Object aunque sepamos que
                               //se trata de una cadena, ya que así podremos utilizar la misma función con cualquier otro tipo de datos. 
            return item.toString().substr(0, filtro_txt.text.length).toLowerCase() == filtro_txt.text.toLowerCase()   
         }
      ]]>
   </mx:Script>


<mx:VBox height="100%">
      <mx:HBox width="100%">
         <mx:Label text="Filtro:"/>
         <mx:TextInput id="filtro_txt" change="filtrar (event)"/>
      </mx:HBox>
      <mx:HBox width="100%">
         <mx:List id="lista" width="205">
            <mx:dataProvider>
               <mx:Array>
                  <mx:String>unoZ</mx:String>
                  <mx:String>dosY</mx:String>
                  <mx:String>tresX</mx:String>
                  <mx:String>cuatroW</mx:String>
                  <mx:String>cincoV</mx:String>
                  <mx:String>seisU</mx:String>
                  <mx:String>sieteT</mx:String>
                  <mx:String>ochoS</mx:String>
                  <mx:String>nueveR</mx:String>
               </mx:Array>
            </mx:dataProvider>
         </mx:List>
   </mx:VBox>
   
</mx:Application>



Para ordenar tenemos una clase entera: la clase Sort. Ésta nos permite definir qué propiedades queremos tener en cuenta para el orden (cuando se trata de arrays de objetos) o buscar en esas propiedades. ListCollectionView tiene una propiedad sort (que por defecto es null) que es la que se encarga del orden de los elementos. Aquí nos centraremos en la propiedad Sort.compareFunction, que es una función que ha de tener la siguiente sintaxis:

Código :

private function funcionParaOrdenar (item1 : Object , item2 : Object , camposQueEntranEnElOrden : Array = null) : int
{
  //Devuelve -1 si item1 va primero.
  //Devuelve 1 si item2 va primero.
  //Devuelve 0 si da igual.
}


Con esta función podremos ordenar los datos de cualquier manera pintoresca que se nos ocurra, por ejemplo en orden alfabético de la última letra, o aleatorio, de modo que el código completo quede así:

Código :

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
   <mx:Script>
      <![CDATA[
         import mx.collections.Sort;
         private function filtrar (ev : Event) : void
         {
            lista.dataProvider.filterFunction = filtroTexto;
            lista.dataProvider.refresh();
         }
         
         private function ordenar (ev : Event) : void
         {
         //   lista.dataProvider.sdsadfd;
            var sort : Sort = new Sort ()
            if (ev.target == ordenarUltimo_btn)
            {
               sort.compareFunction = ordenUltimaLetra;
            }else if (ev.target == ordenarRandom_btn)
            {
               sort.compareFunction = ordenAleatorio;
            }
            lista.dataProvider.sort = sort;
            lista.dataProvider.refresh ();
         }
         
         private function filtroTexto (item : Object) : Boolean
         {
            return item.toString().substr(0, filtro_txt.text.length).toLowerCase() == filtro_txt.text.toLowerCase()   
         }
         
         private function ordenUltimaLetra (a : Object , b : Object , fields : Array = null) : int
         {
            var lastChar1 : String = a.toString().charAt(a.toString().length-1)
            var lastChar2 : String = b.toString().charAt(b.toString().length-1);
            if (lastChar1 > lastChar2)
            {
               return 1;
            }else if (lastChar1 < lastChar2)
            {
               return -1;   
            }else {
               return 0;
            }
         } 
         
         private function ordenAleatorio (a : Object , b : Object , fields : Array = null) : int
         {
            //Esto devuelve siempre -1 o 1 ya que Math.round(Math.random() es 0 o 1 al 50%
            return (Math.round(Math.random()) * 2) - 1;
         }
      ]]>
   </mx:Script>
   <mx:VBox height="100%">
      <mx:HBox width="100%">
         <mx:Label text="Filtro:"/>
         <mx:TextInput id="filtro_txt" change="filtrar (event)"/>
      </mx:HBox>
      <mx:HBox width="100%">
         <mx:List id="lista" width="205">
            <mx:dataProvider>
               <mx:Array>
                  <mx:String>unoZ</mx:String>
                  <mx:String>dosY</mx:String>
                  <mx:String>tresX</mx:String>
                  <mx:String>cuatroW</mx:String>
                  <mx:String>cincoV</mx:String>
                  <mx:String>seisU</mx:String>
                  <mx:String>sieteT</mx:String>
                  <mx:String>ochoS</mx:String>
                  <mx:String>nueveR</mx:String>
               </mx:Array>
            </mx:dataProvider>
         </mx:List>
         <mx:VBox height="100%">
            <mx:Button id="ordenarUltimo_btn" label="Orden por última letra"  click="ordenar (event)" width="100%"/>
            <mx:Button id="ordenarRandom_btn" label="Orden aleatorio"  click="ordenar (event)" width="100%"/>
         </mx:VBox>
      </mx:HBox>
   </mx:VBox>
   
</mx:Application>


Aplicando esto, se pueden conseguir interfaces mucho más usables, por ejemplo con un ComboBox que sugiera palabras.
Espero que les haya servido ^^

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate