如何将多个值从模板传递到模板?
How to pass multiple values from template to template?
我的 City
结构是这样的:
type City struct {
ID int
Name string
Regions []Region
}
而Region
结构是:
type Region struct {
ID int
Name string
Shops []Destination
Masters []Master
EducationCenters []Destination
}
主要是我尝试这样做:
tpl.ExecuteTemplate(resWriter,"cities.gohtml",CityWithSomeData)
是否可以在模板中做这样的事情?
{{range .}}
{{$city:=.Name}}
{{range .Regions}}
{{$region:=.Name}}
{{template "data" .Shops $city $region}}
{{end}}
{{end}}
我猜 CityWithSomeData
是一个切片,如果是的话试试看:
type viewModel struct {
List []City
}
然后,在您的模板中:
{{range .List}}
{{$city:=.Name}}
{{range .Regions}}
{{$region:=.Name}}
{{template "data" .Shops $city $region}}
{{end}}
{{end}}
引用 text/template
的文档,{{template}}
操作的语法:
{{template "name"}}
The template with the specified name is executed with nil data.
{{template "name" pipeline}}
The template with the specified name is executed with dot set
to the value of the pipeline.
这意味着您可以将一个可选数据传递给模板执行,而不是更多。如果你想传递多个值,你必须将它们包装成你传递的某个单一值。有关详细信息,请参阅
所以我们应该将这些数据包装到结构或映射中。但是我们不能在模板中编写 Go 代码。我们可以做的是注册一个函数,我们将这些数据传递给该函数,该函数可以执行 "packing" 和 return 单个值,现在我们可以将其传递给 {{template}}
操作。
这是一个示例包装器,它只是将这些包装到地图中:
func Wrap(shops []Destination, cityName, regionName string) map[string]interface{} {
return map[string]interface{}{
"Shops": shops,
"CityName": cityName,
"RegionName": regionName,
}
}
可以使用 Template.Funcs()
方法注册自定义函数,不要忘记在解析模板文本之前必须这样做。
这是一个修改后的模板,它调用此 Wrap()
函数来生成单个值:
const src = `
{{define "data"}}
City: {{.CityName}}, Region: {{.RegionName}}, Shops: {{.Shops}}
{{end}}
{{- range . -}}
{{$city:=.Name}}
{{- range .Regions -}}
{{$region:=.Name}}
{{- template "data" (Wrap .Shops $city $region) -}}
{{end}}
{{- end}}`
这是一个可运行的示例,显示了这些操作:
t := template.Must(template.New("cities.gohtml").Funcs(template.FuncMap{
"Wrap": Wrap,
}).Parse(src))
CityWithSomeData := []City{
{
Name: "CityA",
Regions: []Region{
{Name: "CA-RA", Shops: []Destination{{"CA-RA-SA"}, {"CA-RA-SB"}}},
{Name: "CA-RB", Shops: []Destination{{"CA-RB-SA"}, {"CA-RB-SB"}}},
},
},
{
Name: "CityB",
Regions: []Region{
{Name: "CB-RA", Shops: []Destination{{"CB-RA-SA"}, {"CB-RA-SB"}}},
{Name: "CB-RB", Shops: []Destination{{"CB-RB-SA"}, {"CB-RB-SB"}}},
},
},
}
if err := t.ExecuteTemplate(os.Stdout, "cities.gohtml", CityWithSomeData); err != nil {
panic(err)
}
输出(在 Go Playground 上尝试):
City: CityA, Region: CA-RA, Shops: [{CA-RA-SA} {CA-RA-SB}]
City: CityA, Region: CA-RB, Shops: [{CA-RB-SA} {CA-RB-SB}]
City: CityB, Region: CB-RA, Shops: [{CB-RA-SA} {CB-RA-SB}]
City: CityB, Region: CB-RB, Shops: [{CB-RB-SA} {CB-RB-SB}]
您需要允许从参数列表构建 map[string]interface{}
的通用 dict
函数。
见
我的 City
结构是这样的:
type City struct {
ID int
Name string
Regions []Region
}
而Region
结构是:
type Region struct {
ID int
Name string
Shops []Destination
Masters []Master
EducationCenters []Destination
}
主要是我尝试这样做:
tpl.ExecuteTemplate(resWriter,"cities.gohtml",CityWithSomeData)
是否可以在模板中做这样的事情?
{{range .}}
{{$city:=.Name}}
{{range .Regions}}
{{$region:=.Name}}
{{template "data" .Shops $city $region}}
{{end}}
{{end}}
我猜 CityWithSomeData
是一个切片,如果是的话试试看:
type viewModel struct {
List []City
}
然后,在您的模板中:
{{range .List}}
{{$city:=.Name}}
{{range .Regions}}
{{$region:=.Name}}
{{template "data" .Shops $city $region}}
{{end}}
{{end}}
引用 text/template
的文档,{{template}}
操作的语法:
{{template "name"}}
The template with the specified name is executed with nil data.
{{template "name" pipeline}}
The template with the specified name is executed with dot set
to the value of the pipeline.
这意味着您可以将一个可选数据传递给模板执行,而不是更多。如果你想传递多个值,你必须将它们包装成你传递的某个单一值。有关详细信息,请参阅
所以我们应该将这些数据包装到结构或映射中。但是我们不能在模板中编写 Go 代码。我们可以做的是注册一个函数,我们将这些数据传递给该函数,该函数可以执行 "packing" 和 return 单个值,现在我们可以将其传递给 {{template}}
操作。
这是一个示例包装器,它只是将这些包装到地图中:
func Wrap(shops []Destination, cityName, regionName string) map[string]interface{} {
return map[string]interface{}{
"Shops": shops,
"CityName": cityName,
"RegionName": regionName,
}
}
可以使用 Template.Funcs()
方法注册自定义函数,不要忘记在解析模板文本之前必须这样做。
这是一个修改后的模板,它调用此 Wrap()
函数来生成单个值:
const src = `
{{define "data"}}
City: {{.CityName}}, Region: {{.RegionName}}, Shops: {{.Shops}}
{{end}}
{{- range . -}}
{{$city:=.Name}}
{{- range .Regions -}}
{{$region:=.Name}}
{{- template "data" (Wrap .Shops $city $region) -}}
{{end}}
{{- end}}`
这是一个可运行的示例,显示了这些操作:
t := template.Must(template.New("cities.gohtml").Funcs(template.FuncMap{
"Wrap": Wrap,
}).Parse(src))
CityWithSomeData := []City{
{
Name: "CityA",
Regions: []Region{
{Name: "CA-RA", Shops: []Destination{{"CA-RA-SA"}, {"CA-RA-SB"}}},
{Name: "CA-RB", Shops: []Destination{{"CA-RB-SA"}, {"CA-RB-SB"}}},
},
},
{
Name: "CityB",
Regions: []Region{
{Name: "CB-RA", Shops: []Destination{{"CB-RA-SA"}, {"CB-RA-SB"}}},
{Name: "CB-RB", Shops: []Destination{{"CB-RB-SA"}, {"CB-RB-SB"}}},
},
},
}
if err := t.ExecuteTemplate(os.Stdout, "cities.gohtml", CityWithSomeData); err != nil {
panic(err)
}
输出(在 Go Playground 上尝试):
City: CityA, Region: CA-RA, Shops: [{CA-RA-SA} {CA-RA-SB}]
City: CityA, Region: CA-RB, Shops: [{CA-RB-SA} {CA-RB-SB}]
City: CityB, Region: CB-RA, Shops: [{CB-RA-SA} {CB-RA-SB}]
City: CityB, Region: CB-RB, Shops: [{CB-RB-SA} {CB-RB-SB}]
您需要允许从参数列表构建 map[string]interface{}
的通用 dict
函数。
见