1

I'm building a simple forum in Go for a school project, and I'm passing a data struct to a template to display all the posts in a subforum. The data I'm passing to the template is this:

type Data struct {
   ID    int       // ID of the subforum
   User  User      // logged-in user
   Posts []Post    // all the posts of the subforum
}

The Post struct within the Data struct is like this:

type Post struct {
    ID         int
    Title      string
    Content    string
    Date       time.Time
    [...]
    Author     User
    Comments   []Comment
}

And the Comment struct is similar to the Post struct. When I display the list of all the posts, I would like to also show the number of replies and the date/time of the last reply.

In my HTML template, I can get the number of replies like this:

{{range .Posts}}

    <p>Replies: {{ len .Comments }}</p>

{{ end }}

...but I can't seem to get my head around getting the date of the last element of the Comments array. I know you can get the first element with the index keyword and the value '0', but I can't use (len .Comments -1) inside the template to get the last element as '-' is a forbidden character. I'll probably just make a second function to get my comments sorted by descending order from my SQLite database, but I was wondering if there was a simple way to work with the indexes in Go templates.

Thank you.

2 Answers2

3

There's not a clean way to do this with Go templates, however this is a workaround here. A simpler workaround would be to add the last item to your struct before passing the struct to the templater. What you're doing is moving the complicated logic out of the template (templates weren't designed to do this anyways) and into the Go code.

type Post struct {
    ....
    Comments   []Comment
    LastComment Comment
}

Then in your template, just do

{{ .LastComment }}
Clark McCauley
  • 1,342
  • 5
  • 16
2

You can use a custom function inside your template to get the last element:

fmap := template.FuncMap{
    "lastElem": func(comments []Comment) Comment { 
        return comments[len(comments)-1]
    },
}

tmpl, err := template.New("tmpl").Funcs(fmap).Parse(tpl)

And then use it in your template as:

{{range .Posts}}

    <p>Replies: {{ lastElem .Comments }}</p>

{{ end }}
blackgreen
  • 34,072
  • 23
  • 111
  • 129