2013-10-15 3 views
0

이동에 html/template을 사용하여 템플릿을 삽입하는 것에 대해 머리를 쓰려고합니다. 나는 논리가없는 템플릿 디자인과 매우 흡사하며 예상대로 안전하게 탈출 할 수있는 능력에 확신을 가지고있다.Go-html/template, template.ParseGlob() 및 코드 재사용

그러나 "최종"템플릿 이름을 기반으로 HTTP 처리기에서 내 템플릿을 렌더링하는 데 약간의 도우미를 구현하는 데 문제가 있습니다. 내 base.tmpl은 모든 페이지에서 효과적으로 "표준"이며, 그렇지 않은 경우 base.tmpl에 {{ template checkoutJS }}을 설정하고 {{ define checkoutJS }}https://path.to/extra.js {{ end }}을 설정하여 페이지 당 JS를 추가 할 수 있습니다.

나는 data 내가 채우기 위해 원하는대로와 문자열이나 구조체를 포함하는지도 [문자열] 인터페이스 {} 내 HTTP 처리기에서 renderTemplate(w, "template_name.tmpl", data) 말을 할 수있게하려면 여기

지금까지 코드입니다. :

base.tmpl

{{ define "base" }} 
<!DOCTYPE html> 
<html lang="en"> 
<head> 
<title>{{ template "title" . }}</title> 
</head> 
<body> 
<div id="sidebar"> 
... 
</div> 

{{ template "content" }} 

<div id="footer"> 
... 
</div> 
</body> 
</html> 

create_listing.tmpl

{{ define "title" }}Create a New Listing{{ end }} 

{{ define "content" }} 

<form> 
    ... 
</form> 

{{ end }} 

login_form.tmpl

{{ define "title" }}Login{{ end }} 

{{ define "content" }} 

<form> 
    ... 
</form> 

{{ end }} 

main.go

package main 

import (
    "fmt" 
    "github.com/gorilla/mux" 
    "html/template" 
    "log" 
    "net/http" 
) 

// Template handling shortcuts 
var t = template.New("base") 

func renderTemplate(w http.ResponseWriter, tmpl string, data map[string]interface{}) { 

    err := t.ExecuteTemplate(w, tmpl, data) 

    // Things will be more elegant than this: just a placeholder for now! 
    if err != nil { 
     http.Error(w, "error 500:"+" "+err.Error(), http.StatusInternalServerError) 
    } 
} 

func monitorLoginForm(w http.ResponseWriter, r *http.Request) { 

    // Capture forms, etc. 

    renderTemplate(w, "login_form.tmpl", nil) 
} 

func createListingForm(w http.ResponseWriter, r *http.Request) { 

    // Grab session, re-populate form if need be, generate CSRF token, etc 

    renderTemplate(w, "create_listing.tmpl", nil) 
} 

func main() { 

    r := mux.NewRouter() 

    r.HandleFunc("/monitor/login", monitorLoginForm) 

    http.Handle("/", r) 
    log.Fatal(http.ListenAndServe(":8000", nil)) 

} 

func init() { 

    fmt.Println("Starting up.") 
    _, err := t.ParseGlob("templates/*.tmpl") 
    if err != nil { 
     log.Fatal("Error loading templates:" + err.Error()) 
    } 
} 

이 컴파일,하지만 난 다시 내 핸들러에서 빈 응답을 얻을. 두 번째 처리기에 대한 경로가 없다는 점에 유의하십시오.이 코드는 핸들러에서 renderTemplate()을 호출하는 방법을 보여주기위한 것입니다.

답변

2

현재 진행중인 템플릿 패키지로 원하는 것을 수행 할 수 없습니다. 템플릿에는 상속이 없으므로 템플릿에있는 것과 같은 명명 된 블록이 없습니다. 기본 템플릿을 정의하는 대신 머리글 및 바닥 글 템플릿을 정의하는 것이 더 일반적입니다. 그런 다음 페이지 템플리트에서 사용자가 원하는 곳으로 명시 적으로 포함하십시오.

다른 해결책으로는 2 단계 템플릿 단계가 있다고 생각합니다. 첫 번째는 기본 템플릿의 모든 블록에 대한 템플릿을 컴파일하는 것입니다. 이것들은 맵에 추가 된 다음 기본 템플리트로 보내져 포함됩니다.

+0

감사합니다. 테스트 용도 이외의 이유로 단일 기본 템플릿을 사용하고있었습니다. 나는 이것을'header.tmpl'과'footer.tmpl'로 나누었습니다. 이제 작동합니다. – elithrar

+0

또한 템플릿에서'{{title}} '을 다시 정의 할 수없는 것 같습니다. 'header.tmpl'에'login_form.tmpl'이나'create_listing.tmpl'과 같은 내용 템플리트에서 제목을 설정하는 더 좋은 방법이 있습니까? – elithrar

+0

'{{template "header.tmpl"}}}''Title' 속성을'.'에 정의 할 수 있습니다. – mjibson

1

이 꽤 비 명백하다, 그리고 나는 그들이이

ParseGlob처럼 할 이유를 모르는 당신이 버리고있는 값을 반환하지만 당신은 그것을 유지할 필요가; 당신이 호출 할 필요가 템플릿 개체, 그래서 코드은 다음과 같은 모양입니다 :

func init() { 
    fmt.Println("Starting up.") 
    t, err := template.ParseGlob("templates/*.tmpl") 
    if err != nil { 
    log.Fatal("Error loading templates:" + err.Error()) 
    } 
} 

그것이 연관 있다고으로 (위에서 사용 된 라이브러리 함수와 반대)하는 방법에 대한 설명서는 조금 불분명하다 메서드가 호출되는 템플릿 객체가있는 템플릿이지만 템플릿 객체에 대한 포인터를 반환합니다.이 객체는 광고 된 것처럼 작동 할 필요가 없습니다. 장난!

+0

불행히도 이것은 트릭을 수행하지 않습니다. 나는 아직도 빈 반응을 얻는다. – elithrar

+1

오른쪽 * 소매를 감습니다 * 다른 모양을 보겠습니다 ... 아하! 내 나쁜 ... 파일에 정의 된 템플릿 이름이 아닌 파일 이름을 사용하여 템플릿을 호출하고 있습니다. 따라서 템플릿 파일 이름을 RenderTemplate에 전달하는 대신'{{define templateName}} '문에 정의 된대로 실제 템플릿 이름을 전달하십시오 – mfhholmes