2

I have a nested loop:

{{$columns := .columns}}
{{range $dx := .dataList}}
    {{range $c := $columns}}
        {{index $dx $c}}
    {{end}}
{{end}}

dataList is the orm model array. With ID, Title fields , then columns is the []string variable contains all orm model field names like ID, Title.

type AdFile struct {
    ID      uint `gorm:"primary_key"`
    Title   string
}

I've tried with {{(index .listData 0).Title}} and it works.

But if i want to access $dx.Title, $dx.ID .... with Title, ID as variables, but it doesn't work. I've tried $dx[$c].

Can achieve the same thing with Python easily

for i in list_data
    tr
        for p in columns
            td=i[p]
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
TomSawyer
  • 3,711
  • 6
  • 44
  • 79
  • 2
    I think its a nice question. Important things to learn here. Why closing vote? – Shahriar Feb 02 '18 at 09:52
  • 1
    You say `$dx.Title` doesn't work, but your code doesn't do that. Also, how does it not work? What was the result? And what is your actual data structure? There's not enough info here to answer your question. Include a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). – Jonathan Hall Feb 02 '18 at 09:58
  • @Flimzy It's a correct and enough info question. What am i supposed to ask? `$dx.Title = $dx.$c`, all i want is to make access to object field / property like other language. – TomSawyer Feb 02 '18 at 10:02
  • 1
    @TomSawyer can you give us whole code and data structure? – Abu Hanifa Feb 02 '18 at 10:09
  • @AbuHanifa The code is simple , dataList is the orm model array. With `ID, Title` fields , you see the loop to fetch all of them, then `columns` is the `[]string` variable contains all orm model field names like `ID, Title` – TomSawyer Feb 02 '18 at 10:11
  • 1
    I think he means that `$c` is iterating over `Title` `ID` and so on. – leaf bebop Feb 02 '18 at 10:12

1 Answers1

2

To access field values of a struct given by their names, you need help from the reflect package. It can be done like this:

v := AdFile{ID:1, Title: "T1"} // A struct value
name := "ID"                   // field name

fieldValue := reflect.ValueOf(v).FieldByName(name).Interface()

Since this is Go code, you can't embed this in templates. But you may register custom functions with the Template.Funcs() method which may be called from templates.

So let's do this: wrap this functionality into a function, and register it by the name "Field" so we can call it from our template.

func main() {
    t := template.Must(template.New("").Funcs(template.FuncMap{
        "Field": func(v interface{}, name string) interface{} {
            return reflect.ValueOf(v).FieldByName(name).Interface()
        },
    }).Parse(templ))

    m := map[string]interface{}{
        "columns": []string{"ID", "Title"},
        "dataList": []AdFile{
            {ID: 1, Title: "Title1"},
            {ID: 2, Title: "Title2"},
        },
    }

    if err := t.Execute(os.Stdout, m); err != nil {
        panic(err)
    }

}

const templ = `{{$columns := .columns}}
{{range $dx := .dataList}}
    {{range $c := $columns}}
        {{- Field $dx $c }}
    {{end}}
{{end}}`

Output of the above app (try it on the Go Playground):

1
Title1


2
Title2

Note: error check is omitted in the registered "Field" function. You may improve it to return nil if the given field name is invalid, or return an error which is handled by the template engine (in which case template execution would be aborted with the error you return).

icza
  • 389,944
  • 63
  • 907
  • 827
  • Thank icza, i thought custom function is the only chance :(, go template should have the the build in function for this – TomSawyer Feb 02 '18 at 11:09