I’ve been exploring options for dynamic rendering in Hugo.
It took a bit to stumble upon how to render an enumerable (e.g. an Array or Hash) as valid Javascript Object Notation (JSON 📖). The primary problem is how to handle the commas AND apply any transformations on the Array/Slice or Hash/Dictionary.
In Hugo, if I have a Slice {{- $slice := slice("title" "created_at" "author") }}
,
I can use the delimit
function to render that slice. For example
{{ delimit $slice "; " }}
would render title; created_at; author
. However I
need to do something different if I want to use the $slice
as a key to lookup
data and render that data according to its attributes.
Original JSON Document
Lets say I have a JSON document:
{
"title": {
"type": "html",
"label": "Title",
"value": "<h1>Hugo Demo<h1><h2>Creative Approaches to Iteration</h2>"
},
"author": {
"type": "text",
"label": "Author",
"value": "Jeremy Friesen"
},
"created_at": {
"type": "date",
"label": "Date",
"value": "2020-05-01"
}
}
Notice the trailing comma at the end of the “title” and “author” line. There is no comma at the end of the “created_at” line.
Transformed JSON Document
I want to transform the original JSON into the following Transformed JSON:
{
"Title": "\u003ch1\u003Hugo Demo\u003c/h1\u003\u003ch2\u003Creative Approaches to Iteration\u003c/h2\u003",
"Author": "Jeremy Friesen",
"Date": "May 1, 2020"
}
In the transformed JSON, I’ve taken the original JSON document, and transformed it. The title attribute is JSON encoded HTML. I’ve chosen to render the date attribute in a “natural language format”.
Let’s walk through the steps. I added a ./data/attributes.json
document. This
conforms to Hugo’s Data Templates.
Partials
I then wrote three partials, all in the ./layouts/partials/default
directory.
Note: these partials map to the type
attribute in the original JSON. The
.label
and .value
references in the below templates are form the attributes
of the original JSON.
date.json
"{{ .label }}": "{{ dateFormat "Jan 2, 2006" .value }}"
Note, I’m using Hugo’s dateFormat function to transform from an ISO8601 format into a “human readable” format. Normally, I would never transport JSON with a date in this “human readable” format, but this is part of the exercise.
html.json
"{{ .label }}": {{ .value | jsonify }}
The jsonify
ensures that we have a compliant JSON element. It also renders the
enclosing paranthesis.
text.json
"{{ .label }}": {{ .value | jsonify }}
Again, using jsonify
to ensure we have compliant JSON.
Stitching it All Together
I then use the following Hugo template to render the JSON.
{{/* Here we need to gather all the keys for the attributes. We need just the
keys, as they are strings, and can later be compared when we call the
`complement` function. In hugo, we cannot run the `compliment` on a
map/dict object
*/}}
{{- $keys := slice }}
{{- range $key, $data := .Site.Data.attributes }}
{{- $keys = $keys | append $key }}
{{- end }}
{{- $last_key := $keys | last 1 }}
{{/* NOTE: The next line is the open bracket for the resulting JSON document */}}
{
{{- range $key := ($keys | complement $last_key) }}
{{- $predicate := index $.Site.Data.attributes $key }}
{{- $partialName := (printf "default/%s.json" $predicate.type )}}
{{ partial $partialName $predicate }},
{{- end }}
{{/* NOTE: The above range and below range are almost exact copies. However,
in the above, after we render the partial, we add a comma. In the below
range, we do not add a comma after we render the partial */}}
{{- range $key := $last_key }}
{{- $predicate := index $.Site.Data.attributes $key }}
{{- $partialName := (printf "default/%s.json" $predicate.type )}}
{{ partial $partialName $predicate }}
{{- end }}
{{/* NOTE: The next line is the close bracket for the resulting JSON document */}}
}
Conclusion
With the above Hugo template and partials, I transformed the original JSON document into a new JSON document.
I hope this provides some insight in how you might use dynamic data, render dispatching strategies, and some set logic to transform the dynamic data.
If you’d like a working example, please take a look at github.com/jeremyf/hugo-dynamic-data