2

Question: How can I specify a specific template for a specific method (with different routes), if they are in different folders and named the same?

Descript:

I have two tables in Database, Users and Agency with different fields for example. For each of them I've made router for list objects by SELECT function. Router:

r := mux.NewRouter() // gorilla/mux
r.HandleFunc("/user", handlers.UserList).Methods("GET")
r.HandleFunc("/agency", handlers.AgencyList).Methods("GET")

where handlers is a struct with database pointer and templates,

type Handler struct {
    DB   *sql.DB
    Tmpl *template.Template
}

and it's have a methods for catching responses:

func (h *Handler) AgencyList(w http.ResponseWriter, r *http.Request) {
    Agencys := []*Agency{}
    rows, err := h.DB.Query(`SELECT Id, Name, IsActive FROM Agencys`)
    // etc code for append objects into Agencys and error handling
    err = h.Tmpl.ExecuteTemplate(w, "index.html", struct{ Agencys []*Agency }{Agencys: Agencys})
    // etc code and error handling
}

Same principles in handling Users list function. This handler have also methods for GET (one object) POST and DELETE methods, and for each of them I need specific template for working (for editing etc). So. In this example I have directory templates, where I have two sub-directories "user" and "agency" with files index.html (for listing objects) for each "subject" (user and agency).

templates\
  \agency
   --\edit.html
   --\index.html
   ... etc htmls for agency
  \user
   --\edit.html
   --\index.html
   ... etc htmls for users
  ... etc dirs for other DB-objects

And I'm using this:

func main() {
    handlers := &handler.Handler{
        DB:   db,
        Tmpl: template.Must(template.ParseGlob("templates/*.html")), // for root templates
    }
    // next code is avoid panic: read templates/agency: is a directory
    template.Must(handlers.Tmpl.ParseGlob("templates/user/*.html"))
    template.Must(handlers.Tmpl.ParseGlob("templates/agency/*.html"))
    r := mux.NewRouter()
    r.HandleFunc("/", handlers.Index).Methods("GET") // root
    r.HandleFunc("/user", handlers.UserList).Methods("GET")
    r.HandleFunc("/agency", handlers.AgencyList).Methods("GET")
// etc code with ListenAndServe()
}

After all I catched error in template like

template: index.html:26:12: executing "index.html" at <.Agencys>: can't evaluate field Agencys in type struct { Users []*handler.User } 

when I trying call localhost/user listing in browser (because it's different 'objects' with different fields, of course). Looks like ParseGlob(agency/) redefine tepmlates with same names after ParseGlob(user/)

I'm trying find solution like this:

err = h.Tmpl.ExecuteTemplate(w, "templates/user/index.html", post)

in method UserList() for pointing which template needs.

Maybe that's all is not good solution; maybe will be good, if I shall use prefixes in template's names (like listAgency.html and listUser.html in templates dir) instead of different directories for each object like now. I tried this way, but that looks not so pretty and beauty.

  • 3
    Do you need to have all templates associated? If not, just create and use different `template.Template`s. If yes, use unique names (e.g. rename them to `user-index.html` and `agency-index.html`). – icza Nov 30 '21 at 18:31
  • Yeap. Same thoughts about different names. At the same time, if use different `template.Templates` that's will made something like namespaces in templates and needs storage in `handler` object (again not beauty). And without associations that will not be able to use inheriting, I guess. – Johann Schatten Nov 30 '21 at 19:12
  • Have you seen https://stackoverflow.com/questions/19373586/go-html-template-template-parseglob-and-code-re-use ? – erik258 Nov 30 '21 at 23:20

1 Answers1

1

I'm trying find solution like this:

err = h.Tmpl.ExecuteTemplate(w, "templates/user/index.html", post)

You can wrap each file's contents in a "define action" and name it what you want.

For example, open the file templates\user\index.html and add a this line at the top

{{ define "templates/user/index.html" }}

and this line at the bottom

{{ end }}

and then the following

err = h.Tmpl.ExecuteTemplate(w, "templates/user/index.html", post)

will work.

mkopriva
  • 35,176
  • 4
  • 57
  • 71