Golang模板的FuncMap可以调用自身。

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

Golang template FuncMap that can call itself

问题

我正在尝试实现一个函数,将其添加到基本模板的FuncMaps中,该函数应用于渲染可重用的视图组件。

例如:

func (v *Item) RenderComponent(componentPath string, vars ...interface{}) template.HTML {
    p := path.Join(v.folder, "components", componentPath)

    // 获取组件路径的各个部分
    componentPathPieces := strings.Split(p, "/")

    // 获取部分中的最后一项(应该是文件名)
    componentFileName := componentPathPieces[len(componentPathPieces)-1]

    // 使用组件文件名创建新模板,并添加FuncMap函数
    t := template.New(componentFileName).Funcs(v.funcMap)

    // 检查模板语法是否有错误
    t, err := template.ParseFiles(p + "." + v.extension)
    if err != nil {
        panic(err)
    }

    // 将变量添加到组件中,并将结果写入缓冲区
    b := new(bytes.Buffer)
    if err = t.Execute(b, vars); err != nil {
        panic(err)
    }

    // 将模板缓冲区的内容作为HTML字符串返回
    return template.HTML(b.String())
}

这段代码对于不渲染其他组件的组件来说是正常工作的。例如,我可以写{{component "buttons/default-button" "some url goes here"}},它会正常渲染位于components/button/default-button.tmpl的组件。

然而,如果我在default-button组件中包含另一个组件,比如{{component "icons/check-icon"}},我会得到一个很长的错误(太长无法在此处粘贴)。但是这里是其中一个错误消息:

template: default-button.tmpl:4: function "component" not defined

如你所见,错误是从试图调用另一个组件的组件文件中抛出的。我认为这是因为viewFunc要么没有被正确添加,要么以某种方式被递归调用了。

英文:

I am trying to achieve a function to add to FuncMaps in a base template, and this function should be used to render re-useable view components

For instance:

func (v *Item) RenderComponent(componentPath string, vars ...interface{}) template.HTML {
	p := path.Join(v.folder, "components", componentPath)

	// Get the pieces of the component path.
	componentPathPieces := strings.Split(p, "/")

	// Get the last item in the pieces (this should be the file name).
	componentFileName := componentPathPieces[len(componentPathPieces)-1]

	// Make the new template using component file name and add FuncMap functions.
	t := template.New(componentFileName).Funcs(v.funcMap)

	// Determine if there is an error in the template syntax.
	t, err := template.ParseFiles(p + "." + v.extension)
	if err != nil {
		panic(err)
	}

	// Add variables to the component and write to a buffer.
	b := new(bytes.Buffer)
	if err = t.Execute(b, vars); err != nil {
		panic(err)
	}

	// Return the contents of the template buffer as a string of HTML.
	return template.HTML(b.String())
}

This code works just fine for a component that doesn't render another component. For example, I can write {{component "buttons/default-button" "some url goes here"}} and it will render the component at components/button/default-button.tmpl just fine.

However, if I include another component within that default-button component, such as {{component "icons/check-icon"}}, I will get a large error (too big to paste here). But here is one of the error messages:

> template: default-button.tmpl:4: function "component" not defined

As you can see, the error is thrown from the component file that is trying to call another component. I believe that happens because the viewFunc is either not being properly added, or is being recursively called in some way.

答案1

得分: 2

翻译结果如下:

哎呀,看起来我打错了字。

需要将这段代码修改为:

// 使用组件文件名创建新模板,并添加FuncMap函数。
t := template.New(componentFileName + "." + v.extension).Funcs(v.funcMap) // <---- 将'componentFileName'修改为'componentFileName + "." + v.extension'

// 检查模板语法是否有错误。
t, err := t.ParseFiles(p + "." + v.extension) // <---- 将'template'修改为't'

我之前引用了template包而不是我创建的t模板。我还传入了错误的名称给template.New,因为它期望一个完整的文件名,比如index.tmpl,而不仅仅是index

现在一切都按预期工作了!可以从另一个组件调用组件。

英文:

Oops, looked like I had a typo.

Had to change this:

// Make the new template using component file name and add FuncMap functions.
t := template.New(componentFileName).Funcs(v.funcMap)

// Determine if there is an error in the template syntax.
t, err := template.ParseFiles(p + &quot;.&quot; + v.extension)

...to this:

// Make the new template using component file name and add FuncMap functions.
t := template.New(componentFileName + &quot;.&quot; + v.extension).Funcs(v.funcMap) // &lt;---- &#39;componentFileName&#39; to &#39;componentFileName + &quot;.&quot; + v.extension&#39;

// Determine if there is an error in the template syntax.
t, err := t.ParseFiles(p + &quot;.&quot; + v.extension) // &lt;---- &#39;template&#39; to &#39;t&#39;

I was referencing the template package instead of the t template that I created. I also passed in the wrong name for template.New, since that expects a full fill such as index.tmpl, instead of just index.

Now everything works as expected! Can call component from another component.

huangapple
  • 本文由 发表于 2017年4月8日 01:47:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/43284246.html
匿名

发表评论

匿名网友

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

确定