I want to create a Facebook-like page where in if user scroll down the page fetch old post without refreshing. I have done this earlier using Ajax and appending the HTML page using JS.
However, since I am now using Go and its template to build the page, I am not sure how to achieve the similar results. Kindly help me with your suggestion.
{{range .posts}}
<<in side the range brackets, I am showing the posts >>
{{end}}
out side range I have created load more button which calls
the js which internally fetch the posts slice.
The link below shows one solution but it will not work for high volume data, creating all those buttons in js will be difficult.
Dynamically refresh a part of the template when a variable is updated golang
Thanks for help. :)
My other answer you linked in your question contains all the details and tricks you need to implement the "Load more..." functionality: Dynamically refresh a part of the template when a variable is updated golang
Yes, it's not trivial, but it's not that hard / complex either. That answer discusses different ways / alternatives, but obviously a solution only needs one.
Here I show a working solution. The Load more button here will not "remember" what were the last posts returned, it will just retrieve 2 new posts. Think about how you could implement sending back the last ID, and when more is requested, send records following that.
The complete, runnable application code can be found here on the Go Playground. Of course you can't run it on the Go Playground, save it locally and run it on your computer.
So, we'll work with the following Post
entities:
type Post struct {
User, Time, Text string
}
I'm gonna use the following template:
<html><body><h2>Posts</h2>
{{block "batch" .}}
{{range .posts}}
<div><b>{{.Time}} {{.User}}:</b> {{.Text}}</div>
{{end}}
<div id="nextBatch"></div>
{{end}}
<button onclick="loadMore()">Load more</button>
<script>
function loadMore() {
var e = document.getElementById("nextBatch");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
e.outerHTML = xhr.responseText;
}
}
xhr.open("GET", "/posts/more", true);
try { xhr.send(); } catch (err) { /* handle error */ }
}
</script>
</body></html>
It contains a {{block "batch" .}}
block for listing posts, and also renders a placeholder for the next batch (<div id="nextBatch">
). Next it contains a Load More button, which when pressed, fetches the next batch in a rendered form, and replaces the placeholder. The rendered next batch also contains the placeholder for the next batch.
The javascript function for making an AJAX call is detailed in my linked another answer.
The handler that executes this template:
var t = template.Must(template.New("").Parse(page))
var lastTime = time.Now()
func produceTime() string {
lastTime = lastTime.Add(time.Second)
return lastTime.Format("15:04:05")
}
func postsHandler(w http.ResponseWriter, r *http.Request) {
// Put up some random data for demonstration:
data := map[string]interface{}{"posts": []Post{
{User: "Bob", Time: produceTime(), Text: "The weather is nice."},
{User: "Alice", Time: produceTime(), Text: "It's raining."},
}}
var err error
switch r.URL.Path {
case "/posts/":
err = t.Execute(w, data)
case "/posts/more":
err = t.ExecuteTemplate(w, "batch", data)
}
if err != nil {
log.Printf("Template execution error: %v", err)
}
}
produceTime()
just produces monotonic increasing timestamp strings, so the output will look like something sensible.
And the main()
function to register the handler and start the server:
func main() {
http.HandleFunc("/posts/", postsHandler)
panic(http.ListenAndServe(":8080", nil))
}
And that's about it. It's a working application. Entering http://localhost:8080/posts/
in a browser, you'll see:
Posts
09:42:29 Bob: The weather is nice.
09:42:30 Alice: It's raining.
Load more
Pressing the Load more button, the content in the browser will be refreshed dynamically, without page reload. The new content:
Posts
09:42:29 Bob: The weather is nice.
09:42:30 Alice: It's raining.
09:42:31 Bob: The weather is nice.
09:42:32 Alice: It's raining.
Load more
Pressing it again:
Posts
09:42:29 Bob: The weather is nice.
09:42:30 Alice: It's raining.
09:42:31 Bob: The weather is nice.
09:42:32 Alice: It's raining.
09:42:33 Bob: The weather is nice.
09:42:34 Alice: It's raining.
Load more