2013-12-21 3 views
6

템플릿 (텍스트 또는 HTML)을 동적 이름으로 호출하는 방법이 없습니다. 예 :이 작동동적 이름을 가진 다른 템플릿을 호출하십시오.

"템플릿 호출에" "예상치 못한"$ BlahVar와

{{template "Blah" .}} 

이 오류 :

{{$BlahVar := "Blah"}} 
{{template $BlahVar .}} 

내가 해결하기 위해 노력하고있어 전반적인 문제 구성 파일을 기반으로 조건부로 템플릿을 렌더링해야하므로 템플릿의 이름을 미리 알지 못합니다. 필자는 FuncMap에 별도의 템플릿 파싱 및 호출을 수행하고 그 결과를 반환하는 함수를 넣을 수 있지만 더 나은 방법이 있는지 궁금해하고 있습니다.

+0

@ Boushley gotcha. 내가 방금 사용했던 솔루션을 제공하는 방금 게시 한 다른 대답을 참조하십시오. –

+1

그동안 답변이 있으십니까? – Kiril

+0

나는 또한 그것을 할 방법을 찾고있다 ... – Creasixtine

답변

0

다른 접근 방법 I가 꿈과 협력 재능있는 디바이스가되었다는 템플릿을 정의하고 볼되지 않는 포함 찾기 위해 템플릿 인스턴스를 사후 처리합니다 일치하는 파일에 대한 파일 시스템을 찾고 발견 된 각각에 대해 파싱합니다. 그런 다음 렌더링합니다. 다음과 같이이 당신에게 설정을 제공

:

전망/index.html을 :

{{template "/includes/page-wrapper.html" .}} 

{{define "body"}} 
<div>Page guts go here</div> 
{{end}} 

{{define "head_section"}} 
<title>Title Tag</title> 
{{end}} 

가/페이지 wrapper.html 포함

<html> 
<head> 
{{block "head_section" .}}{{end}} 
<head> 
<body> 

{{template "body" .}} 

</body> 
</html> 

그리고 당신의 ServeHTTP() 방법을 찾습니다 파일을 "views"디렉토리에로드하고 파싱 한 다음 TmplIncludeAll() (아래)을 호출합니다.

다음과 같은 몇 가지 기능만으로 동일한 기본 개념을 적용했습니다. t은 파싱 된 후 렌더링되기 전의 템플릿입니다. fs은 "보기"및 "포함"라이브 (위 참조)가있는 디렉토리입니다.

func TmplIncludeAll(fs http.FileSystem, t *template.Template) error { 

    tlist := t.Templates() 
    for _, et := range tlist { 
     if et != nil && et.Tree != nil && et.Tree.Root != nil { 
      err := TmplIncludeNode(fs, et, et.Tree.Root) 
      if err != nil { 
       return err 
      } 
     } 
    } 

    return nil 
} 

func TmplIncludeNode(fs http.FileSystem, t *template.Template, node parse.Node) error { 

    if node == nil { 
     return nil 
    } 

    switch node := node.(type) { 

    case *parse.TemplateNode: 
     if node == nil { 
      return nil 
     } 

     // if template is already defined, do nothing 
     tlist := t.Templates() 
     for _, et := range tlist { 
      if node.Name == et.Name() { 
       return nil 
      } 
     } 

     t2 := t.New(node.Name) 

     f, err := fs.Open(node.Name) 
     if err != nil { 
      return err 
     } 
     defer f.Close() 

     b, err := ioutil.ReadAll(f) 
     if err != nil { 
      return err 
     } 

     _, err = t2.Parse(string(b)) 
     if err != nil { 
      return err 
     } 

     // start over again, will stop recursing when there are no more templates to include 
     return TmplIncludeAll(fs, t) 

    case *parse.ListNode: 

     if node == nil { 
      return nil 
     } 

     for _, node := range node.Nodes { 
      err := TmplIncludeNode(fs, t, node) 
      if err != nil { 
       return err 
      } 
     } 

    case *parse.IfNode: 
     if err := TmplIncludeNode(fs, t, node.BranchNode.List); err != nil { 
      return err 
     } 
     if err := TmplIncludeNode(fs, t, node.BranchNode.ElseList); err != nil { 
      return err 
     } 

    case *parse.RangeNode: 
     if err := TmplIncludeNode(fs, t, node.BranchNode.List); err != nil { 
      return err 
     } 
     if err := TmplIncludeNode(fs, t, node.BranchNode.ElseList); err != nil { 
      return err 
     } 

    case *parse.WithNode: 
     if err := TmplIncludeNode(fs, t, node.BranchNode.List); err != nil { 
      return err 
     } 
     if err := TmplIncludeNode(fs, t, node.BranchNode.ElseList); err != nil { 
      return err 
     } 

    } 

    return nil 
} 

이것은 내가 가장 좋아하는 방법이며 지금 당분간 이것을 사용해 왔습니다. 템플릿 렌더링이 하나 뿐이므로 오류 메시지가 훌륭하고 깨끗하며 Go 템플리트 마크 업은 매우 읽기 쉽고 분명합니다. html/template의 용기가 있다면 좋을 것입니다.템플릿을 사용하면 구현이 간단 해졌지만 전반적으로 IMO는 훌륭한 솔루션입니다.

6

또 다른 방법은 아마도 더 좋은 방법은 아니지만 동일한 템플릿을 제공하는 별도의 템플릿 파일을 만드는 것입니다. 다음

{{define "body"}} 
    This will be in the body 
{{end}} 

그리고 코드에서 병합 : 당신이 할 각 페이지에서

<html> 
    ... 
    <body> 
    {{template "body" .}} 
    </body> 
</html> 

: A와

func compileTemplate(layout, name string) (*template.Template, error) { 
    tpl := template.New(name) 
    tpl, err := tpl.ParseFiles(
     "views/layouts/"+layout+".htm", 
     "views/"+name+".htm", 
    ) 
    if err != nil { 
     return nil, err 
    } 
    return tpl, nil 
} 
+0

흥미 롭다 - 특히 내 문제를 해결하지는 못하지만, 그렇다면 어떤 경우에는 유용 ​​할 수있는 또 다른 접근법입니다. 그러나 어쨌든 고마워. –

7

예를 들어 당신이 공유 웹 페이지의 레이아웃이 있다고 가정 이것에주의하고 후속 조치를 취하기 위해 필자는 결국이 질문에 대한 두 가지 주요 대답으로 끝 맺었습니다. 1) 이것을 피하십시오. 여러 경우에 간단한 if 문이 잘 작동했습니다. 2) FuncMap에서 별도의 렌더링을 수행하는 함수를 사용하여이 작업을 수행 할 수있었습니다. 세계에서 가장 위대한 것은 아니지만 문제를 해결하고 해결합니다. 여기에 아이디어를 보여 전체 독립형 데모는 다음과 같습니다

package main 

import (
    "bytes" 
    "html/template" 
    "os" 
) 

func main() { 

    var err error 

    // our main template here calls a sub template 
    tpl := template.New("main") 

    // provide a func in the FuncMap which can access tpl to be able to look up templates 
    tpl.Funcs(map[string]interface{}{ 
     "CallTemplate": func(name string, data interface{}) (ret template.HTML, err error) { 
      buf := bytes.NewBuffer([]byte{}) 
      err = tpl.ExecuteTemplate(buf, name, data) 
      ret = template.HTML(buf.String()) 
      return 
     }, 
    }) 

    // this is the main template 
    _, err = tpl.Parse(` 

{{$Name := "examplesubtpl"}} 

from main template 

{{CallTemplate $Name .}} 

`) 
    if err != nil { 
     panic(err) 
    } 

    // whatever code to dynamically figure out what templates to load 

    // a stub just to demonstrate 
    _, err = tpl.New("examplesubtpl").Parse(` 

this is from examplesubtpl - see, it worked! 

`) 
    if err != nil { 
     panic(err) 
    } 

    err = tpl.Execute(os.Stdout, map[string]interface{}{}) 
    if err != nil { 
     panic(err) 
    } 

} 
관련 문제