Am trying to generate a HTML content using html/template
in Go
. The data is actually an output of SELECT
query from different MySQL
Tables.
I need help on the below
result := []map[string]interface{}{}
(I use interface since the number of columns and it's type are unknown prior to execution) to present data in a table format ?Note: Currently result
in the playground link contains 2 maps which should be considered as dynamic. It will change depending on the target table.
Here is the playground link which has sample data matching my use case. https://go.dev/play/p/UTL_j1iRyoG
Below is the output HTML which adds all the values as single row which also doesn't match with Columns.
<html>
<head>
<meta charset="UTF-8">
<title>My page</title>
<style>
table, th, td {
border: 1px solid black;
}
th, td {
padding: 10px;
}
</style>
</head>
<body>
<table>
<tr>
<th>Name</th><th>Colour</th>
</tr>
<tr>
<td>Red</td><td>Apple</td><td>Banana</td><td>Yellow</td>
</tr>
</table>
</body>
</html>
You can do the following:
var cols []string
var rows [][]interface{}
for key, _ := range result[0] {
cols = append(cols, key)
}
for _, res := range result {
vals := make([]interface{}, len(cols))
for i, col := range cols {
vals[i] = res[col]
}
rows = append(rows, vals)
}
data := struct {
Title string
Columns []string
Rows [][]interface{}
}{
Title: "My page",
Columns: cols,
Rows: rows,
}
And the HTML will need to be modified accordingly:
<table>
<tr>
{{range .Columns}}<th>{{ . }}</th>{{else}}<div><strong>no rows</strong></div>{{end}}
</tr>
{{- range .Rows}}
<tr>
{{range .}}<td>{{ . }}</td>{{end}}
</tr>
{{- end}}
</table>
https://go.dev/play/p/MPJOMlfQ488
Note that in Go maps are unordered, so looping over result[0]
to aggregate the column names will produce an unordered []string
. This means that the user viewing your HTML page multiple times will see inconsistent output. If that's something you want to avoid, you could either choose to sort the columns using package sort
, or you could opt to retain the order of sql.Rows.Columns
in some way.