Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang: Parse all templates in directory and subdirectories?

Tags:

go

This is my directory structure:

app/
  template/
    layout/
      base.tmpl
    index.tmpl

template.ParseGlob("*/*.tmpl") parses index.tmpl but not base.tmpl in the layout subdirectory. Is there a way to parse all templates recursively?

like image 872
Sunny Avatar asked Jul 31 '16 17:07

Sunny


3 Answers

if it is not deeply nested (if you know names of sub-directories beforehand) you can just do this:

t := template.Must(template.ParseGlob("template/*.tmpl"))
template.Must(t.ParseGlob("template/layout/*.tmpl"))

Then for each sub-directory do the same as for 'layout'

like image 79
pete911 Avatar answered Nov 08 '22 03:11

pete911


Datsik's answer has the drawback that there are name collision issues when several directories contain many templates. If two templates in different directories have the same filename it won't work properly: only the second of them will be usable.

This is caused by the implementation of template.ParseFiles, so we can solve it by avoiding template.ParseFiles. Here's a modified walk algorithm that does this by using template.Parse directly instead.

func findAndParseTemplates(rootDir string, funcMap template.FuncMap) (*template.Template, error) {
    cleanRoot := filepath.Clean(rootDir)
    pfx := len(cleanRoot)+1
    root := template.New("")

    err := filepath.Walk(cleanRoot, func(path string, info os.FileInfo, e1 error) error {
        if !info.IsDir() && strings.HasSuffix(path, ".html") {
            if e1 != nil {
                return e1
            }

            b, e2 := ioutil.ReadFile(path)
            if e2 != nil {
                return e2
            }

            name := path[pfx:]
            t := root.New(name).Funcs(funcMap)
            _, e2 = t.Parse(string(b))
            if e2 != nil {
                return e2
            }
        }

        return nil
    })

    return root, err
}

This will parse all your templates then you can render them by calling their names e.g.

template.ExecuteTemplate(w, "a/home.html", nil)
like image 27
Rick-777 Avatar answered Nov 08 '22 03:11

Rick-777


Not without implementing your own function to do it, I've been using something like this

func ParseTemplates() *template.Template {
    templ := template.New("")
    err := filepath.Walk("./views", func(path string, info os.FileInfo, err error) error {
        if strings.Contains(path, ".html") {
            _, err = templ.ParseFiles(path)
            if err != nil {
                log.Println(err)
            }
        }

        return err
    })

    if err != nil {
        panic(err)
    }

    return templ
}

This will parse all your templates then you can render them by calling their names e.g.

template.ExecuteTemplate(w, "home", nil)

like image 35
Datsik Avatar answered Nov 08 '22 02:11

Datsik