0

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. :)

Community
  • 1
  • 1
Dheeraj Sarwaiya
  • 163
  • 1
  • 12
  • why negative vote, if you think question is not good, give feedback. This is a road block for me, looking for ideas here. – Dheeraj Sarwaiya Dec 14 '16 at 07:34
  • I guess downvotes come from you showing little research or effort trying to solve the problem. Also your question as it is is too broad, but this is a quite common and handy feature to have for a webapp, so I'll answer it anyway. – icza Dec 14 '16 at 09:39

1 Answers1

8

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

Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827
  • It worked.. Thanks. I didn't know about block and somehow I missed that in your last post as well.. This is great. Thank you very much for your help. – Dheeraj Sarwaiya Dec 14 '16 at 19:00
  • @DheerajSarwaiya Note that `{{block}}` is not a requirement, you can do this wtihout using `{{block}}`. It is simply a shorthand for a `{{define}}` followed by a `{{template}}`. – icza Dec 15 '16 at 07:36
  • Thanks for your help. I am facing one problem with this approach. js doesnt work if I use block or template. I am using js script to display images from URLs receiving from data store. I realized that even simple does not work when you press load more. Any suggestion for this? – Dheeraj Sarwaiya Dec 15 '16 at 16:53
  • 2
    @DheerajSarwaiya Most likely the text you try to insert in the template gets auto-escaped by the `html/template` package. Check out this answer: [Golang Web - HTML Comments are not rendered](http://stackoverflow.com/questions/34348072/golang-web-html-comments-are-not-rendered/34351058#34351058); and this: [avoid auto escape in html template](http://stackoverflow.com/questions/36980049/avoid-auto-escape-in-html-template/36980336#36980336). If those don't help, I suggest to post a new question with more details. – icza Dec 15 '16 at 17:02