我可以从嵌套模板访问顶级模板变量吗?

问题描述 投票:1回答:3

假设我有一个带有嵌套子模板的模板,像这样。 playground link

package main

import (
    "os"
    "text/template"
)

type Person struct {
    FirstName  string
    SecondName string
}

type Document struct {
    DocName string
    People  []Person
}

const document = `
Document name: {{.DocName}}

{{range $person:=.People}}
{{template "person" $person}}
{{end}}

{{- define "person"}}
Person name is: {{.FirstName}} {{.SecondName}}
{{end}}
`

func main() {

    d := Document{
        DocName: "first try",
        People: []Person{
            {"Brian", "Kernighan"},
            {"Dennis", "Ritchie"},
        },
    }

    t := template.Must(template.New("document").Parse(document))

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

}

都可以,但是现在我想设置一些文档范围的变量,以更改所有模板及其子模板的行为。像这样(不起作用,恐慌)。 playground link

type Person struct {
    FirstName  string
    SecondName string
}

type Document struct {
    DocName string
    People  []Person

    SwitchNameOrder bool
}

const document = `
Document name: {{.DocName}}

{{range $person:=.People}}
{{template "person" $person}}
{{end}}

{{- define "person"}}
{{if $.SwitchNameOrder}} // <---- panic here
Person name is: {{.SecondName}} {{.FirstName}}
{{else}}
Person name is: {{.FirstName}} {{.SecondName}}
{{end}}
{{end}}
`

如何做?有可能吗?

go go-templates
3个回答
1
投票

您可以做的一件事是使用模板函数将传递到子模板的变量与父模板中的变量“合并”。

type Person struct {
    FirstName  string
    SecondName string
}

type Document struct {
    DocName string
    People  []Person

    SwitchNameOrder bool
}

func personWithDocument(p Person, d Document) interface{} {
    return struct {
        Person
        Document Document
    }{p, d}
}

t := template.Must(template.New("document").Funcs(template.FuncMap{
    "personWithDocument": personWithDocument,
}).Parse(document))

然后在模板中,您将要做:

const document = `
Document name: {{.DocName}}

{{range $person:=.People}}
{{template "person" (personWithDocument $person $) }}
{{end}}

{{- define "person"}}
{{if .Document.SwitchNameOrder}}
Person name is: {{.SecondName}} {{.FirstName}}
{{else}}
Person name is: {{.FirstName}} {{.SecondName}}
{{end}}
{{end}}
`

https://play.golang.org/p/YorPsMdr9g_H


0
投票

我最终要做的是添加一个单独的struct Config并将其复制到各处。也就是说,

type Config struct {
    SwitchNameOrder bool
}

type Person struct {
    FirstName  string
    SecondName string

    Config Config 
    // this could also be a pointer,
    // but I don't want to deal with nils, so let's copy
}

type Document struct {
    DocName string
    People  []Person

    Config Config
}

c := Config{SwitchNameOrder: true}

d.Config = c
for _, p := range d.People {
    p.Config = c
}

然后在模板中使用它


{{- define "person"}}
{{if .Config.SwitchNameOrder}}
Person name is: {{.SecondName}} {{.FirstName}}
{{else}}
Person name is: {{.FirstName}} {{.SecondName}}
{{end}}
{{end}}

很丑,但是该怎么办

https://play.golang.org/p/f95i4me8XLP


0
投票

对上述复杂解决方案的一个更好的解决方案是停止尝试使用顶级config选项,而是将其写为模板函数。

{{- define "person"}}
Person name is: {{SwitchNames .FirstName .SecondName}}
{{end}}

t := template.Must(template.New("document").Funcs(template.FuncMap{
    "SwitchNames": func(first, second string) string {
        if switchNames { // variable sits in closure
            return second + " " + first
        }
        return first + " " + second
    },
}).Parse(document))

https://play.golang.org/p/Qt5FERIqIYp

© www.soinside.com 2019 - 2024. All rights reserved.