我创建了一个函数来检查是否定义了变量:

1
2
3
4
5
6
7
8
9
10
11
12
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)

在模板中,我有:

1
2
3
{{ if isset .Email }}
    email is set
{{ end }}

如果变量包含在templateData中(此自定义结构包含映射和字符串),则此函数有效,但是如果变量不存在,则会给我一个错误。

错误是:

1
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 }},但这也给了我同样的错误。

任何的想法?

  • 尝试在isset函数中登录a。你看到你在传递什么吗?如果不是,则在模板级别存在问题。也许尝试同时传入struct和键以访问它以检查isset,然后相应地修改函数以同时接收两个参数。
  • 如果我的结构包含"电子邮件",它将起作用,并将其记录在isset函数中。如果该结构不包含"电子邮件"(这是我的情况),它将仅从上面输出错误,而不会显示issset函数的日志。
  • PHP具有isset($ variable)函数,该函数返回true / false,那么GO呢?如何检查模板中的变量以查看其是否从处理程序发送?例如,我只想在用户登录后才显示菜单。
  • 只需尝试{{ if .Email }},它应该对您有用。
  • 我也尝试使用:{{if .Email}}做{{end}},但这也给我同样的错误。我没有发送"电子邮件"到模板。 Sheldnt if返回false而不是抛出错误?
  • 什么是base.customData
  • base是处理程序," base.go",customData是包含映射(" Streets")和字符串(" Name")的结构。如果我在名为" Email"的" customData"结构中添加新字符串,则{{if isset .Email}}函数和{{if .Email}}都可以使用。因此,仅当我不发送在模板上检查的数据时,才会出现问题。
  • 在这里看看。
  • 很好的例子。我根据在该页面上看到的内容创建了" isset"函数。我没有使用gohugo(静态网站生成器),因此您在其中看到的所有内容都是自定义代码,这些代码无法在简单/简单的go模板上运行。请参阅我对问题的回答。现在,我不再需要使用" isset"功能。

推荐方式

首先,推荐的方法是不要依赖于结构域是否存在。当然,模板中可能有可选部分,但是决定是否渲染零件的条件应取决于所有情况下都存在的字段。

问题,并避免使用地图

如果模板数据的类型为struct(或指向结构的指针),并且没有具有给定名称的字段或方法,则模板引擎将为此返回错误。

如果要使用地图,则可以轻松摆脱该错误,因为可以使用地图不包含的键对地图进行索引,并且该索引表达式的结果是值类型的零值(而不是错误) 。

为了演示,请参见以下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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("\
%s:\
 ", 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:"as@as.com"})
exec("Empty struct", struct{}{})

输出(在Go Playground上尝试):

1
2
3
4
5
6
7
8
Filled map:
  Email is: as@as
Empty map:
  Email is NOT set.
Filled struct:
  Email is: as@as.com
Empty struct:
  Error: template: :1:5: executing"" at <.Email>: can't evaluate field Email in type struct {}

坚持struct并提供" isset"

如果您必须或想坚持使用struct,则可以实现并提供此" isset",我将其称为avail()

此实现使用反射,并且为了检查其名称给定的字段是否存在(可用),还必须将(包装器)数据传递给它:

1
2
3
4
5
6
7
8
9
10
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()
}

使用它的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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("\
%s:\
 ", name)
    if err := t.Execute(os.Stdout, param); err != nil {
        fmt.Println("Error:", err)
    }
}

exec("Filled struct", struct {
    Email string
}{Email:"as@as.com"})
exec("Empty struct", struct{}{})

输出(在Go Playground上尝试):

1
2
3
4
Filled struct:
  Email is: as@as.com
Empty struct:
  Email is unavailable.
  • 如果地图中的条目的值为false,则该地图方法将不起作用(即,它打印"未设置电子邮件"。而不是"电子邮件为:false")

简单的方法是:

1
{{ if .Email }}

是使用索引:

1
{{ if index ."Email" }}
  • 我不知道这是如何工作的。 请解释? AFAICT索引将对非枚举错误

如果不将包含变量的数据发送到模板,但是使用{{ if .Variable }},则会收到错误消息:

executing"templatename" at <.Variable>: can't evaluate field Variable in type handler.Data

我的解决方案是将" Email"变量作为布尔值(false)发送,以便通过{{ if .Email }}函数检查。但这是我不喜欢的短期解决方案。

我的灵感来自于:https://stackoverflow.com/a/31527618/1564840。在该示例中,它们为经过身份验证的用户和未经身份验证的用户显示了不同的HTML。您将看到,在两种情况下,它们都发送" Logged"变量。尝试从结构中删除该变量并执行功能。您将收到我上面提到的错误。