Referencing map values in text/template

Hi,

I’m working my way through Todd McLeod’s excellent “Web development with Go” course from Udemy. It’s great.

One question I have though about working with templates is that I cannot find any way to reference members of a [string]string map in my template.

I can see examples of how to reference slice member using a syntax like:

{{ index .words 1 }}
Which would return index one in the ‘words’ slice. Thats fine and dandy…

However given that we can only pass a single piece of data into any one template, it seemed to me that the ideal type to accomplish my goal would be a map which contained all the stuff I need to render. Have not been able to find anything to suggest that won’t work.

Can anyone tell me, or point me toward where I can find out how to reference the map values in the template? I know that the map data is being injected into {{.}} because when I just print out the {{.}} I see:

<h5>(c) 2017 Klaatu Barada Nikto</h5>
    map[start_time:05.09.1968 02:00:00 end_time:10.08.2017 09:00:00]
<br>

Currently the two members of my map are indeed “start_time” and “end_time”. I’m just getting started though… the map will eventually contain maybe a hundred values.

Would appreciate any assistance,
Thanks.

As per usual 5 mins after asking the question after struggling for an hour … the answer comes and as per usual the answer is typically simple and elegant.

This works:

 <h5>(c) 2017 Klaatu Barada Nikto</h5>
    {{ index . "start_time" }}
    {{ index . "end_time" }}

Thanks

Why not pass in a struct?

type Foo struct {
  startTime time.Date
  endTime   time.Date
}

Passing this into the template should make the fields available as {{ .startTime }} and {{ .endTime }} respectively.

But if you really want to use a map (which I do not suggest), you should be able to use index as you do with arrays/slices

1 Like

Everything works as expected using the . notation:

package main

import (
	"html/template"
	"log"
	"os"
)

func main() {
	tpl := `foo={{.foo}}
bar={{.bar}}
baz={{.baz}}
`

	m := make(map[string]interface{})
	m["foo"] = 1
	m["bar"] = "BAR"
	m["baz"] = true

	tmpl, err := template.New("test").Parse(tpl)
	if err != nil {
		log.Fatal(err)
	}

	err = tmpl.Execute(os.Stdout, m)
	if err != nil {
		log.Fatal(err)
	}
}

produces

foo=1
bar=BAR
baz=true

see https://play.golang.org/p/BVFlucf6wh

1 Like

@NobbZ

Thank you. Yes, I had considered a struct as possibly it will be easier (once I understand it) and more flexible for future growth.

Context
I’m trying to put together an html report of reasonable complexity. The Go code will have to collect in the order of a hundred or so different pieces of data from diverse sources such as databases and REST services. Each response will be subject to further processing in Go to isolate the specific value needed for inclusion in the report. I thought it would be easier, for now, to simply isolate the value as a string and then pop it onto the map with a memorable name for reference in the template. Based on early experimentation, this seems to work extremely well (once I got my immense density over how to actually reference the map key in the template).

Using a struct would, I think ( correct me here, please), require me to ‘type’ the response/value as the struct type and as long as the struct fields are capitalised, they would be exported - right? That would effectively add the value to the field name which matched? A bit like Json marshal/unmarshal - yes?

I probably need to experiment more with casting my required values to the struct and getting more used to working with that model before committing.

Would appreciate any thoughts/advice. Thanks!

Hi @lutzhorn
Thank you very much - yes, I think I figured out how to reference individual map keys (eventually!).

Appreciate the response.

What if the key has spaces eg (foo bar)?

Then you can still use {{ index .theMap "foo bar" }}.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.