変数が定義されているかどうかを確認する関数を作成しました。
fm["isset"] = func(a interface{}) bool {
if a == nil || a == "" || a == 0 {
fmt.Println("is not set")
return false
}
fmt.Println("is set")
return false
}
tmpl := template.Must(template.New("").Funcs(fm).ParseFiles("templates/header.html"))
err := tmpl.ExecuteTemplate(w, "header", templateData)
テンプレートでは:
{{ if isset .Email }}
email is set
{{ end }}
この関数は、変数がtemplateData
(マップと文字列を含むカスタム構造体)に含まれている場合に機能しますが、変数が存在しない場合はエラーが発生します。
エラーは:
executing "header" at <.Email>: can't evaluate field Email in type base.customData
私の場合、「base.go」がハンドラーであり、「customData」は次のように定義されます:type customData struct{..}
。
テンプレートを再利用し、ハンドラーからいくつかの変数が送信された場合にのみ一部のセクションを表示できるようにしたいと思います。テンプレート側に変数isset
チェックを実装するにはどうすればよいですか?
私も使用してみました:{{ if .Email}} do stuff {{ end }}
しかし、これでも同じエラーが発生します。
何か案が?
まず、推奨される方法は構造体フィールドが存在するかどうかに依存しないことです。もちろん、テンプレートにはオプションのパーツがあるかもしれませんが、パーツをレンダリングするかどうかを決定する条件は、すべての場合に存在するフィールドに依存する必要があります。
テンプレートデータのタイプがstruct
(または構造体へのポインター)であり、指定された名前のフィールドまたはメソッドがない場合、テンプレートエンジンはそのエラーを返します。
マップに含まれていないキーでマップにインデックスを付けることができ、その結果 インデックス式 が ゼロであるため、マップを使用する場合、このエラーを簡単に取り除くことができますvalue 値型(エラーではない)。
例として、次の例をご覧ください。
_s := `{{if .Email}}Email is: {{.Email}}{{else}}Email is NOT set.{{end}}`
t := template.Must(template.New("").Parse(s))
exec := func(name string, param interface{}) {
fmt.Printf("\n%s:\n ", name)
if err := t.Execute(os.Stdout, param); err != nil {
fmt.Println("Error:", err)
}
}
exec("Filled map", map[string]interface{}{"Email": "as@as"})
exec("Empty map", map[string]interface{}{})
exec("Filled struct", struct {
Email string
}{Email: "[email protected]"})
exec("Empty struct", struct{}{})
_
出力( Go Playground で試してください):
_Filled map:
Email is: as@as
Empty map:
Email is NOT set.
Filled struct:
Email is: [email protected]
Empty struct:
Error: template: :1:5: executing "" at <.Email>: can't evaluate field Email in type struct {}
_
struct
を守り、「isset」を提供するstruct
にこだわる必要がある、またはこだわりたい場合は、この「isset」を実装および提供できます。これをavail()
と呼びます。
この実装はリフレクションを使用し、その名前で指定されたフィールドが存在する(使用可能である)かどうかを確認するために、(ラッパー)データもそれに渡す必要があります。
_func avail(name string, data interface{}) bool {
v := reflect.ValueOf(data)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return false
}
return v.FieldByName(name).IsValid()
}
_
使用例:
_s := `{{if (avail "Email" .)}}Email is: {{.Email}}{{else}}Email is unavailable.{{end}}`
t := template.Must(template.New("").Funcs(template.FuncMap{
"avail": avail,
}).Parse(s))
exec := func(name string, param interface{}) {
fmt.Printf("\n%s:\n ", name)
if err := t.Execute(os.Stdout, param); err != nil {
fmt.Println("Error:", err)
}
}
exec("Filled struct", struct {
Email string
}{Email: "[email protected]"})
exec("Empty struct", struct{}{})
_
出力( Go Playground で試してください):
_Filled struct:
Email is: [email protected]
Empty struct:
Email is unavailable.
_
簡単な方法:
{{ if .Email }}
インデックスを使用することです:
{{ if index . "Email" }}
変数を含むデータをテンプレートに送信せず、{{ if .Variable }}
を使用すると、エラーが発生します。
<.Variable>で「templatename」を実行すると、タイプhandler.DataのフィールドVariableを評価できません
私の解決策は、{{ if .Email }}
関数チェックに合格するために、「Email」変数をブール値(false)として送信することでした。しかし、これは私が気に入らない短期的な解決策です。
https://stackoverflow.com/a/31527618/156484 に触発されました。その例では、認証されたユーザーと認証されていないユーザーに異なるHTMLが表示されます。どちらの場合も、「Logged」変数を送信することがわかります。構造体からその変数を削除して、関数を実行してみてください。上記のエラーが表示されます。