miércoles, 17 de junio de 2015

SlickGrid. Proveedor de datos (y II) - El método getItemMetadata

Artículos anteriores:
Tras haber creado nuestro proveedor de datos en este artículo vamos a ver cómo podemos proporcionar información adicional para particularizar la visualización y el comportamiento de cada elemento. Esta información adicional la proveeremos al grid a través del método getItemMetadata del proveedor de datos.

El método getItemMetadata devolverá un valor null si no es necesaria ninguna particularización sobre el elemento y un objeto con las propiedades a particularizar en caso de que sea necesaria.


Metadatos del elemento

El objeto devuelto por el método getItemMetadata puede definir cuatro propiedades (3 de ellas para establecer propiedades a nivel de línea y una cuarta que será una colección de particularizaciones para las diferentes columnas):

  • cssClasses: define una o más clases CSS a aplicar a la línea completa
  • focusable: establece un valor booleano que indica si la fila puede establecerse como fila activa
  • selectable: establece un valor booleano que indica si la fila o sus celdas pueden ser seleccionables
  • columns: colección de objetos con las propiedades a personalizar en cada columna

Como valor de la propiedad columns se puede establecer un array, en el que el índice de cada elemento coincide con el índice de la columna que define, o un objeto, en el que se establecen propiedades que coinciden con la propiedad id de cada columna.

El objeto de definición de cada columna puede definir hasta cinco propiedades distintas:

  • focusable: establece un valor booleano que indica si la celda puede establecerse como activa
  • selectable: establece un valor booleano que indica si la celda puede ser seleccionada
  • formatter: establece la función de formateo para la celda
  • editor: establece un editor particularizado para la celda
  • colspan: sirve para fusionar celdas y establece el número de celdas que se fusionarán. También se puede establecer un valor "*" para indicar que la celda debe fusionarse con todas las celdas que queden a su derecha.

Definiendo los Metadatos para la línea de totales

Voy a modificar la línea de totales para establecer a nivel de línea un formato diferente a partir de una clase CSS e impedir que la línea pueda ser seleccionada o editada.
El número total de productos voy a cambiarlo por un mensaje del tipo "<número> Productos" y lo cambiaré a la columna ProductNumber estableciéndole un colspan de 2 para que el mensaje pueda utilizar también el espacio de la siguiente celda para visualizarse.
El precio medio lo voy a reemplazar por un mensaje del tipo "Precio medio: <precio>" y lo cambiaré a la columna Color estableciendo a través del colspan que se fusione esta celda con el resto de celdas a la derecha de forma que haya espacio de sobra para mostrar el mensaje completo. También le estableceré como función de formateo Slick.Formatters.CurrencyFormatter para que me añade al final el símbolo de moneda.

Para las líneas que no se corresponden con la de totales la función getItemMetadata devolverá un valor null indicando que deben seguir visualizándose como hasta ahora.

La nueva clase CSS para definir el estilo de las celdas de la línea de totales lo añadiré a la hoja de estilos pildorasgrid.css.

function ProductsDataProvider() {
    var _data = products;
    var _totals = getTotalsRow();

    var _totalsMetadata = {
        cssClasses: "totalsRow",
        focusable: false,
        selectable: false,
        columns: {
            ProductNumber: {editor: null, colspan:2 },
            Color: { editor: null, colspan: "*", formatter: Slick.Formatters.CurrencyFormatter },
        }
    }

    this.getLength = function () {
        return _data.length + 1;
    };

    this.getItem = function (index) {
        if (index == 0)
            return _totals;
        else
            return _data[index - 1];
    }

    this.getItemMetadata = function (index) {
        return (index === 0) ? _totalsMetadata : null;
    }

    this.onCellChange = function (e, args) {
        var grid = args.grid;
        if (grid.getColumns()[args.cell].field == "StandardCost") {
            _totals = getTotalsRow();
            grid.invalidateRow(0);
            grid.render();
        }
    }

    function getTotalsRow() {
        var sumOfPrice = 0;
        for (var item in _data) {
            sumOfPrice += _data[item].StandardCost;
        }
        
        return { ProductNumber: _data.length + " Productos", Color: "Precio medio : " + (sumOfPrice / _data.length).toFixed(2) };
    }
}
.totalsRow{
    color: #dddddd;
    background-color: rgb(204,0,0);
    font-weight: bold;
}

Si volvemos a cargar la página podremos observar el efecto creado.

Línea totales con formato

También podríamos mover la definición de funciones de formateo y editores de la definición de las columnas al proveedor de datos, delegando la definición de estos en el proveedor:

    var _itemsMetadata = {
        columns: {
            ProductID: { editor: Slick.Editors.Numeric },
            ProductNumber: { editor: Slick.Editors.Text },
            Name: { editor: Slick.Editors.Text },
            Color: { formatter: Slick.Formatters.ColorFormatter, editor: Slick.Editors.Color },
            StandardCost: { formatter: Slick.Formatters.CurrencyFormatter, editor: Slick.Editors.Numeric },
            ProductSubcategoryID: { editor: subcategoryEditor },
            SubcategoryName: { formatter: asyncSubcategoryNameFormatter }
        }
    }
 
    this.getItemMetadata = function (index) {
        return (index === 0) ? _totalsMetadata : _itemsMetadata;
    }
 var columns = [
  { name: "ID", field: "ProductID", id: "ProductID", width: 60, resizable: false
   , headerCssClass: "prKeyHeadColumn", cssClass: "numericCell" },
  { name: "Nº Producto", field: "ProductNumber", id: "ProductNumber", width: 120, resizable: false
   , headerCssClass: "headColumn" },
  { name: "Denominación", field: "Name", id: "Name", width: 250, minWidth: 150, maxWidth: 400
   , headerCssClass: "headColumn" },
  { name: "Color", field: "Color", id: "Color", width: 80, minWidth: 60, maxWidth: 120
   , headerCssClass: "headColumn" },
  { name: "Precio", field: "StandardCost", id: "StandardCost", width: 110, minWidth: 80, maxWidth: 170
   , headerCssClass: "headColumn", cssClass: "numericCell" },
  { name: "Sub", field: "ProductSubcategoryID", id: "ProductSubcategoryID", width: 60, resizable: false
   , headerCssClass: "headColumn", cssClass: "numericCell" },
  { name: "Subcategoría", field: "ProductSubcategoryID", id: "SubcategoryName"
   , width: 200, minWidth: 150, maxWidth: 400, headerCssClass: "headColumn"
   , asyncPostRender: getSubcategoryName, cache: {} }
 ];

Por desgracia desde la función getItemMetadata no podemos especificar la clase CSS de las celdas ni la función para la carga asíncrona de datos.
Así que deberemos mantener esta información en la definición de las columnas. Esperemos que en una futura versión se incluyan estas propiedades para poder sobreescribirlas desde el proveedor de datos.

El código


Puedes descargar el código de todos los ejemplos de SlickGrid de:



Artículo siguiente:
SlickGrid. DataView (I) - Introducción y uso

No hay comentarios:

Publicar un comentario