Golang模板 – 在范围循环内使用模板变量作为全局变量

huangapple go评论90阅读模式
英文:

Golang Template - Use Template Variable As Global Variable From Within Range Loop

问题

我会尽量简单地解释。
我在Golang中有两个变量,它们被解析到模板文件中。

这是我声明变量的Golang代码:

for _, issue := range issues {
    issueIDStr := strconv.Itoa(*issue.ID)
    parse[*issue.ID] = issueIDStr 
    parse[issueIDStr+"-label"] = "blah blah"
}

然后在我的HTML文件中:

{{ range .issues }}
    <!-- 这里我想要使用当前问题的ID作为一个在range循环之外的全局变量 -->
    <!-- 根据Golang文档的说法,当执行开始时,$被设置为传递给Execute的数据参数,也就是dot的初始值 -->
    <!-- 我可以使用$.Something来访问range循环之外的变量,但是如何将模板变量用作全局变量呢?我尝试了以下代码,但不起作用 -->
    {{ $ID := .ID }}
    <p>{{ index $.$ID "author" }}</p>
{{ end }}

运行这段代码后,我得到了错误信息:bad character U+0024 '$',并且抛出了一个panic。

我现在尝试将这段代码翻译成中文,希望对你有所帮助。

英文:

I will try to make this as simple as possible.
I have two variables in Golang which are parsed to the template file.

Here is my Golang code which declares the variables:

for _, issue := range issues {
    issueIDStr := strconv.Itoa(*issue.ID)
    parse[*issue.ID] = issueIDStr 
    parse[issueIDStr+&quot;-label&quot;] = &quot;blah blah&quot;
}

Then in my HTML file:

{{ range .issues }}
    &lt;!-- Here I want to use the current issue&#39;s ID as a global variable which is outside the range loop --&gt;
    &lt;!-- According to the Golang doc which says the following:
             When execution begins, $ is set to the data argument passed to Execute, that is, to the starting value of dot.
         I can use $.Something to access a variable outside my range loop right...
         but how can I use a template variable as a global variable? I tried the following which doesn&#39;t work.
    {{ $ID := .ID }}
    &lt;p&gt;{{ index $.$ID &quot;author&quot; }}&lt;/p&gt;
{{ end }}

After running this code, I get the error: bad character U+0024 &#39;$&#39; along with a panic thrown.

Is what I am attempting completely impossible currently, or is there some trick I am missing?

Thanks Golang模板 – 在范围循环内使用模板变量作为全局变量

答案1

得分: 1

你应该简单地创建一个包含issues数组的map[string]interface{},然后将其用作模板执行数据。

然后你可以循环遍历issues,并直接从模板中访问其成员。

这是一个完整的小例子:

const t = `
{{ range .issues }}
issue: {{ .ID }}
	author: {{ .Author }}
{{ end }}
`

type Issue struct {
	ID     int
	Author string
}

func main() {
	issues := []Issue{{1, "Pepe"}, {2, "Cholo"}}
	data := map[string]interface{}{"issues": issues}
	tpl := template.Must(template.New("bla").Parse(t))
	tpl.Execute(os.Stdout, data)
}

输出结果为:

issue: 1
	author: Pepe

issue: 2
	author: Cholo

此外,如果你想要/需要添加特定于模板渲染过程的数据,你应该为此目的定义一个"rich"的issue结构,并在传递给模板执行之前转换你的模型。这可以用于静态已知的额外数据(作为RichIssue的简单成员)和动态加载的数据(作为map的键/值对)。

这是一个扩展示例,展示了上述建议:

const t = `
{{ range .issues }}
issue: {{ .ID }}
	author: {{ .Author }}
	static1: {{ .Static1 }}
	dyn1: {{ .Data.dyn1 }}
{{ end }}
`

type Issue struct {
	ID     int
	Author string
}

type RichIssue struct {
	Issue
	Static1 string                 // 用于渲染的一些静态已知附加数据
	Data    map[string]interface{} // 动态数据的容器(如果需要)
}

func GetIssueStatic1(i Issue) string {
	return strconv.Itoa(i.ID) + i.Author // 随便什么
}

func GetIssueDyn1(i Issue) string {
	return strconv.Itoa(len(i.Author)) // 随便什么
}

func EnrichIssue(issue Issue) RichIssue {
	return RichIssue{
		Issue:   issue,
		Static1: GetIssueStatic1(issue),
		// 在这个假设的例子中,我从静态硬编码字符串构建“动态”成员
		// 但这些字段(名称和数据)应该来自某种配置或查询结果,
		// 以实际上是动态的(并且有理由在map中设置而不是作为简单的静态成员,如Static1)
		Data: map[string]interface{}{
			"dyn1": GetIssueDyn1(issue),
			"dyn2": 2,
			"dyn3": "blabla",
		},
	}
}

func EnrichIssues(issues []Issue) []RichIssue {
	r := make([]RichIssue, len(issues))
	for i, issue := range issues {
		r[i] = EnrichIssue(issue)
	}
	return r
}

func main() {
	issues := []Issue{{1, "Pepe"}, {2, "Cholo"}}
	data := map[string]interface{}{"issues": EnrichIssues(issues)}
	tpl := template.Must(template.New("bla").Parse(t))
	tpl.Execute(os.Stdout, data)
}

输出结果为:

issue: 1
author: Pepe
static1: 1Pepe
dyn1: 4
issue: 2
author: Cholo
static1: 2Cholo
dyn1: 5
英文:

You should simply make a map[string]interface{} containing the issues array and then use that as the template execution data.

Then you can loop over the issues and directly access its' members from the template.

Here's a small complete example:

const t = `
{{ range .issues }}
issue: {{ .ID }}
author: {{ .Author }}
{{ end }}
`
type Issue struct {
ID     int
Author string
}
func main() {
issues := []Issue{{1, &quot;Pepe&quot;}, {2, &quot;Cholo&quot;}}
data := map[string]interface{}{&quot;issues&quot;: issues}
tpl := template.Must(template.New(&quot;bla&quot;).Parse(t))
tpl.Execute(os.Stdout, data)
}

Which outputs:

issue: 1
	author: Pepe

issue: 2
	author: Cholo

Additionally if you want/need to add data specific to the template rendering process you should define a "rich" issue struct for this purpose and transform your model before passing it to template execution. This could be done for both statically known extra data (as simple members of RichIssue) and for dynamically loaded data (as key/values of a map).

Here's an extended example showing the above suggestions:

const t = `
{{ range .issues }}
issue: {{ .ID }}
author: {{ .Author }}
static1: {{ .Static1 }}
dyn1: {{ .Data.dyn1 }}
{{ end }}
`
type Issue struct {
ID     int
Author string
}
type RichIssue struct {
Issue
Static1 string                 // some statically known additional data for rendering
Data    map[string]interface{} // container for dynamic data (if needed)
}
func GetIssueStatic1(i Issue) string {
return strconv.Itoa(i.ID) + i.Author // whatever
}
func GetIssueDyn1(i Issue) string {
return strconv.Itoa(len(i.Author)) // whatever
}
func EnrichIssue(issue Issue) RichIssue {
return RichIssue{
Issue:   issue,
Static1: GetIssueStatic1(issue),
// in this contrived example I build &quot;dynamic&quot; members from static
// hardcoded strings but these fields (names and data) should come from
// some kind of configuration or query result to be actually dynamic
// (and justify being set in a map instead of being simple static
// members as Static1)
Data: map[string]interface{}{
&quot;dyn1&quot;: GetIssueDyn1(issue),
&quot;dyn2&quot;: 2,
&quot;dyn3&quot;: &quot;blabla&quot;,
},
}
}
func EnrichIssues(issues []Issue) []RichIssue {
r := make([]RichIssue, len(issues))
for i, issue := range issues {
r[i] = EnrichIssue(issue)
}
return r
}
func main() {
issues := []Issue{{1, &quot;Pepe&quot;}, {2, &quot;Cholo&quot;}}
data := map[string]interface{}{&quot;issues&quot;: EnrichIssues(issues)}
tpl := template.Must(template.New(&quot;bla&quot;).Parse(t))
tpl.Execute(os.Stdout, data)
}

Which produces the following output:

issue: 1
author: Pepe
static1: 1Pepe
dyn1: 4
issue: 2
author: Cholo
static1: 2Cholo
dyn1: 5

huangapple
  • 本文由 发表于 2017年1月8日 23:13:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/41534192.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定