miércoles, 3 de noviembre de 2010

Flex/AIR: DataGrids dinámicos (2)

En el anterior post sobre Datagrids dinámicos (http://rafinguer.blogspot.com/2010/11/flexair-datagrids-dinamicos.html), expusimos un ejemplo práctico en base a un XML clásico y básico. El planteamiento expuesto contempla que el nombre de cada elemento es también el texto de la columna. Pero, ¿y si el texto de la columna debe contener caracteres no alfabéticos, espacios, signos, etc.? Entonces no nos vale. Hemos de replantear el XML, por ejemplo, de la siguiente manera:

<?xml version="1.0" encoding="utf-8"?>
<vista2d>
 <fila>
  <columna nombre="Costes financieros">99898.95</columna>
  <columna nombre="Costes globales">78700.87</columna>
  <columna nombre="Costes internos">54980.76</columna>
 </fila>
 ...
</vista2d>


Las columnas serán todas elementos columna, y el nombre de la columna vendrá dado por el atributo nombre. Por tanto, ha de recogerse el atributo, no el nombre del elemento. Esto plantea un problema, pues a la hora de crear la columna (mediante DataGridColumn), hay que asignar el argumento como texto de cabecera (propiedad headerText), pero la creación de la misma requiere de un nombre. Al ser dinámico, también ha de tener un nombre único. Esto se podría realizar mediante el siguiente código:

// Extraccion de columnas
var cols:Array = new Array(); // Crear array de columnas
var iCol:int=0;

for each(var element:XML in vxmll[0].elements()) {
  var col:DataGridColumn = new DataGridColumn("c"+iCol);
  col.headerText=element.attribute("nombre");
  cols.push(col);
  iCol++;
}

dgVista2D.columns = cols; // Asignar columnas al DataGrid
dgVista2D.validateNow(); // Validar y refrescar el DataGrid


Como se puede comprobar, hay un contador de columnas (de 0 a n), el cual servirá para asignar el nombre a la columna ("c1", "c2", "c3", etc.)

El problema que viene a continuación es que si se convierte los datos del XML almacenado en vxmll a un ArrayCollection, y asignárselo al DataGrid, no aparecerá ningún dato. ¿El motivo? El nombre de las columnas.

La solución está en crear un ArrayCollection que contenga un objeto por cada fila, que contenga tantas propiedades como columnas tenga, y que dichas propiedades se llamen igual que las columnas. Como todo es dinámico, habrá que crear objetos en tiempo de ejecución (ver anterior post: http://rafinguer.blogspot.com/2010/11/flexair-creacion-de-objetos-en-tiempo.html).

El siguiente código realizará la conversión correcta para que el DataGrid muestre correctamente los datos:

// Procesamiento de los datos
acResult = new ArrayCollection();

// Recorre las filas
for each(var elem:XML in vxmll) {
  // Recorre las columnas
  iCol = 0;
  var o:Object = new Object();

  for each(var subelement:XML in elem.elements()) {
    o["c"+iCol]=subelement.toString();
    iCol++;
  }
  acResult.addItem(o);
}

dgVista2D.dataProvider=acResult;


El código completo para la función srvObtenerVista2DResult() es el siguiente:

private function srvObtenerVista2DResult(event:ResultEvent):void {
  var vxmll:XMLList = new XMLList(event.result.fila);
  
  // Si hay datos
  if (vxmll.length()>0) {
    // Extraccion de columnas
    var cols:Array = new Array(); // Crear array de columnas
    var iCol:int=0;
    
    for each(var element:XML in vxmll[0].elements()) {
      var col:DataGridColumn = new DataGridColumn("c"+iCol);
      col.headerText=element.attribute("nombre");
      cols.push(col);
      iCol++;
    }
    
    dgVista2D.columns = cols; // Asignar columnas al DataGrid
    dgVista2D.validateNow(); // Validar y refrescar el DataGrid
    
    // Procesamiento de los datos
    acResult = new ArrayCollection();
    
    // Recorre las filas
    for each(var elem:XML in vxmll) {
      // Recorre las columnas
      iCol = 0;
      var o:Object = new Object();
      
      for each(var subelement:XML in elem.elements()) {
        o["c"+iCol]=subelement.toString();
        iCol++;
      }
      acResult.addItem(o);
    }
    
    dgVista2D.dataProvider=acResult;
  }
}