Michael J. Lee
Michael J. Lee

Reputation: 12416

Is there a way to render a Map as an HTML table in Grails?

I was wondering if there was a nice way to render a Map to an HTML table within a .gsp page.

An example Map:

def map = ['Mammals':['Unicorn','Chimpanzee','Goat'],
                   'Reptiles':['Snake','Turtle']];

This would render to something like this:

<table>
  <thead>
    <tr>
      <th>Mammals</th>
      <th>Reptiles</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Unicorn</td>
      <td>Snake</td>
    </tr>
    <tr>
      <td>Chimpanzee</td>
      <td>Turtle</td>
    </tr>
   <tr>
      <td>Goat</td>
      <td></td>
    </tr>
  </tbody>
</table>

Ideally I could then create my own custom tag, so I could do this:

<stackOverflow:tablizer map="${map}" />

Upvotes: 2

Views: 790

Answers (2)

Scott Langeberg
Scott Langeberg

Reputation: 199

I can't comment on @James Kleeh's answer, but I modified his code to print a list of Maps, such as what you get back from Groovy Sql results:

protected String mapToTable(List<Map> list) {

    StringBuilder output = new StringBuilder()

    Map first = list.first()

    output.append("<table><thead><tr>")

    first.each { key, val ->
        output.append("<th>${key}</th>")
    }

    output.append("</tr></thead><tbody>")

    list.each { map ->
        if (map.size() > 0) {

            def values = map.values()

            output.append("<tr>")

            values.each {
                output.append "<td>${it}</td>"
            }

            output.append("</tr>")
        }
    }
    output.append("</tbody></table>")

    output.toString()
}

Upvotes: 0

James Kleeh
James Kleeh

Reputation: 12238

Something like this - Probably a better way to do it, but this was what I came up with first.

def mapToTable = { attrs ->

StringBuilder output = new StringBuilder()

if ( attrs.map instanceof Map )
{ 
    Map map = attrs.map

    if ( map.size() > 0 )
    {
        output.append("<table><thead><tr>")

        ArrayList[] values = map.values()

        int max = values.collect{it.size()}.max()


        map.each { key, val ->
            output.append("<th>${key}</th>")
        }

        output.append("</tr></thead><tbody>")

        (1..max).each { num ->
            output.append("<tr>")

            values.each {

                if ( it.size() >= num  )
                {
                    output.append("<td>${it.get(num-1)}</td>")    
                }
                else
                {
                    output.append("<td></td>")   
                }
            }    

            output.append("</tr>")
        }

        output.append("</tbody></table>")
    }

}
out << output
}

Upvotes: 3

Related Questions