-1

I'm trying to create a progress bar that updates based on the progress of a command line argument that is execute in my Go code. Using a template, I am trying to update the progress value once every second by running the template.Execute(w, data) command. I'm doing this within a for loop but rather than updating the value in the html via the template, it is appending another instance on my html body onto the existing page. So I end up with numerous progress values all showing on the page.

I've tried separating the progress value into its own template and then using template.ExecuteTemplate(w, "templateName", data) to update only that specific data, but then no changes are seen. I've read the below post and tried to follow the steps outlined there but I could not fully understand what was being said and how to implement it. (Dynamically refresh a part of the template when a variable is updated golang)

HTML Code(loadingPage.html)

<!DOCTYPE html>
    <head>
        <title>Image Creation & Download</title>
        <!--Bootstrap CSS and JS-->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">     
    </head>
    <body>
        <div class="container">
                <h1>Download Page</h1>
                <div>
                    <form action="/createProgress" method="post">
                        <div class="form-group">
                            <label for="inFile">Input File</label>
                            <div>
                                <input type="text" id="inFile" name="inFile" value="placeholder">
                            </div>
                        </div>
                        <div>
                            <button type="submit" class="btn btn-secondary" id="submitBtn">Load</button>
                        </div>
                        <div>
                            <h4>{{ .PercComp }} Completed</h4>
                            <div class="spinner-border text-primary"></div>
                        </div>
                    </form>              
                </div>
            </div>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
            <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
            <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>          
    </body>
</html>

Go Code (main.go) package main

import (
    "log"
    "net/http"
    "os"
    "strconv"
    "text/template"
    "time"
)

type FileData struct {
    PercComp string
}

var t *template.Template
var fd FileData

func createScreen(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(200)
    t.Execute(w, fd)
    return
}

func progressUpdate(w http.ResponseWriter, r *http.Request) {
    perc := 0
    for i := 0; i < 10; i++ {
        perc = perc + 10
        fd.PercComp = strconv.Itoa(perc) + "%"
        t.Execute(w, fd)
        time.Sleep(time.Second)
    }
    return
}

func main() {
    var err error
    t, err = template.ParseFiles("loadingPage.html")

    if err != nil {
        log.Println("Cannot parse templates:", err)
        os.Exit(-1)
    }
    fd = FileData{
        "0%",
    }

    http.HandleFunc("/", createScreen)
    http.HandleFunc("/createProgress", progressUpdate)

    http.ListenAndServe(":8080", nil)
}

After loading the page and pressing the "Submit" button, the HTML body is show 10 times. The below code is a condensed snapshot of what is showing after running the progressUpdate() function in the Go code.

<head>
        <title>Image Creation &amp; Download</title>
        <!--Bootstrap CSS and JS-->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">     
    </head>
    <body>
        <div class="container">
                <h1>Download Page</h1>
                <div>
                    <form action="/createProgress" method="post">
                        <div class="form-group">
                            <label for="inFile">Input File</label>
                            <div>
                                <input id="inFile" name="inFile" value="placeholder" type="text">
                            </div>
                        </div>
                        <div>
                            <button type="submit" class="btn btn-secondary" id="submitBtn">Load</button>
                        </div>
                        <div>
                            <h4>10% Completed</h4>
                            <div class="spinner-border text-primary"></div>
                        </div>
                    </form>              
                </div>
            </div>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
            <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
            <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>          



        <title>Image Creation &amp; Download</title>
        <!--Bootstrap CSS and JS-->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">     


        <div class="container">
                <h1>Download Page</h1>
                <div>
                    <form action="/createProgress" method="post">
                        <div class="form-group">
                            <label for="inFile">Input File</label>
                            <div>
                                <input id="inFile" name="inFile" value="placeholder" type="text">
                            </div>
                        </div>
                        <div>
                            <button type="submit" class="btn btn-secondary" id="submitBtn">Load</button>
                        </div>
                        <div>
                            <h4>20% Completed</h4>
                            <div class="spinner-border text-primary"></div>
                        </div>
                    </form>              
                </div>
            </div>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
            <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
            <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>          



        <title>Image Creation &amp; Download</title>
        <!--Bootstrap CSS and JS-->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">     


        <div class="container">
                <h1>Download Page</h1>
                <div>
                    <form action="/createProgress" method="post">
                        <div class="form-group">
                            <label for="inFile">Input File</label>
                            <div>
                                <input id="inFile" name="inFile" value="placeholder" type="text">
                            </div>
                        </div>
                        <div>
                            <button type="submit" class="btn btn-secondary" id="submitBtn">Load</button>
                        </div>
                        <div>
                            <h4>30% Completed</h4>
                            <div class="spinner-border text-primary"></div>
                        </div>
                    </form>              
                </div>
            </div>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
            <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
            <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>          
    ...
    ...
    ... 
</body>

Thank you in advance for all help and wisdom!

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
abeiler
  • 3
  • 2
  • 2
    "...it is appending another instance on my html body onto the existing page" -- Yes, of course that's what it's doing, because that's how HTTP works. You can't just re-write some part of the document from the server. What you're trying to do is simply impossible. This is a clear [XY Problem](http://xyproblem.info/). – Jonathan Hall Oct 03 '19 at 15:01
  • The correct approach to updating status on a web page is with client-side logic written in JavaScript. – Jonathan Hall Oct 03 '19 at 15:01

1 Answers1

1

You cannot do this using templates and server-side processing. That said, there are multiple ways you can do this:

You can use Javascript on the client side, iteratively querying the backend server to find out about the progress, and redraw the progress bar based on that. There are probably JS/Ajax libraries or code samples out there to do this.

You can use Javascript to periodically refresh the page, each time returning an HTML page generated from your template with the correct progress display.

Burak Serdar
  • 46,455
  • 3
  • 40
  • 59
  • Thank You! I was able to use AJAX to pass the data from my Go function to a JS function and then use JS to update a progress bar. – abeiler Oct 03 '19 at 17:21