How do you pass multiple objects to go template?

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

How do you pass multiple objects to go template?

问题

大多数我能找到的示例都描述了非常简单/基本的事情,比如显示一个人对象的属性,像这样:

名字是{{.Name}}。年龄是{{.Age}}。

如果你有一个更复杂的网页,例如多个不同的对象和对象列表,会发生什么?例如,你要怎么做这样的事情:

{{p.Name}}的年龄是{{p.Age}}。
未付发票数量为{{invoices.Count}}

<table>
<tr><td>{{invoices[0].number}}</td></tr>
....等等...
英文:

Most examples I can find describe very simple/basic things, such as showing attributes of a person object like this:

The name is {{.Name}}. The age is {{.Age}}.

What happens if you have a more complicated web page, for example, multiple different objects and lists of objects, i.e. How do you do something like this:

{{p.Name}} is aged {{p.Age}}. 
Outstanding invoices {{invoices.Count}} 

&lt;table&gt;
&lt;tr&gt;&lt;td&gt;{{invoices[0].number}}&lt;/td&gt;&lt;/tr&gt;
.... etc...

答案1

得分: 7

你可以这样声明和传递一个匿名结构体:

templ.Execute(file, struct {
    Age int
    Name string
}{42, "Dolphin"})

然后可以这样访问变量:

{{.Age}}, {{.Name}}

虽然这仍然需要你创建一个结构体,但这是最简洁的方法之一。你需要决定是否对你来说太丑陋了 How do you pass multiple objects to go template?

英文:

You can declare and pass in an anonymous struct like this:

templ.Execute(file, struct {
    Age int
    Name string
}{42, &quot;Dolphin&quot;})

and access the variables like:

{{.Age}}, {{.Name}}

While this still requires you to make a struct, it is among the most concise ways to do it. You'll have to decide if it is too ugly for you How do you pass multiple objects to go template?

答案2

得分: 5

你可以将更复杂的数据放入结构体中,并像你之前传递NameAge一样传递它。例如,

type vars struct {
    P User
    Invoices []Invoice
}

type User struct {
    Name string
    Age int
}

type Invoice struct {
    Number int
    Description string
}

如果你将vars的实例传递到模板执行中,你可以使用点和数组索引来引用子结构,就像在普通的Go代码中一样。

{{.P.Name}}, {{.P.Age}}, {{.Invoices[0].Number}}
英文:

You can put your more complex data into struct, and pass it just like you did Name and Age. For example,

type vars struct {
    P User
    Invoices []Invoice
}

type User struct {
    Name string
    Age int
}

type Invoice {
    Number int
    Description string
}

If you pass an instance of vars into the template execution, you can reference sub-structures by using dots and array indexes, just like in regular go code.

{{.P.Name}}, {{.P.Age}}, {{.Invoices[0].Number}}

答案3

得分: 1

这取决于你的数据是什么。
我想对这个进行分类。

  1. 主要数据是模板所用的数据。在你的例子中,这可能是发票/发票清单。如果你需要传递多个这样的数据,你需要重新考虑你的模板设计。
  2. 次要数据,比如已登录用户的信息或者任何你发现自己在多个模板中都要传递的公共信息。

由于这些信息是公共的,我通常将它们封装成函数。由于这些函数不能有输入参数,你可能需要将它们创建为闭包(在另一个函数内部)。将这些函数分配给funMap,并在解析后将其添加到模板中。

func MakeFuncMap(u *user) map[string]interface{} {
    return map[string]interface{}{
        "User": func() *user {return u}, //可以在模板中通过"User."来访问
    }
}

t, err := template.New("tmpl").Funcs(MakeFuncMap(nil)).Parse("template") //在模板解析时,你需要添加一个虚拟的funcMap,因为此时还无法访问到User

//你需要克隆模板以使其线程安全,以便追加funcMap
tClone, _ := t.Clone()
tClone.Funcs(MakeFuncMap(u)).Execute(w, invoicelist)

现在你可以只使用invoicelist作为数据来执行模板。在模板中,你应该能够通过"User."来访问用户信息,通过"."来访问发票清单。

你可以为所有公共数据定义一次funcMap,这样你就可以重复使用它。

要循环遍历invoicelist,你可以使用range关键字:

{{range .}} //如果你传递的是invoicelist,那么"."表示invoicelist
   //在这里,"."表示每个发票
   <label>{{User.Name}}, {{User.Age}}</label>
   <label>{{.Id}}</label>
{{end}}

编辑:修复了Ripounet指出的问题。

英文:

It depends on what your data is.
I want to categorise this.

  1. Primary data that the template is meant for. In your example that would be Invoice/Invoicelist. If you have to pass more than one of these you have to reconsider your template design.
  2. Secondary data such as logged in user information or any common information that you find yourself passing into several templates.

Since these information are common. I usually make them into functions. Since these functions cannot have input params. You might want to create them as closures (within another function). Assign these function to funMap and add it to the template after parsing.

func MakeFuncMap(u *user) map[string]interface{} {
	return map[string]interface{}{
        &quot;User&quot;: func() *user {return u}, //Can be accessed by &quot;User.&quot; within your template
    }
}

t, err := template.New(&quot;tmpl&quot;).Funcs(MakeFuncMap(nil)).Parse(&quot;template&quot;) //You will need to append a dummy funcMap as you will not have access to User at the time of template parsing

//You will have to clone the template to make it thread safe to append funcMap.
tClone, _ := t.Clone()
tClone.Funcs(MakeFuncMap(u)).Execute(w, invoicelist)

Now you can execute the template with only the invoicelist as data.
Within your template you should be able to access user information using "User." and invoice list by "."

You should be able to define the funcMap once for all the common data. So that you will be able reuse it.

To loop through a invoicelist you can look into range

{{range .}} //if you are passing invoicelist then the . means invoicelist
   //in here . means each of the invoice
   &lt;label&gt;{{User.Name}}, {{User.Age}}&lt;/label&gt;
   &lt;label&gt;{{.Id}}&lt;/label&gt;
{{end}}

EDIT: Included fix for issue pointed out by Ripounet

huangapple
  • 本文由 发表于 2014年5月22日 16:50:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/23802008.html
匿名

发表评论

匿名网友

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

确定