【问题标题】:Go Templates: Are Nested Ranges Possible?Go 模板:嵌套范围可能吗?
【发布时间】:2013-07-04 18:27:30
【问题描述】:

这个看似简单,却让我发疯。

如何在 golang 模板的嵌套范围内引用范围内更高的结构元素?

例子:

type Foo struct {
  Id string
  Name string
}

type Bar struct {
  Id string
  Name string
}

var foos []Foo
var bars []Bar

// logic to populate both foos and bars

在模板中:

{{range .foos}}
  <div>Foo {{.Name}}</div>
  <div>
    {{range ..bars}}
      <div>Bar {{.Name}} <input type="text" name="ids_{{..Id}}_{{.Id}}" /></div>
    {{end}}
  </div>
{{end}}

显然 ..bars 和 ..Id 不起作用,但希望我的意图很明确。我想遍历 Foo 和 Bar 的所有组合,并生成一个表单元素,其名称由 Foo 的 Id 和 Bar 的 Id 构建。

问题是似乎不可能:

  1. 从 foos 范围范围内访问栏
  2. 从栏的范围内访问 Foo 的 ID

我有一个临时的解决方法,方法是在两个结构中放置一堆冗余字段,但这对我来说似乎很丑陋,违反了 DRY,而且总的来说感觉很不对。

golang 模板有什么方法可以做我想做的事吗?

【问题讨论】:

    标签: templates go


    【解决方案1】:

    是的。我觉得好像没有找到解决方案来自没有足够仔细地阅读text/template 包。如果您使用html/template,语法是相同的(它们告诉您阅读文本/模板;))。这是您可能想做的完整工作解决方案。

    转到文件:

    package main
    
    import (
        "bytes"
        "io/ioutil"
        "os"
        "strconv"
        "text/template"
    )
    
    type Foo struct {
        Id   string
        Name string
    }
    
    type Bar struct {
        Id   string
        Name string
    }
    
    var foos []Foo
    var bars []Bar
    
    func main() {
        foos = make([]Foo, 10)
        bars = make([]Bar, 10)
    
        for i := 0; i < 10; i++ {
            foos[i] = Foo{strconv.Itoa(i), strconv.Itoa(i)} // just random strings
            bars[i] = Bar{strconv.Itoa(10 * i), strconv.Itoa(10 * i)}
        }
    
        tmpl, err := ioutil.ReadFile("so.tmpl")
        if err != nil {
            panic(err)
        }
    
        buffer := bytes.NewBuffer(make([]byte, 0, len(tmpl)))
    
        output := template.Must(template.New("FUBAR").Parse(string(tmpl)))
        output.Execute(buffer, struct {
            FooSlice []Foo
            BarSlice []Bar
        }{
            FooSlice: foos,
            BarSlice: bars,
        })
    
        outfile, err := os.Create("output.html")
        if err != nil {
            panic(err)
        }
        defer outfile.Close()
        outfile.Write(buffer.Bytes())
    }
    

    注意:您可能可以做一些事情来不将文件加载到中间缓冲区(使用ParseFiles),我只是复制并粘贴了一些我为我的一个项目编写的代码。

    模板文件:

    {{ $foos := .FooSlice }}
    {{ $bars := .BarSlice }}
    
    {{range $foo := $foos }}
      <div>Foo {{$foo.Name}}</div>
      <div>
        {{range $bar := $bars}}
          <div>Bar {{$bar.Name}} <input type="text" name="ids_{{$foo.Id}}_{{$bar.Id}}" /></div>
        {{end}}
      </div>
    {{end}}
    

    这个故事的两个寓意是
    a) 明智地在模板中使用变量,它们是有益的
    b) 模板中的范围也可以设置变量,不需要单独依赖$.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-30
      • 2011-09-28
      • 1970-01-01
      • 2021-09-14
      • 2014-09-30
      • 2021-09-16
      • 1970-01-01
      • 2011-03-19
      相关资源
      最近更新 更多