Switch or if/elseif/else inside golang HTML templates

HtmlTemplatesGoGo Templates

Html Problem Overview


I have this struct :

const (
	paragraph_hypothesis = 1<<iota
	paragraph_attachment = 1<<iota
	paragraph_menu       = 1<<iota
)

type Paragraph struct {
	Type int // paragraph_hypothesis or paragraph_attachment or paragraph_menu
}

I want to display my paragraphs in a Type dependent way.

The only solution I found was based on dedicated functions like isAttachment testing the Type in Go and nested {{if}} :

{{range .Paragraphs}}
    {{if .IsAttachment}}
    	-- attachement presentation code  --
    {{else}}{{if .IsMenu}}
    	-- menu --
    {{else}}
    	-- default code --
    {{end}}{{end}}
{{end}}

In fact I have more types, which makes it even weirder, cluttering both the Go code with IsSomething functions and the template with those {{end}}.

What's the clean solution ? Is there some switch or if/elseif/else solution in go templates ? Or a completely different way to handle these cases ?

Html Solutions


Solution 1 - Html

Templates are logic-less. They're not supposed to have this kind of logic. The maximum logic you can have is a bunch of if.

In such a case, you're supposed to do it like this:

{{if .IsAttachment}}
    -- attachment presentation code --
{{end}}

{{if .IsMenu}}
    -- menu --
{{end}}

{{if .IsDefault}}
    -- default code --
{{end}}

Solution 2 - Html

Yes, you can use {{else if .IsMenu}}

Solution 3 - Html

You can achieve switch functionality by adding custom functions to the template.FuncMap.

In the example below I've defined a function, printPara (paratype int) string which takes one of your defined paragraph types and changes it's output accordingly.

Please note that, in the actual template, the .Paratype is piped into the printpara function. This is how to pass parameters in templates. Please note that there are restrictions on the number and form of the output parameters for functions added to FuncMaps. This page has some good info, as well as the first link.

package main

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

func main() {

    const (
        paragraph_hypothesis = 1 << iota
        paragraph_attachment = 1 << iota
        paragraph_menu       = 1 << iota
    )

    const text = "{{.Paratype | printpara}}\n" // A simple test template

    type Paragraph struct {
        Paratype int
    }

    var paralist = []*Paragraph{
        &Paragraph{paragraph_hypothesis},
        &Paragraph{paragraph_attachment},
        &Paragraph{paragraph_menu},
    }

    t := template.New("testparagraphs")

    printPara := func(paratype int) string {
        text := ""
        switch paratype {
        case paragraph_hypothesis:
            text = "This is a hypothesis\n"
        case paragraph_attachment:
            text = "This is an attachment\n"
        case paragraph_menu:
            text = "Menu\n1:\n2:\n3:\n\nPick any option:\n"
        }
        return text
    }

    template.Must(t.Funcs(template.FuncMap{"printpara": printPara}).Parse(text))

    for _, p := range paralist {
        err := t.Execute(os.Stdout, p)
        if err != nil {
            fmt.Println("executing template:", err)
        }
    }
}

Produces:

>This is a hypothesis > >This is an attachment > >Menu
>1:
>2:
>3:
> >Pick any option:

Playground link

Hope that helps, I'm pretty sure the code could be cleaned up a bit, but I've tried to stay close to the example code you provided.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDenys S&#233;guretView Question on Stackoverflow
Solution 1 - HtmlFlorian MargaineView Answer on Stackoverflow
Solution 2 - HtmlmcfedrView Answer on Stackoverflow
Solution 3 - HtmlIntermernetView Answer on Stackoverflow