1

I can't figure out how to pass the data that I get from the MySQL database to my HTML template and display every column in a table.

The Instructions I found work fine, however when i try to implement it into my own code it won't pass the data to my HTML and the table remains empty.

Go code:


var table = NewView("bootstrap", "views/pages/table.gohtml")

func main() {
    http.Handle("/views/", http.StripPrefix("/views/", http.FileServer(http.Dir("./views"))))
    http.HandleFunc("/table", tableHandler)
    fmt.Println("server running on port :8080")
    http.ListenAndServe(":8080", nil)
}
func tableHandler(w http.ResponseWriter, r *http.Request) {
    db := ipSQL.SqlConnect()

    data := ipSQL.SqlSelect(db)
    // This returns a nested struct and stores it in the 'data' variable.
    /*
        type Data struct {
        Items []Devicevalue_view
        }

        type Devicevalue_view struct {
            Name        string
            Ip          string
            Pcn         string
            Description string
        }
    */

    fmt.Println(data)
    //The println prints the following: 'test1: {[{Name1 192.168.166.13 123456 webserver} {Name2 192.168.166.14 123456 webserver2}]}'

    err := table.Render(w, data)
    //This renders the page together with a default layout. table is initialized somewhere else in this way:
    // var table = NewView("bootstrap", "views/pages/table.gohtml") --> This is a function I found and confirmed to be working.
    if err != nil {
        panic(err)
    }
}

I've been using the following code to render a standard layout for my webpage from a different file called bootstrap.gohtml and get the body of the HTML from the file I specify. (Added this in ---UPDATE 2)



func NewView(layout string, files ...string) *View {
    files = append(layoutFiles(), files...)
    t, err := template.ParseFiles(files...)
    if err != nil {
        panic(err)
    }

    return &View{
        Template: t,
        Layout:   layout,
    }
}

type View struct {
    Template *template.Template
    Layout   string
}

func (v *View) Render(w http.ResponseWriter, data interface{}) error {
    spew.Dump(data)
    return v.Template.ExecuteTemplate(w, v.Layout, data)
}

func layoutFiles() []string {
    files, err := filepath.Glob(LayoutDir + "/*.gohtml")
    if err != nil {
        panic(err)
    }
    return files
}


The HTLM template looks like this, note that table.Render uses bootstrap.gohtml in which i call on the 'yield' template which I define in table.gohtml.

{{define "yield"}}
<!DOCTYPE html>
<html lang="en">
    <body>
        <table >
            <tr>
                <th>name</th>
                <th>ip</th>
                <th>pcn</th>
                <th>description</th>
            </tr>
            {{ range .Items}}
            <tr>
                <td>{{ .Name }}</td>
                <td>{{ .Ip }}</td>
                <td>{{ .Pcn }}</td>
                <td>{{ .Description }}</td>
            </tr>
            {{ end}}
        <tr>
            <td>END</td>
        </tr>
    </table>
</body>
</html>
{{end}}

The bootstrap.gohtml looks something like this:

{{define "bootstrap"
   <head>some links to css among other things</head>
   <nav>a navigation bar</nav>
   {{template "yield"}}
   <foot>footer</foot>
{{end}}

I compared my code to a working example and the data needed for the table seems to be correct leaving me to believe the issue lies in getting the variables into the HTML table.

I've tried many other variable names in my html file but it won't add them to the table, the column names work fine just not the contents.

The result I expect is a table with multiple rows that has the data that I've currently stored in the 'data' variable.

---UPDATE 1 I've replaced '{{ range .}}' with '{{ range .Items}}' but it still wont show the data in the table.

---UPDATE 2 Added more of my code to the post.

---UPDATE 3 I've added spew.Dump(data) to the render() function, the output is the following:

server running on port :8080
{[{Name1 192.168.166.13 123456 Webserver1} {Name2 192.168.166.14 123456 Webserver2}]}
(ipSQL.Data) {
 Items: ([]ipSQL.Devicevalue_view) (len=2 cap=2) {
  (ipSQL.Devicevalue_view) {
   Name: (string) (len=5) "Name1",
   Ip: (string) (len=14) "192.168.166.13",
   Pcn: (string) (len=6) "123456",
   Description: (string) (len=10) "Webserver1"
  },
  (ipSQL.Devicevalue_view) {
   Name: (string) (len=5) "Name2",
   Ip: (string) (len=14) "192.168.166.14",
   Pcn: (string) (len=6) "123456",
   Description: (string) (len=10) "Webserver2"
  }
 }
}
BumbleB-NL
  • 61
  • 6
  • 1
    I think your range should be `{{ range .Items }}`, currently you are iterating over nothing. Take a look here for more info about the Go template package: https://medium.com/@IndianGuru/understanding-go-s-template-package-c5307758fab0 – Thijs van der Heijden Apr 13 '22 at 17:45
  • Hey, thanks for your comment! I changed my code as you suggested but the problem still persists. – BumbleB-NL Apr 13 '22 at 18:46
  • 2
    Could you share the code that is in table.Render, I just copied the code you provided and applied the template and it worked fine: https://pastebin.com/ube3hPcK – Thijs van der Heijden Apr 13 '22 at 18:54
  • I added it the code that table.Render uses/contains. – BumbleB-NL Apr 13 '22 at 21:00
  • 1
    Can you [spew.Dump](https://github.com/davecgh/go-spew) the data itself you're passing into the `Render` function, and share the output here? Add `spew.Dump(data)` to the `Render` function – Shay Nehmad Apr 14 '22 at 06:17
  • I did as you suggested and added the output to my post. – BumbleB-NL Apr 14 '22 at 07:22

1 Answers1

0

I got it working by changing {{template "yield"}} to {{template "yield" .}}. From what I understand of it this will used the pipeline to parse the variables to the next template file.

{{define "bootstrap"
   <head>some links to css among other things</head>
   <nav>a navigation bar</nav>
   {{template "yield" .}}
   <foot>footer</foot>
{{end}}

The yield template now has access to the variables I parsed to the bootstrap template.

BumbleB-NL
  • 61
  • 6