2013-07-07 2 views
12

Этот, казалось бы, простой, но это сводит меня с ума.Перейти Шаблоны: Возможны ли вложенные диапазоны?

Как сделать ссылку на элемент структуры выше в области внутри вложенного диапазона в шаблонах 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, так и с идентификатором Bar.

Проблема заключается в том, что кажется, что это невозможно:

  1. баров доступа внутри объема Фооса диапазон,
  2. Id Access Foo от внутренней рамки диапазона бара

У меня есть временное обходное решение, поставив кучу лишних полей в обеих структурах, но это кажется мне очень уродливым, нарушает СУХОЙ, и в целом кажется очень неправильным.

Есть ли способ с шаблонами golang делать то, что я хотел бы сделать?

ответ

17

Да. Я чувствую, как будто не найти решение исходит из того, что не читает пакет text/template достаточно близко. Если вы используете html/template, синтаксис один и тот же (и они говорят вам читать текст/шаблон;)). Вот полное рабочее решение для того, что вы, возможно, захотите сделать.

Go файла:

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

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

+0

Спасибо, этот подход отлично работает. – haploid

Смежные вопросы