Go html模板中如何在range循环中访问结构体字段?

huangapple go评论74阅读模式
英文:

Go html template access struct fields inside range

问题

给定以下结构体,我想在遍历field1数据时访问field2。我该如何做?

var MyPageData struct {
      field1 []Foo
      field2 map[string]Bar
}

我尝试了以下代码,在处理函数中:

err := myPageTemplate.Execute(w, MyPageData{field1: field1Slice, field2: myMapData})

模板代码如下:

{{ range $index, $fooInstance := .field1}} 
    <tr>
        <td>{{$fooInstance.Name}}</td> <!-- 这里打印了 Name 的值 -->
        <td>{{ index .$field2 "myKey".Name }}</td>

我如何访问上面的field2并指定一个键值来检索Bar实例?

更新 添加了FooBar结构体的定义:

type Foo2 struct {
    Name string
    Id   int 
}

type Foo struct {
    Name    string
    Element Foo2
}

type Bar struct {
    Name string
}
英文:

Given below struct, I want to access field2 while iterating over field1 data in html. How do I do this?

var MyPageData struct {
      field1 []Foo
      field2 map[string]Bar
}

I tried: Inside Handler function:

err := myPageTemplate.Execute(w,MyPageData{ field1: field1Slice, field2 : myMapData})

Template:

     {{ range $index, $fooInstance := .field1}} 
        &lt;tr&gt;
            &lt;td&gt;{{$fooInstance.Name}}&lt;/td&gt; //This prints the Name value
            &lt;td&gt;{{ index .$field2 &quot;myKey&quot;.Name }}&lt;/td&gt;

How do I access field2 above and specify a key value to retrieve Bar instance?

UPDATE Adding Foo and Bar structs
<!-- language : Go -->

type Foo2 struct {
    Name string
    Id  int 
}


type Foo struct {
    Name string
    element Foo2
}

type Bar struct {
    Name string
}

答案1

得分: 4

无论管道的值是什么(在模板中用点号 . 表示),你可以使用 $ 来引用传递给 Template.Execute() 的数据值。{{range}} 动作遍历元素并将管道(.)设置为当前项,因此 . 总是表示当前项,$ 绝对指的是传递给 Template.Execute() 的“顶层”数据。

这在 text/template 中有记录:

> 当执行开始时,$ 被设置为传递给 Execute 的数据参数,也就是 dot 的初始值。

还要注意,你必须导出结构字段以在模板中使用。所以将你的 MyPageData 类型改为:

type MyPageData struct {
    Field1 []Foo
    Field2 map[string]Bar
}

还要注意,你可以使用 . 运算符简单地访问映射元素。所以你可以在 {{range}} 动作中像这样访问与 &quot;myKey&quot; 键关联的 Field2 映射的值:

{{$.Field2.myKey}}

看看这个简单的例子:

type MyPageData struct {
    Field1 []Foo
    Field2 map[string]Bar
}

type Foo struct {
    Name string
}

type Bar struct {
    Name string
}

func main() {
    t := template.Must(template.New(&quot;&quot;).Parse(templ))
    mpd := MyPageData{
        Field1: []Foo{{&quot;First&quot;}, {&quot;Second&quot;}},
        Field2: map[string]Bar{&quot;myKey&quot;: {&quot;MyValue&quot;}},
    }
    t.Execute(os.Stdout, mpd)
}

const templ = `{{range $idx, $foo := .Field1}}{{$.Field2.myKey}} {{$idx}} - {{$foo.Name}}
{{end}}`

输出结果(在 Go Playground 上尝试):

{MyValue} 0 - First
{MyValue} 1 - Second

还要注意,在 {{range}} 中,你可以使用 {{.Name}} 来代替 $foo.Name,因为点号 . 表示 $foo,即当前项。

如果你想使用动态键从 Field2 中查找一个值,你确实需要使用 {{index}} 动作。例如,如果你想要与键 $foo.Name 关联的值:

{{index $.Field2 $foo.Name}}

或简写为:

{{index $.Field2 .Name}}

此外,如果与键关联的值是一个结构体,你只需要这个结构体的一个字段,比如 Id,你可以使用括号:

{{(index $.Field2 .Name).Id}}
英文:

No matter what the value of the pipeline is (which is denoted by the dot . in the template), you can use the $ to refer to the data value you passed to Template.Execute(). The {{range}} action iterates over the elements and it sets the pipeline (.) to the current item, so . always denotes the current item, $ is absolutely refers to the "top level" data passed to Template.Execute().

This is documented in text/template:

> When execution begins, $ is set to the data argument passed to Execute, that is, to the starting value of dot.

Also note that you have to export struct fields to be available in templates. So change your MyPageData type to:

type MyPageData struct {
    Field1 []Foo
    Field2 map[string]Bar
}

Also note that you can simply access map elements using the . operator. So you can access the value of the Field2 map associated with the &quot;myKey&quot; key like this, inside the {{range}} action too:

{{$.Field2.myKey}}

See this simple example:

type MyPageData struct {
    Field1 []Foo
    Field2 map[string]Bar
}

type Foo struct {
    Name string
}

type Bar struct {
    Name string
}

func main() {
    t := template.Must(template.New(&quot;&quot;).Parse(templ))
    mpd := MyPageData{
        Field1: []Foo{{&quot;First&quot;}, {&quot;Second&quot;}},
        Field2: map[string]Bar{&quot;myKey&quot;: {&quot;MyValue&quot;}},
    }
    t.Execute(os.Stdout, mpd)
}

const templ = `{{range $idx, $foo := .Field1}}{{$.Field2.myKey}} {{$idx}} - {{$foo.Name}}
{{end}}`

Output (try it on the Go Playground):

{MyValue} 0 - First
{MyValue} 1 - Second

Also note that insdie the {{range}} instead of $foo.Name you can simply use {{.Name}} as the dot . denotes $foo, the current item.

If you want to lookup a value from Field2 with a dynamic key, you do need to use the {{index}} action. For example if you want the value associated with the key being $foo.Name:

{{index $.Field2 $foo.Name}}

Or short:

{{index $.Field2 .Name}}

And going forward, if the value associated with the key is a struct for example, and you only need a field of this struct, let's say Id, you can use parenthesis:

{{(index $.Field2 .Name).Id}}

huangapple
  • 本文由 发表于 2016年1月11日 13:21:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/34714663.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定