Erlydtl:有没有办法在模板中呈现记录列表?

时间:2014-05-16 15:24:08

标签: templates erlang

例如我有:

-record(usr,{name,email}).
...
Usr1 = #usr{name="John", email="john@host.com"},
Usr2 = #usr{name="Jane", email="jane@host.com"},
Usr3 = #usr{name="Alex", email="alex@host.com"},
{ok, Result} = template_dtl:render([{users, [Usr1, Usr2, Usr3]}]),
...

我希望像以下一样使用它:

{% block content %}
{% for user in users %}
<a href="mailto:{{user.email}}">Send mail to {{user.name}}</a>
{% endfor %}
{% endblock %}

有人遇到同样的问题吗?

1 个答案:

答案 0 :(得分:4)

记录是元组之上的语法糖Usr1Usr2Usr3只是元组,正是:

Usr1 = {usr, "John", "john@host.com"},
Usr2 = {usr, "Jane", "jane@host.com"},
Usr3 = {usr, "Alex", "alex@host.com"}.

模板不知道如何解释这些记录,因为它在编译时不知道记录定义。

您的问题有三种解决方案。在所有情况下,模板都是相同的,您应该像处理user.emailuser.name一样。

教你erlydtl关于你的记录

record_info编译选项正好用于告诉erlydtl模板变量中使用的记录。

erlydtl:compile_template(Template, TemplateModuleName, [{record_info, [{usr, record_info(fields, usr)}]).

缺点是您可能不会自己致电erlydtl:compile*,因此添加record_info选项可能会很困难。此外,调用此函数的代码段必须知道您可能必须移动到.hrl文件的记录定义。

将您的记录转换为dict:dict(),proplist()或gb_trees:tree()

这是Soup d'Campbells在评论中建议的内容。您还可以使用编译时函数record_info/2来实现此目的。最简单的是proplist()形式:

lists:zip(record_info(fields, usr), tl(tuple_to_list(Usr1))).

tuple_to_list(Usr1)评估为[usr, "John", "john@host.com"],而record_info(fields, usr)等于[name, email]

在模块中封装数据

使用公共访问器(user.name)捕获数据结构的记录并不是很好,因为它们可以更好地在本地维护给定模块,因为这样可以更轻松地进行代码更新。或者,您可以定义一个模块(称为usrapp_user但不是user,因为这样一个模块已经存在),它将导出name/1email/1个访问者。

这里的Erlydtl魔术是基于以前称为参数化模块的功能,更准确地说是使用元组而不是原子作为模块名称来调用函数的能力。您不需要参数化模块,只需传递与现有模块匹配的元组。

例如,您的app_user模块可能如下所示:

-module(app_user).
-export([new/2, name/1, email/1]).
-record(?MODULE, {name :: string(), email :: string()}). % private to this module.
-type app_user() :: #?MODULE{}.

-spec new(string(), string()) -> app_user().
new(Name, Email) -> #?MODULE{name = Name, email = Email}.

-spec name(app_user()) -> string().
name(#?MODULE{name = Name}) -> Name.

-spec email(app_user()) -> string().
email(#?MODULE{email = Email}) -> Email.

?MODULE代替app_user,因为只有当记录的名称与模块名称匹配时才有效,即使重命名模块,此代码仍然有效。“

然后,在您的代码中,而不是:

Usr1 = #usr{name = "John", email = "john@host.com"}

你会写:

Usr1 = app_user:new("John", "john@host.com").

Usr1只是一个记录,或者更确切地说是元组:

{app_user, "John", "john@host.com"}.

然而,Erlydtl将能够直接处理Usr1。它会将其视为参数化模块,因为app_user作为模块存在(它是上面的模块)。因此,在模板渲染期间,它将调用app_user:name/1app_user:email/1访问器函数,并将整个记录传递给它们。