Search code examples
htmlgotemplatesgo-templates

How to pass in a map "created on the way" in a go template


I want to make something like a UI component 100% reusable in Go templates but i don't know if it's possible to do it. So I'm trying to do the next:

{{define "components/menu-button"}}
<a href="{{.link}}" class="text-white">{{.content}}</a>
{{end}}

This is my component, it expect a map because of the properties are in lowercase.

And then in my homepage I have this little menu that uses 3 times the components/menu-button component in my navbar:

<div class="hidden gap-4 sm:flex">
    {{template "components/menu-button" {"link": "/contact", "content": "Contact"}}}
    {{template "components/menu-button" {"link": "/docs", "content": "Docs"}}}
    {{template "components/menu-button" {"link": "/download", "content": "Download"}}}
</div>

But I don't know if I can in some way create a map like I'm doing up here in the example, it's like JSON thing but well I tried.

By the way, it gives me the next error:

unexpected "{" in template clause

Solution

  • That kind of syntax is not supported by Go's templates.

    What you can do is declare a custom function, e.g.

    func MakeMap(kvs ...any) map[any]any {
        m := make(map[any]any)
        for i := 0; i < len(kvs)-1; i+=2 {
            m[kvs[i]] = kvs[i+1]
        }
        return m
    }
    

    Then you can make the function available to the templates by using (*Template).Funcs, e.g.

    t.Funcs(template.FuncMap{"M":MakeMap})
    

    Then, inside the template, you can invoke the function using the key M.

    {{template "components/menu-button" (M "link" "/contact" "content" "Contact")}}
    

    https://go.dev/play/p/Sl1ON-z7Mtn