Tablas rápidas para Grails


Si hay algo odioso cuando hay que hacer una interfaz de administración, es armar la lista para cada modelo del dominio para los AMBs. Esta semana me tocó mejorar el diseño para una aplicación grails, por lo que decidí ver como se podían generar “helpers” o TagLibs en nomenclatura grails.

El siguiente código genera usando bootstrap3 una tabla con paginado, botón de editar y eliminar de forma genérica:

package test
 
class ResourceTableTagLib {
    /**
     * Creates a bootstrap3 compatible datatable.<br/>
     *
     * @emptyTag
     *
     * @attr list REQUIRED List of domain models to show
     * @attr count REQUIRED Total registers (for pagination)
     * @attr labels REQUIRED Comma-separated values for the columns headers
     * @attr columns REQUIRED Comma-separated of model attributes to show
     */
    def table_for = { attrs ->
        def writer = out
        def list = attrs.list
        def count = attrs.count
        def labels = attrs.labels.split(/,/).collect { x -> x.trim() }
        def columns = attrs.columns.split(/,/).collect { x -> x.trim() }
 
        writer << '<div class="dataTable_wrapper">'
        writer << '<table class="table table-striped table-bordered table-hover" id="dataTables-example">'
        writer << '<thead>'
        writer << '<tr>'
        labels.eachWithIndex { a, i ->
            writer << "<th>${a}</th>"
        }
        writer << '<th></th>'
        writer << '</tr>'
        writer << '</thead>'
        writer << '<tbody>'
        list.eachWithIndex { a, i ->
            writer << "  <tr class=\"${(i % 2) == 0 ? 'even' : 'odd'}\">"
            writer << "  <td>"
            writer << g.link(action: "show", id: a.id, a."${columns[0]}")
            writer << "  </td>"
            columns.eachWithIndex { c, j ->
                if (j != 0) {
                    writer << "<td>${a."${columns[j]}"}</td>"
                }
            }
            writer << '  <td>'
            writer << g.form(url: [resource:a, action:'delete'], method: "DELETE") {
                writer << g.link(class: "btn btn-default btn-sm", action: "edit", resource: a, "Editar")
                writer << "&nbsp;"
                writer << g.actionSubmit(class: "btn btn-danger btn-sm", action: "delete", value: "Eliminar", onclick: "return confirm('¿Eliminar curso?');")
            }
            writer << '  </td>'
            writer << '</tr>'
        }
        writer << '</tbody>'
        writer << '</table>'
        writer << '<div class="row">'
        writer << '<div class="col-sm-6">'
 
        def offset = params.offset as Integer ?: 0
 
        def page_start = offset + 1
        def page_end = Math.min(offset+10, count)
 
        writer << "<div aria-live=\"polite\" role=\"status\" class=\"dataTables_info\">Mostrando ${page_start} a ${page_end} de ${pluralize(count: count, singular: "registro")}</div>"
        writer << '</div>'
        writer << '<div class="col-sm-6 dataTables_paginate">'
        writer << g.paginate(total: count)
        writer << '</div>'
        writer << '</div>'
        writer << '</div>'
    }
 
    def pluralize = { attrs, body ->
        def plural = attrs['plural'] ?: attrs['singular'] + "s"
        out << attrs['count'] + " " + ( attrs['count'] > 1 ? plural : attrs['singular'] )
    }
}

PD : Seguramente exista forma de sacar el nombre de columna desde el nombre del atributo del modelo, pero todavía no lo encontré.

Para usarlo simplemente basta con agregar en nuestro template :

<div class="row">
    <div class="col-lg-12">
        <g:table_for list="${list}" count="${employeeInstanceCount}" labels="Legajo,Nombre,Apellido" columns="fileNumber,firstName,lastName" />
    </div>
 
    <!-- /.col-lg-12 -->
</div>

Leave a Reply