What's unsafe about the code above?
The basic issue I'm trying to solve is that I want to have a general "layout" framework for web pages, in which I have a navbar at the top, a navbar at the side, and content in the mail part. The natural way to do this would be to have a template that looks like this:
{{define "page"}}
{{template "navbarTop" .NavbarTopArgs}}
{{template "navbarLeft" .NavbarLeftArgs}}
{{template .MainContent .MainContentArgs}}
{{end}}
Then you define templates for the different main pages, and call the "page" template at the top saying which of the templates to render.
Looking around, there are basically three alternate solutions to this problem, none of which are very satisfying:
* Solution 1: Multiple parsed templates
In this one, you define your main template like this:
{{define "page"}}
{{template "navbarTop" .NavbarTopArgs}}
{{template "navbarLeft" .NavbarLeftArgs}}
{{template "content" .MainContentArgs}}
{{end}}
Then for each "main content" page, you define a separate file that contains a "content" template.
But this means having a fully separate template variable, and all the template code, for each different view of the webpage. This seems really repetitive an inefficient.
Examples suggesting this:
* Solution 2: Invert the nesting
In this option, you have each "main content" template manually include the navbars, thus:
{{define "MainContentAbout"}}
{{template "navbarTop" .NavbarTopArgs}}
{{template "navbarLeft" .NavbarLeftArgs}}
... content of 'about' page...
{{end}}
This again is repetitive -- each page has to include the navbars, and if I (say) wanted to add a footer, I'd have to manually go and add it to each of my content pages; and I might make a mistake and miss some.
Examples suggesting this:
The problem with both #1 and #2 is that they're violating the Don't Repeat Yourself principle.
* Solution 3: Work around the limitation with functions
In this case, you define a function that will do the work of programmatically nesting templates for you, like this:
{{define "page"}}
{{template "navbarTop" .NavbarTopArgs}}
{{template "navbarLeft" .NavbarLeftArgs}}
{{content .MainContentTemplate .MainContentArgs}}
{{end}}
And then implementing a function that looks like this:
funcs := template.FuncMap{
"content": func(t string, arg interface{}) (template.HTML, error) {
buf := bytes.NewBuffer(nil)
mtmpl, err := template.ParseFiles("templates/study.html.tmpl")
if err == nil {
err = mtmpl.ExecuteTemplate(w, t, arg)
}
return template.HTML(buf.String()), err
},
}
This has the benefit of being able to make our layout fully parameterisable. But it means having this weird structure where we go into a template, go out into go, and go back into a *different* template.
Examples of people recommending this approach:
It seems like it would be much better to simply incorporate #3 into the language itself.