Using table in template

In my GO code, I can Post form data to the server as below:

  1. Create struct to represent the form data
  2. Marshal the data into JSON
  3. Post JSON data to the server
  4. Get server response
  5. Convert the server response body into bytes ioutil.ReadAll(resp.Body)
  6. Unmarshal server response body (if in JSON)
  7. Handle the response
// go build -ldflags "-H=windowsgui"
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"text/template"
)

// ContactDetails ...
type ContactDetails struct {
	Email   string
	Subject string
	Message string
}

// ReturnedResult ...
type ReturnedResult struct {
	Result  bool   `json:"result"`
	Message string `json:"message"`
}

func index(w http.ResponseWriter, r *http.Request) {
	tmpl := template.Must(template.ParseFiles("forms.html"))
	if r.Method != http.MethodPost {
		tmpl.Execute(w, nil)
		return
	}

	details := ContactDetails{
		Email:   r.FormValue("email"),
		Subject: r.FormValue("subject"),
		Message: r.FormValue("message"),
	}

	// do something with details
	sheetID := "AKfycbxfMucXOzX15tfU4errRSAa9IzuTRbHzvUdRxzzeYnNA8Ynz8LJuBuaMA/exec"
	url := "https://script.google.com/macros/s/" + sheetID + "/exec"
	bytesRepresentation, err := json.Marshal(details)
	if err != nil {
		log.Fatalln(err)
	}
	resp, err := http.Post(url, "application/json", bytes.NewBuffer(bytesRepresentation))
	if err != nil {
		log.Fatalln(err)
	}
	// read all response body
	data, _ := ioutil.ReadAll(resp.Body)

	// close response body
	resp.Body.Close()

	webReturn := ReturnedResult{}
	if err := json.Unmarshal([]byte(data), &webReturn); err != nil {
		panic(err)
	}
	fmt.Println(webReturn.Message)

	//tmpl.Execute(w, struct{ Success bool }{webReturn.Result})
	tmpl.Execute(w, webReturn)
}

func main() {
	// Start Host goroutine
	go func() {
		http.HandleFunc("/", index)
		http.ListenAndServe(":8090", nil)
	}()
}

The form template I’ve is below and is working smoothly

<title>Form Submittal</title>
<h1>Contact</h1>
<form method="POST">
    <label>Email:</label><br />
    <input type="text" name="email"><br />
    <label>Subject:</label><br />
    <input type="text" name="subject"><br />
    <label>Message:</label><br />
    <textarea name="message"></textarea><br />

    <input type="submit">
</form>
{{if .Result}}
    <div id='foo'>
        <a href={{.Message}}>Download PDF file</a>
    </div>
    <h1></h1>
    <script>
        // setTimeout(function () {document.querySelector('#foo').style.display='none'}, 5000);
    </script>
{{end}}

Now I’ve another requirement that needs me to add html5 table to the template, so it become:

<title>Form Submittal</title>
<h1>Contact</h1>
<form method="POST">
    <label>Email:</label><br />
    <input type="text" name="email"><br />
    <label>Subject:</label><br />
    <input type="text" name="subject"><br />
    <label>Message:</label><br />
    <textarea name="message"></textarea><br />

    <table class="table table-striped">
        <tr>
            <td><h2>In</h2></td>
            <td><h2>Out</h2></td>
            <td><h2>Total</h2></td>
        </tr>
        <tr>
            <td>InData</td>
            <td>OutData</td>
            <td>TotalData</td>
        </tr>
</table>

    <input type="submit">
</form>
{{if .Result}}
    <div id='foo'>
        <a href={{.Message}}>Download PDF file</a>
    </div>
    <h1></h1>
    <script>
        // setTimeout(function () {document.querySelector('#foo').style.display='none'}, 5000);
    </script>
{{end}}

My question is, what could be the struct to be created to handle this form, do I need to modify:

type ContactDetails struct {
	Email   string
	Subject string
	Message string
}

Or what is the best way to handle this table?

Below sample of the data required:

type Payments struct {
    BU                  string
    PONo                string
    PO/PIValue          Number
    Currency            string
    VATrequired?        bool
    POcopyAttachment    attachement
}

I found it, I should use r.ParseForm() then r.Form[] is the item name is repeated, as using r.FormValue() will pick only the first item.
so my code now is:

// go build -ldflags "-H=windowsgui"
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"text/template"

	"github.com/zserge/lorca"
)

// ContactDetails ...
type ContactDetails struct {
	Email   string
	Subject string
	Message string
	Color1  []string
	Color2  []string
}

// ReturnedResult ...
type ReturnedResult struct {
	Result  bool   `json:"result"`
	Message string `json:"message"`
}

func index(w http.ResponseWriter, r *http.Request) {
	tmpl := template.Must(template.ParseFiles("forms.html"))
	if r.Method != http.MethodPost {
		tmpl.Execute(w, nil)
		return
	}

	r.ParseForm()
	fmt.Println(r.Form) // print information on server side.
	fmt.Println("path", r.URL.Path)
	fmt.Println("scheme", r.URL.Scheme)
	fmt.Println(r.Form["color1"][0])
	fmt.Println(r.Form["color1"][1])
	for k, v := range r.Form {
		fmt.Println("key:", k)
		fmt.Println("val:", strings.Join(v, ""))
	}
	details := ContactDetails{
		Email:   r.FormValue("email"),
		Subject: r.FormValue("subject"),
		Message: r.FormValue("message"),
		Color1:  r.Form["color1"],
		Color2:  r.Form["color2"],
	}
	fmt.Printf("Post from website! r.PostFrom = %v\n", r.PostForm)
	fmt.Printf("Details = %v\n", details)

	//r.FormValue("username")
	fmt.Println()
	// do something with details
	sheetID := "AKfycbxfMucXOzX15tfU4errRSAa9IzuTRbHzvUdRxzzeYnNA8Ynz8LJuBuaMA/exec"
	url := "https://script.google.com/macros/s/" + sheetID + "/exec"
	bytesRepresentation, err := json.Marshal(details)
	if err != nil {
		log.Fatalln(err)
	}
	resp, err := http.Post(url, "application/json", bytes.NewBuffer(bytesRepresentation))
	if err != nil {
		log.Fatalln(err)
	}
	// read all response body
	data, _ := ioutil.ReadAll(resp.Body)

	// close response body
	resp.Body.Close()

	webReturn := ReturnedResult{}
	if err := json.Unmarshal([]byte(data), &webReturn); err != nil {
		panic(err)
	}
	fmt.Println(webReturn.Message)

	//tmpl.Execute(w, struct{ Success bool }{webReturn.Result})
	tmpl.Execute(w, webReturn)
}

func main() {
	// Start Host goroutine
	go func() {
		http.HandleFunc("/", index)
		http.ListenAndServe(":8090", nil)
	}()

	// Start UI
	ui, err := lorca.New("http://localhost:8090/index", "", 480, 320)
	if err != nil {
		log.Fatal(err)
	}
	defer ui.Close()

	<-ui.Done()
}

And the template is:

<title>Form Submittal</title>
<h1>Contact</h1>
<form method="POST">
    <label>Email:</label><br />
    <input type="text" name="email"><br />
    <label>Subject:</label><br />
    <input type="text" name="subject"><br />
    <label>Message:</label><br />
    <textarea name="message"></textarea><br />

    <table>
        <tr>
          <td><input type="text" name="color1" /></td>
          <td><input type="text" name="color2" /></td>
        </tr>
        <tr>
          <td><input type="text" name="color1" /></td>
          <td><input type="text" name="color2" /></td>
        </tr>
      <table>

   <input type="submit">
</form>
{{if .Result}}
    <div id='foo'>
        <a href={{.Message}}>Download PDF file</a>
    </div>
    <h1></h1>
    <script>
        url = ''
        window.open(url, "_blank");
        // setTimeout(function () {document.querySelector('#foo').style.display='none'}, 5000);
    </script>
{{end}}