Creating load more button in Golang with templates

前端 未结 1 471
甜味超标
甜味超标 2020-12-06 15:54

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 pag

1条回答
  •  南方客
    南方客 (楼主)
    2020-12-06 16:25

    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:

    Posts

    {{block "batch" .}} {{range .posts}}
    {{.Time}} {{.User}}: {{.Text}}
    {{end}}
    {{end}}

    It contains a {{block "batch" .}} block for listing posts, and also renders a placeholder for the next batch (

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

    0 讨论(0)
提交回复
热议问题