Home > Back-end >  Go text/template templates: how to check value against an array of values within the template itself
Go text/template templates: how to check value against an array of values within the template itself

Time:07-22

Let's say you have a JSON value like { "Fruit": "apple" } as your input before applying the template. I want to check that the value of "Fruit" is in a set of []string{"pear", "banana", "grape"} and do something or not do something depending on whether the value is in the set.

So, input to template:

{ "fruit": "apple" }

Template (assume containsVal is a custom function we pass in to the template that accepts a string and a slice of strings):

{{ if containsVal .Fruit []string{"banana", "grape", "etc"} }}do stuff{{ end }}

It seems the templates don't allow string slice literals in them -- template fails to compile.

Apparently you can define a struct and pass that into .Execute(). Or I could hard-code my values in the containsVal function.

But for my purpose, I want the values to be dynamic and in the template, not hard-coded in Go code. So someone else should be able to come along and have a different set of values to check against ("fig", "cherry", etc.) by updating the template text.

I've poked around https://pkg.go.dev/text/template and google and am not seeing any way to do this. I have only been able to do simple equality against simpler variables, like string == string in the templates.

Thanks.

CodePudding user response:

Use a template function map to add the functionality. Here's a map with the function:

var funcs = template.FuncMap{
    // in returns true if needle is in haystack
    "in": func(needle any, haystack ...any) bool {
        for _, v := range haystack {
            if needle == v {
                return true
            }
        }
        return false
    },
}

The function uses a variadic argument to specify the set of strings to match.

Use it in a template like this:

t := template.Must(template.New("").Funcs(funcs).Parse(
     `{{if in . "foo" "bar" -}}YES {{else}}NO {{end}}`))
t.Execute(os.Stdout, "foo")  // prints YES
t.Execute(os.Stdout, "quux") // prints NO

Run the code on the playground.

CodePudding user response:

You should use "if" statement with "or" and "eq" operators like as:

    tmplText := `
    {{ if or (eq .Fruit "banana" "grape" "etc") }}
        {{ .Fruit }} exists in the list
    {{ else }}
        {{ .Fruit }} doesn't exist in the list
    {{ end }}
`

    tmpl, err := template.New("").Parse(tmplText)
    if err != nil {
        panic(err)
    }

    err = tmpl.Execute(os.Stdout, map[string]interface{}{
        "Fruit": "apple",
    })
    if err != nil {
        panic(err)
    }
  • Related