Trabajar con Flex DataGrid y las estructuras de datos anidadas

A menudo sucede que los datos que deben verse / presentarse en un Flex DataGrid provienen de un archivo XML o JSON con más de un nivel de anidamiento. Desafortunadamente, de forma predeterminada, Flex DataGrid le permite mostrar solo matrices de objetos anidados de un solo nivel.

Este tutorial muestra cómo puede extender la clase Flex DataGrid para acomodar estructuras de datos más complicadas. También le mostrará cómo hacer que todas las columnas se puedan ordenar, incluso cuando se usan estructuras de datos anidadas.




Introducción

Este tutorial asume que usted conoce los conceptos básicos de Flex, cómo usar Flex Builder y cómo escribir archivos MXML. Debe tener una copia de Flex Builder instalada en su sistema.

Paso 1: Configurar el Proyecto Flex

El primer paso es configurar el proyecto en Flex Builder. Crea un nuevo proyecto en Flex Builder con Nombre del proyecto como "NestedDataGrid" y tipo de aplicacion como "aplicación web (se ejecuta en Flash Player)". Deje todas las demás opciones en sus valores predeterminados y haga clic en Finalizar.

Paso 2: Importar datos de muestra

Los datos que vamos a mostrar en el DataGrid se obtienen de un archivo XML. Cree una carpeta en su carpeta 'src' llamada 'elementos' y coloque los datos que se muestran a continuación en un archivo llamado 'meetings.xml'. Alternativamente, puede descargar el archivo XML desde aquí y ponerlo en la carpeta 'elementos'.

    alto  Lisa verde [email protected] +330-7593  12 de julio de 2009  Habitacion 405   medio  Christopher Martin [email protected] +330-7553  14 de julio de 2009  Habitacion 405   alto  George Rodriguez [email protected] +330-7502  18 de julio de 2009  Habitación 771   alto  Jennifer parker [email protected] +330-5380  20 de agosto de 2009  Habitacion 562  

Paso 3: Hacer la interfaz

Aquí hay un rápido desglose de la construcción de la interfaz para mostrar los datos y los valores de ID apropiados necesarios para el código en este tutorial:

  1. Abra el archivo NestedDataGrid.mxml y vaya a la vista de diseño
  2. Arrastre y suelte un 'Panel' desde la vista Componentes. Establezca su ID en "meetingsPanel" y el título en "Meetings"
  3. Establezca la altura y el ancho del Panel en 500 y los valores X e Y en 0
  4. Arrastra y suelta un 'DataGrid' en el panel
  5. Establece los valores de X e Y en 10
  6. Establezca el ancho en meetingsPanel.width-40 y la altura en 45%
  7. Vaya a la vista de origen y, en la etiqueta 'mx: Appication', agregue el atributo layout = "vertical"

Su interfaz debe ser similar a la que se muestra en la imagen a continuación:

El MXML en la vista de origen debería verse así:

            

Leyendo en el archivo XML

En los siguientes tres pasos, creamos un componente HTTPService, leemos los datos del archivo XML y los almacenamos en una variable local. Esto se hace en tres etapas:

Paso 4: Crear el componente HTTPService

Cambie a la vista Fuente del archivo MXML y agregue el siguiente código justo debajo de la mx: Aplicación etiqueta:

 

La función httpResultHandler () se llamará cuando se hayan recuperado los datos. Si hay un error al obtener los datos, se llama a la función httpFaultHandler (). Tenga en cuenta que esto solo crea el objeto HTTPService, los datos se deben recuperar mediante una llamada de función explícita (consulte el subpaso 3)

Paso 5: httpResultHandler () y httpFaultHandler ()

Añadir un mx: Script etiqueta justo debajo de la mx: Aplicación etiqueta. Dentro de eso, defina la variable que contendrá los datos entrantes y las funciones para manejar los eventos del componente HTTPService. El código para hacer que se vea así:

 importar mx.rpc.events.FaultEvent; importar mx.rpc.events.ResultEvent; importar mx.collections.ArrayCollection; importar mx.controls.Alert; [Bindable] public var dataForGrid: ArrayCollection; función privada httpResultHandler (event: ResultEvent): void dataForGrid = event.result.meetings.meeting;  función privada httpFaultHandler (evento: FaultEvent): void Alert.show ("Se produjo un error al obtener la cadena"); 

La variable 'dataForGrid' contiene los datos que vamos a leer. La etiqueta '[Bindable]' asegura que cada vez que los datos cambian (cuando se leen), el DataGrid se actualiza en consecuencia. El XML se lee como un objeto que se pasa a través del evento 'ResultEvent', y 'event.result.meetings.meeting' accede al ArrayCollection de los objetos 'meeting'.

Paso 6: Obtenga los datos del archivo XML

En este paso, se realiza la llamada a la función real para obtener los datos XML. Se asigna una función de inicialización al evento que se activa cada vez que se carga la aplicación: el evento 'creationComplete'. Agregar el atributo creationComplete = "getData ()" a la etiqueta 'mx: Application' y defina la función 'getData ()' como se muestra a continuación (que se agregará después de la función 'httpFaultHandler'):

 función privada getData (): void readXML.send (); 

Esto hace que el objeto HTTPService obtenga los datos del archivo. Una vez que se recuperan los datos, se activa el evento 'resultado' que llama a la función 'httpResultHandler ()'. Si hay un problema para obtener los datos, se activa el evento 'falla', que llama a la función httpFaultHandler ().

Paso 7: Hito

En este punto, su NestedDataGrid.mxml debería verse así:

                

Paso 8: DataGrid con datos no anidados

Solo señalaré brevemente por qué los datos anidados plantean problemas en la visualización, al demostrar primero cómo se muestran los datos no anidados. Por ejemplo, a partir del archivo XML anterior, solo quería mostrar la fecha, el lugar y la prioridad de las reuniones (y no la información del presentador). El siguiente código podrá mostrarlo sin problemas (el contenido de 'mx: Panel' se muestra aquí. El resto del código es el mismo):

        

El resultado de esta sería la siguiente aplicación:


Tenga en cuenta que el atributo dataProvider de DataGrid se puede asignar directamente a ArrayCollection 'dataForGrid', y cada DataGridColumn que se encuentra dentro recibe un atributo dataField que corresponde directamente al nombre de la propiedad. Sin embargo, si desea acceder a la información del nombre del presentador, se puede acceder a ella como "presenter.name". Si intenta dar este valor al 'campo de datos' obtendrá un error. Esto se debe a que Flex no admite objetos anidados de forma predeterminada. Siga leyendo para aprender cómo resolver este problema extendiendo la clase DataGridColumn y escribiendo su propio código para manejar este caso.

Paso 9: crear la clase NestedDataGridColumn

Redefinimos algunas funciones en la clase de columna DataGrid para sortear el problema descrito anteriormente. Primero cree una carpeta en el directorio 'src' llamado 'clases'. Cree una nueva 'Clase de ActionScript' en esa carpeta, llamada "NestedDataGridColumn". En el campo "Superclase", haga clic en "Examinar ..." y seleccione "DataGridColumn" en la lista que aparece. Deje todo lo demás en los valores predeterminados y haga clic en 'Finalizar'. Se debe haber creado un nuevo archivo y rellenarse con el siguiente código:

 clases de paquete import mx.controls.dataGridClasses.DataGridColumn; la clase pública NestedDataGridColumn extiende DataGridColumn función pública NestedDataGridColumn (columnName: String = null) super (columnName); 

Paso 10: Declarar la propiedad 'nestedDataField'

En la clase NestedDataGridColumn, agregue una variable vinculable pública llamada 'nestedDataField'. Usaremos esto en lugar de la propiedad predeterminada 'dataField' para pasar el nombre del campo. Esto es vital, porque si se usa la propiedad predeterminada 'dataField', un error dice Error: los criterios de búsqueda deben contener al menos un valor de campo de clasificación. ocurrirá cuando intentemos ordenar el DataGrid después de haber definido la función de clasificación personalizada más adelante.

Paso 11: redefiniendo la función 'itemToLabel'

Como puede ver, la nueva clase que creamos ya se ha completado con un constructor. Deje el constructor como está y debajo, agregue la siguiente función:

 anular la función pública itemToLabel (data: Object): String var fields: Array; etiqueta var: String; var dataFieldSplit: String = nestedDataField; var currentData: Object = data; // comprueba si el valor nestedDataField contiene un '.' (es decir, está accediendo a un valor anidado) si (nestedDataField.indexOf (".")! = -1) // obtiene todos los campos que necesitan acceso campos = dataFieldSplit.split ("."); para cada (var f: Cadena en campos) // recorra los campos uno por uno y obtenga el valor final, yendo a un campo en cada iteración currentData = currentData [f]; if (currentData es String) // devuelve el valor final return String (currentData);  // si no hay ningún anidamiento involucrado otra cosa if (dataFieldSplit! = "") currentData = currentData [dataFieldSplit];  // si nuestro método no ha funcionado como se esperaba, recurra a llamar a la función predeterminada intente label = currentData.toString ();  catch (e: Error) label = super.itemToLabel (data);  // devolver la etiqueta de retorno de resultado; 

La redefinición de la función 'itemToLabel' es la clave para poder acceder a los datos anidados en su DataGrid. La función itemToLabel controla lo que se muestra en las filas de DataGrid. Así que lo usamos aquí para pedirle a Flex que muestre los datos anidados de la manera que hemos especificado.

Como puede ver, la definición de la función comienza con la palabra clave 'sobrescribir', lo que significa que la función predefinida predeterminada del mismo nombre se reemplaza en favor de la función que ha definido. Cada declaración se explica en los comentarios. En resumen, lo que hace la función es verificar si se está accediendo a los campos de datos anidados (si hay un '.' Presente). Si es así, obtenga el nombre de cada campo de datos e itérelo a través del DataProvider, profundizando cada paso al acceder al campo secundario.

Flex llama a la función 'itemToLabel' con un argumento que contiene el ArrayCollection que se especificó como el DataProvider para el dataGrid. Se puede acceder directamente a todos los atributos de NestedDataGridColumn (cuando se usa en el archivo mxml), y se puede asignar un valor en MXML a cualquier propiedad pública definida en esta clase. En nuestro archivo NestedDataGrid.mxml, reemplazamos los componentes 'mx: DataGridColumn' con 'classes: NestedDataGridColumn', y asignamos los elementos específicos que queremos mostrar en las columnas al atributo 'nestedDataField' (que se declaró en el ' NestedDataGridColumn.as 'archivo). El DataGridColumn ahora debería verse así:

          

Tenga en cuenta que estoy especificando directamente la propiedad 'nestedDataField' como "presenter.name" y "presenter.phone" aquí. Además, he agregado anchos a las columnas y he establecido el ancho del componente 'mx: Panel' en 600px para una mejor visualización. He añadido la propiedad 'ordenable' para que sea falsa para las dos nuevas columnas. Si elimina esto (o lo configura en verdadero) y ejecuta el programa, la columna no se ordenará. Resolveremos esto en el siguiente paso definiendo nuestra propia función de clasificación. Por ahora la aplicación debería verse así:


Paso 12: Escribir la función de ordenación personalizada

Lo único que queda ahora es definir la función de clasificación personalizada para que la clasificación también se habilite en todos los campos (por ejemplo, si desea ordenar los nombres de los presentadores alfabéticamente). Agregue la función llamada 'mySortCompareFunction' debajo de la función 'itemToLabel' como se indica:

 función privada mySortCompareFunction (obj1: Object, obj2: Object): int var fields: Array; var dataFieldSplit: String = nestedDataField; var currentData1: Object = obj1; var currentData2: Object = obj2; if (nestedDataField.indexOf (".")! = -1) fields = dataFieldSplit.split ("."); para cada (var f: String en los campos) currentData1 = currentData1 [f]; currentData2 = currentData2 [f];  else else if (dataFieldSplit! = "") currentData1 = currentData1 [dataFieldSplit]; currentData2 = currentData2 [dataFieldSplit];  si (currentData1 es int && currentData2 es int) var int1: int = int (currentData1); var int2: int = int (currentData2); Resultado var: int = (int1> int2)? - 1: 1; resultado de retorno  if (currentData1 es String && currentData2 es String) currentData1 = String (currentData1); currentData2 = String (currentData2); return (currentData1> currentData2)? - 1: 1;  if (currentData1 es Date && currentData2 es Date) var date1: Date = currentData1 como Fecha; var date2: Date = currentData2 as Date; var date1Timestamp: Number = currentData1.getTime (); var date2Timestamp: Number = currentData2.getTime (); return (date1Timestamp> date2Timestamp)? - 1: 1;  devuelve 0; 

Flex llamará a esta función con dos objetos, y se espera que devuelva -1.0 o 1 dependiendo de si el primer objeto es mayor, igual o menor que, respectivamente, el segundo objeto. Flex se encarga de la clasificación real.

Esta función utiliza la misma lógica que la función 'itemToLabel' para obtener el valor anidado apropiado. Luego, dependiendo del tipo de valor (ya sea int, String o Date), lo compara adecuadamente y devuelve -1 si 'currentData1' es mayor que 'currentData2', 0 si son iguales y 1 si 'currentData2 'es mayor que' currentData1 '.

Paso 13: Conectar la función de clasificación personalizada

Si se dio cuenta, 'customSortCompareFunction' no es una función predefinida en la clase DataGridColumn que reemplazamos. Esta función tiene que asignarse como la función de clasificación de una manera diferente. Debemos asignar a la variable predefinida 'sortCompareFunction' el nombre de la función de clasificación, que en nuestro caso es 'customSortCompareFunction'. Esto debe hacerse dentro del constructor. El constructor ahora se ve así:

 función pública NestedDataGridColumn (columnName: String = null) // la función de clasificación personalizada que se asigna a la variable predefinida sortCompareFunction = mySortCompareFunction; super (columnName); 

Una vez hecho esto, estás listo. Ahora tiene una clase personalizada que puede manejar datos anidados arbitrariamente para mostrar en un DataGrid. Y puedes ordenar la grilla como quieras..

Conclusión

Hoy aprendió a evitar una limitación de la clase FlexDataGrid para obtener datos anidados arbitrariamente y mostrarlos en un DataGrid. También aprendió cómo definir su propia función de clasificación para que la cuadrícula siga ordenable. Ahora puede usar este NestedDataGridColumn en todas sus aplicaciones sin ningún gasto..

Puede ampliar aún más la función 'itemToLabel' para incluir otro formato de acceso arbitrario, por ejemplo, acceder a matrices dentro de los objetos secundarios o acceder a atributos xml. También puede ampliar la función de clasificación para ordenar otros tipos de datos. También puede agregar otras funciones, como colorear las filas según la prioridad de la reunión y mostrar más detalles sobre el presentador haciendo clic en una fila.

Gracias por leer :)