1

I have a Form html like :

<input name="email"type="email" />
<input name="password"type="password" />
<input name="tags[name][]"type="text" />
<input name="tags[count][]"type="number" />
<input name="tags[name][]"type="text" />
<input name="tags[count][]"type="number" />
<input name="tags[name][]"type="text" />
<input name="tags[count][]"type="number" />
<input name="freeword[]"type="text" />
<input name="freeword[]"type="text" />

I want to Bind() this form with my struct like :

type UserFrom struct {
  Email string `json:"email" form:"email" query:"email"`
  Password string `json:"password" form:"password" query:"password"`
  Tags []Tag
  Free []string `json:"freeword[]" form:"freeword[]" query:"freeword[]"`
}
type Tag struct {
  Name string `json:"tags[name][]" form:"tags[name][]" query:"tags[name][]"`
  Count string `json:"tags[count][]" form:"tags[count][]" query:"tags[count][]"`
}

But if i print the result of Bind() after POST i have :

u := new(UserFrom)
if err = c.Bind(u); err != nil {
  return
}
log.Println(u)

This bad Output :

&{email@mail.tld pwdpwdpwd [] [word1 word2]}

The row Tags []Tag in UserFrom struct does not work

If y try to change Tags []Tag to Tags Tag i have a good last entry

&{email@mail.tld pwdpwdpwd {tag3 3} [word1 word2]}

I want this output :

&{email@mail.tld pwdpwdpwd [{tag1 1} {tag2 2} {tag3 3}] [word1 word2]}

do you have an idea of the problem ?

Echo Doc to Bind()

eclaude
  • 742
  • 10
  • 25

1 Answers1

1

There are two problems:

  1. you did not specify the form input names correctly, the way you have them can never map to what you want in any language. In languages that support what you want, it would map tags to a struct of two fields (name and count) each consisting of an array. Not to an array of structs of name and count. Names should be like this tags[][name] in order to achieve what you want, see here for example: HTML Form: POST an array of objects
  2. even if you specified the name correctly as per the above, it would not work in Echo anyway as it relies on http.Request.Form to parse the values, which is effectively url.Values which in turn is just a map[string][]string. As you can see, that cannot possibly capture the structure you want. Here is a relevant ticket: https://github.com/golang/go/issues/29703

Now, just because Echo does not support that out of the box, it doesn't mean you cannot do it. You can use a 3rd party library for binding that has the features you need, such as https://github.com/monoculum/formam

The following code:

package main

import (
    "fmt"
    "net/url"

    "github.com/monoculum/formam"
)

type User struct {
    Email,
    Password string
    Tags []struct {
        Tag   string
        Count int
    }
}

func main() {
    formData := "Email=joe@example.com&Password=secret&Tags[0].Tag=red&" + 
        "Tags[0].Count=1&Tags[1].Tag=blue"
    q, _ := url.ParseQuery(formData)
    u := new(User)

    dec := formam.NewDecoder(nil)
    if err := dec.Decode(q, u); err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(u)
}

results in what you need:

&{joe@example.com secret [{red 1} {blue 0}]}

Hope this helps!

alexaandru
  • 101
  • 1
  • 1
  • 3