Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing struct variable outside of {{range .}} scope in golang html template

Tags:

html

templates

go

<!DOCTYPE html>
<html>
<head>
    <title> Test </title>
</head>
<body>
    <div>
        <h2>Reply</h2>
        <form action="/post/{{$threadID}}" method="POST">
        <input type="text" name="subject" />
        <input type="text" name="name" value="Anonymous" />
        <input type="text" name="message" />
        <input type="submit" value="submit" />
        </form>
    </div>
    <div>
        {{range .}}
        {{$threadID := .ThreadID}}
        <h3>{{.Subject}}</h3>
        <h3>{{.Name}}</h3>
        <div>{{.DatePosted}}</div>
        <div><p>{{.Text}}</p></div>
        <br /><br />
        {{end}}
    </div>
</body>

I have this template, there is a form at the top of the page that requires the threadID from ANY one of the Posts sent (they're all the same, a slice of all posts with a certain threadID), this obviously doesn't work, my only other idea was something along the lines of

{{range .}}
    {{if $threadID == nil}}
        $threadID := .ThreadID
        //build the form same as above
    {{end}}
    <h3>{{.Subject}}</h3>
    <h3>{{.Name}}</h3>
    <div>{{.DatePosted}}</div>
    <div><p>{{.Text}}</p></div>
    <br /><br />
{{end}}

Here is the Post structure and methods if any of the above is unclear.

type Post struct {
threadID int
subject string
name string
text string
date_posted string
}

func (p *Post) ThreadID()   int    { return p.threadID    }
func (p *Post) Subject()    string { return p.subject     }
func (p *Post) Name()       string { return p.name        }
func (p *Post) Text()       string { return p.text        }
func (p *Post) DatePosted() string { return p.date_posted } 

And the origin of the slice of posts sent to the template

threadID := r.URL.Path[len("/reply/"):]
replies, err := i.db.Query("SELECT * FROM latest_threads where thread_id="+threadID);
like image 243
user3324984 Avatar asked Mar 13 '14 00:03

user3324984


1 Answers

If the Thread Id can only be retrieved from the Post type itself, consider turning your slice of posts into a separate type. Give it a ThreadID method, which simply returns the id for the first post it contains, or zero if none exist.

type PostList []*Post

func (p PostList) ThreadId() int {
    if len(p) == 0 {
        return 0
    }
    return p[0].ThreadId
}

Pass this list into the template. Now you can reference it from the template, anywhere outside of the {{range .}} clause.

<form action="/post/{{.ThreadID}}" method="POST">

Exploit warning

As a side note, Little Bobby Tables has an issue with the SQL query. It's possible you are just posting it as a quick example. If not, be advised that your code is a recipe for SQL injection exploits. If the thread ID is numeric, then ensure you parse it as such, before passing it into the SQL query. E.g.: Sanitize your inputs.

like image 129
jimt Avatar answered Oct 09 '22 09:10

jimt