2013-07-07 17 views
12

Dieser ist scheinbar einfach, aber es macht mich wahnsinnig.Go-Vorlagen: Sind verschachtelte Bereiche möglich?

Wie geht man in einem geschachtelten Bereich in Golang Templates über ein Strukturelement, das höher im Bereich liegt,?

Beispiel:

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 

In der Vorlage:

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

Offensichtlich ..bars und ..Id nicht funktionieren, aber hoffentlich meine Absicht ist klar. Ich würde gerne alle Kombinationen von Foo und Bar durchlaufen und ein Formularelement mit einem Namen erzeugen, der sowohl von der Foo's Id als auch von der Bar's Id erstellt wurde.

Das Problem ist, dass es scheint, es ist unmöglich zu:

  1. Zugang Bars aus dem Inneren des Umfangs der foos reichen Umfang
  2. Zugang Foo Id aus dem Inneren des Bereichs Umfang der Bar

Ich habe einen vorübergehenden Workaround, indem ich eine Reihe redundanter Felder in beiden Strukturen platziere, aber das scheint mir sehr hässlich zu sein, verstößt gegen DRY und fühlt sich im Allgemeinen sehr falsch an.

Gibt es irgendeine Möglichkeit mit Golang-Vorlagen zu tun, was ich tun möchte?

Antwort

17

Ja. Ich fühle mich, als ob nicht eine Lösung zu finden kommt aus dem text/template Paket nicht genau genug zu lesen. Wenn Sie html/template verwenden, ist die Syntax die gleiche (und sie sagen Ihnen, Text/Vorlage zu lesen;)). Hier ist eine vollständige Arbeitslösung für was Sie tun möchten.

Go-Datei:

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

Hinweis: Sie können sich wahrscheinlich etwas tun, um die Datei nicht in einen Zwischenpuffer zu laden (verwenden ParseFiles), habe ich einige Code einfach kopiert und eingefügt, die ich für eine meiner geschrieben hatte, Projekte.

Template-Datei:

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

Die beiden Moral dieser Geschichte sind
a) umsichtig Variablen in Vorlagen verwenden, sie sind von Vorteil
b) liegen in Vorlagen auch Variablen festlegen können, müssen Sie nicht sich ausschließlich auf $ oder .

+0

zu verlassen, Dank dieser Ansatz funktioniert gut. – haploid

Verwandte Themen