Могу ли я получить доступ к основным переменным шаблона из вложенного шаблона? - PullRequest
0 голосов
/ 11 марта 2020

Давайте представим, что у меня есть шаблон с вложенным подшаблоном, подобным этому. ссылка на игровую площадку

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)
    }

}

Все работает хорошо, но теперь я хочу установить некоторую переменную в масштабе документа, которая изменяет поведение во всем шаблоне и его подшаблонах. Вот так (не работает, паникует). детская площадка ссылка

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}}
`

Как это сделать? Возможно ли это?

Ответы [ 3 ]

2 голосов
/ 11 марта 2020

Лучшим решением для комплексных решений, приведенных выше, является прекращение попыток использовать параметр конфигурации верхнего уровня, а вместо этого записать его в качестве функции шаблона с переменной config, находящейся в закрытии функции

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

и

t := template.Must(template.New("document").Funcs(template.FuncMap{
    "SwitchNameOrder": func() bool {
        return switchNames // variable sits in closure
    },
}).Parse(document))

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

Другой вариант - записать все переключение в виде строковой функции, а именно:

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

и SwitchNames как строковая функция

...Funcs(template.FuncMap{
    "SwitchNames": func(first, second string) string {
        if switchNames {
            return second + " " + first
        }
        return first + " " + second
    },
})...

, которая может быть менее или более чистой, в зависимости от фактической сложности

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

2 голосов
/ 11 марта 2020

Одна вещь, которую вы могли бы сделать, это использовать функцию шаблона, чтобы «объединить» переменную, переданную в суб-шаблон, с переменной из родительского шаблона.

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 голосов
/ 11 марта 2020

В итоге я добавил отдельную структуру 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

...