1

I am trying to submit and parse a form in go and I am failing to parse the form fields properly. Here is an excerpt of the code I am trying.

formtest.go : package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/codegangsta/negroni"
    "github.com/davecgh/go-spew/spew"
    "github.com/julienschmidt/httprouter"
    "github.com/mholt/binding"
    "gopkg.in/unrolled/render.v1"
)

type FormInfo struct {
    Fields    []string
    Action    string
    PageTitle string
    Id        string
}

func (f *FormInfo) FieldMap(*http.Request) binding.FieldMap {
    return binding.FieldMap{
        &f.Fields: "fields",
        &f.Action: "action",
    }
}

func formtest(
    resp http.ResponseWriter,
    req *http.Request,
    p httprouter.Params) {

    // var ticket Ticket
    info := new(FormInfo)
    tkt := p.ByName("tkt")
    info.PageTitle = tkt
    info.Id = tkt

    if req.Method == "POST" {
        bind_err := binding.Bind(req, info)
        if bind_err.Handle(resp) {
            log.Println("Error decoding form contents")
            return
        }
        spew.Dump(info)
    }

    Render.HTML(resp, http.StatusOK, "formtest", info)
    return
}

var Render *render.Render

func main() {

    router := httprouter.New()

    router.GET("/formtest", formtest)
    router.POST("/formtest", formtest)

    Render = render.New(render.Options{
        Layout:          "layout",
        IndentJSON:      true,
        IndentXML:       true,
        HTMLContentType: "text/html",
        IsDevelopment:   true,
    })

    n := negroni.New(
        negroni.NewRecovery(),
        negroni.NewLogger(),
        negroni.NewStatic(http.Dir("static")),
    )
    n.UseHandler(router)
    n.Run(fmt.Sprintf(":%d", 3000))

}

templates/layout.tmpl :

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>{{ .PageTitle }}</title>
    <meta http-equiv="Content-Type" content="text/html;" charset="utf-8">
    <meta charset="UTF-8">
    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
    <link rel="apple-touch-icon" href="/mobile.png" />
    <meta name="viewport" 
          content="initial-scale=1.0,width=device-width,user-scalable=no">
    <meta name="generator" content="Go">
    <link rel="stylesheet" href="/base.css" type="text/css">
  </head>

  <body>

      <div class="mainbody">
        {{ yield }}
      </div>

  </body>

</html>

templates/formtest.tmpl :

<h1>{{ .PageTitle }}</h1>

<form action="/formtest/{{ .Id }}" method="POST">

    <div class="details">
      <label>Question 1</label>
      <input type="text" name="fields[0]" value="value 1" />
    </div>

    <div class="details">
      <label>Question 2</label>
      <input type="text" name="fields[1]" value="value 2" />
    </div>

    <div class="details">
      <input type="submit" name="action" value="save" />
    </div>

</form>

Procedure:

  1. go run formtest.go
  2. Open browser and go to http://127.0.0.1:3000/formtest
  3. Submit the form
  4. Check console for the logs.

Observation :

(*main.FormInfo)(0xc820066c30)({
 Fields: ([]string) <nil>,
 Action: (string) (len=4) "save",
 PageTitle: (string) "",
 Id: (string) ""
})

Expectation :

Fields: ([]string) <contains two values submitted>,

But when I try to print the contents of Fields, it is nil. What am I doing wrong?

3
  • 1
    provide MCVE stackoverflow.com/help/mcve . Now you code not correct. Commented Sep 28, 2015 at 11:57
  • Thank you for the feedback. I have corrected it now. Commented Sep 28, 2015 at 17:32
  • I will try to answer. Why do you use so many libraries for this simple example? Commented Sep 29, 2015 at 0:00

1 Answer 1

1

Binding so not work. The fields of your form - name = "fields [1]" and name = "fields [0]" are independent from each other, so for each of them your structure should contain its own field:

type FormInfo struct {
    Fields1   string
    Fields2   string
    Action    string
    PageTitle string
    Id        string
}

respectively, in the handler:

...
&f.Fields1: "fields[0]",
&f.Fields2: "fields[1]",
&f.Action:  "action",
...

As a result, the output will be:

(*main.FormInfo)(0xc08200aa50)({
 Fields1: (string) (len=7) "value 1",
 Fields2: (string) (len=7) "value 2",
 Action: (string) (len=4) "save",
 PageTitle: (string) "",
 Id: (string) ""
})

EDIT:

If you change the code in the form on the

...
<input type="text" name="fields"...
<input type="text" name="fields"...

you can get

info.Fields = [value 1 value 2]

without changing its original code.

Sign up to request clarification or add additional context in comments.

1 Comment

What should the form look like if I have to scan into an array? Meaning, I do not want to change the structure of FormInfo, what do I change in template?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.