Search code examples
gogo-templates

Custom function is not working in template


I've the below that is working fine playground

package main

import (
    "html/template"
    "os"
)

func main() {
    tmpl := `
{{ $slice := mkSlice "a" 5 "b" }}
{{ range $slice }}
     {{ . }}
{{ end }}
`
    funcMap := map[string]interface{}{"mkSlice": mkSlice}
    t := template.New("").Funcs(template.FuncMap(funcMap))
    template.Must(t.Parse(tmpl))
    t.Execute(os.Stdout, nil)
}

func mkSlice(args ...interface{}) []interface{} {
    return args
}

But once I tried to run in from template file, nothing had been displayed, and no error had been recieved!

func mkSlice(args ...interface{}) []interface{} { // to ceate the array in the template
    return args
}

funcMap := map[string]interface{}{"mkSlice": mkSlice}
tmpl := template.New("").Funcs(template.FuncMap(funcMap))
template.Must(tmpl.ParseFiles("index.html"))
tmpl.Execute(w, nil)

And index.html is:

{{ $slice := mkSlice "a" 5 "b" }}
{{ range $slice }}
    <span> {{ . }} </span>
{{ end }}

any thought?


Solution

  • You don't see any errors because you don't check the error returned by tmpl.Execute(w, nil). When do check it:

    if err := t.Execute(os.Stdout, nil); err != nil {
        panic(err)
    }
    

    You'll see an output like:

    panic: template: "" is an incomplete or empty template
    

    The difference is that in the first case you used Template.Parse() method which:

    ... parses text as a template body for t.

    Note that the template text you parse will be used for t itself!

    In the second case you used Template.ParseFiles() which:

    ... parses the named files and associates the resulting templates with t. If an error occurs, parsing stops and the returned template is nil; otherwise it is t. There must be at least one file. Since the templates created by ParseFiles are named by the base names of the argument files, t should usually have the name of one of the (base) names of the files.

    So in your first example t contains a single template, and that single template will be executed by Template.Execute().

    In your second example t contains multiple associated templates, t itself being an empty template, and another, associated template named index.html. You may execute that template using Template.ExecuteTemplate():

    if err := t.ExecuteTemplate(os.Stdout, "index.html", nil); err != nil {
        panic(err)
    }
    

    For more information, see:

    Go template name

    The Go Template ParseFiles func parsing multiple files