在循环的把手装饰员

时间:2016-07-01 15:26:29

标签: javascript templates handlebars.js decorator

几天后,我开始使用Handlebars,我正在尝试装饰器。当它仍然很简单时,我已经理解它是如何工作的: 例如:单独装饰名称:bill gaTes - >比尔盖茨先生

然后我尝试在"每个"中使用装饰器。循环,做与以前完全相同但使用人员列表而不是一个人。问题是:当我在装饰器函数中时,我需要知道我正在查看哪个元素(来自数组)。

所以我想要论证"每个"的索引。循环(然后,因为我可以访问数据,我可以检索当前元素)或当前元素。

我尝试使用@index(通常效果很好),但在调试时我得到了未定义。 我无法找到一种方法来获取装饰器中的当前元素。

以下是代码:

的index.html

<!doctype html>
<html>
    <head>  
        <title>Test Handlebars Decorators 4</title>
    </head>
    <body>
        <div id = "main"> </div>

        <script id = "rawTemplate" type = "text/x-handlebars-template">

            {{#each this}}
                Decorated: {{formatGenderHelper this}}
                {{* activateFormatter @index}}
                <br />
            {{/each}}

        </script>

        <script type = "text/javascript" src = "js/lib/handlebars.min-latest.js"></script>
        <script type = "text/javascript" src = "js/lib/jquery-2.2.4.min.js"></script>
        <script type = "text/javascript" src = "js/data.js"></script>
        <script type = "text/javascript" src = "js/index.js"></script>
    </body>
</html>

data.js

var data = [{
    "firstname": "Bill",
    "lastname": "Gates",
    "gender": "MALE"
}, {
    "firstname": "Hillary",
    "lastname": "Clinton",
    "gender": "FEMALE"
}];

function formatMale(author) {
    return "M. " + author.firstname + " " + author.lastname.toUpperCase();
}
function formatFemale(author) {
    return "Mme " + author.firstname + " " + author.lastname.toUpperCase();
}

Handlebars.registerDecorator('activateFormatter', function(program, props, container, context) {
    var genderHelper;
    var gender = context.args[0] || context.data.root[0].gender;

    switch(gender) {
        case "MALE":
            genderHelper = formatMale;
            break;
        case "FEMALE":
            genderHelper = formatFemale;
            break;
        default:
            console.log('Gender format not set. Please set before rendering template.');
            genderHelper = function() {};
    }

    container.helpers = {
        formatGenderHelper: genderHelper
    };
});

index.js

// Get the template
var rawTemplate = $('#rawTemplate').html();

// Compile the template
var compiledTemplate = Handlebars.compile(rawTemplate);

// Apply the template on the data
var content = compiledTemplate(data);

// Finally, re-inject the rendered HTML into the DOM
$('#main').html(content);

如果您需要更多信息,请告诉我。

感谢您的帮助:)。

1 个答案:

答案 0 :(得分:2)

有两个问题会导致您的示例失败。一个是你的代码的一个小问题,另一个是装饰器似乎工作的方式,这实际上只是“不在循环中”(除非你使用部分,请参阅本答案的最后一部分)。

首先,你没有告诉装饰者如何处理你传递给它的@index。您可以更改装饰器功能,但由于您在#each块中有装饰器,this与传递给formatGenderHelper的装置相同,这意味着我们可以传递装饰器{ {1}}只解析为性别字符串。这意味着模板的编写者确切地知道他们传递给装饰器的内容,并且逻辑并不是试图猜测模板告诉它的内容。

<强>的index.html

this.gender
  

另外,我认为你的例子基于Ryan Lewis's sitepoint demo。他的代码有一个问题/限制并不是很明显(因为在简单的情况下它甚至不是问题),他的装饰器会覆盖所有可用的助手,除了它提供的格式。为了避免“错误:TypeError:在执行稍微复杂的事情时无法读取未定义的属性'调用'错误,我建议在装饰器函数中使用它。

     

<强> data.js

...
{{#each this}}
    Decorated: {{formatGenderHelper this}}
    {{* activateFormatter this.gender}}
    <br />
{{/each}}
...

第二个问题是在循环中使用装饰器的一般问题,这只是Handlebars与装饰器一起使用的结果。根据{{​​3}},

  

当块程序被实例化并被传递(程序,道具,容器,上下文,数据,块参数,深度)时,将执行装饰器。

这意味着(afaict)当首先实例化块的模板时,意味着需要在块上运行的任何其他助手或程序之前,它执行装饰器,装饰器进行它需要的修改,在执行创建块的程序(在本例中为 Handlebars.registerDecorator('activateFormatter', function(program, props, container, context) { // leaving out the code here for brevity container.helpers = Object.assign({}, container.helpers, { formatGenderHelper: genderHelper }); }); 之前。这意味着要让装饰器以不同的方式区分#each的每个迭代,它需要在#each的孙子块中运行,因此它在#each之后但在但是,#each,如果您正在执行此操作并根据迭代上下文重新定义每次迭代的装饰助手,则最好只注册一个已填充性别格式逻辑的助手。

然而,这是一种不答案。所以,为了回答你的问题,我发现你 可以 让把手做你正在尝试做的事情,但这有点像黑客。由于技巧是你需要从formatGenderHelper的子子块渲染装饰器的块,我们可以将其渲染为局部。要做到这一点,我们可以将它粘贴在另一个文件中并将其注册为部分文件,但这并不是很方便,所以我们有两个更好的选择。 1)我们可以将代码包装在未定义的部分块中,并让Handlebars在部分失败时将其渲染为回退块,或者(滑动选项)2)我们可以使用提供的内置装饰器#each来定义内联部分。

  1. 故障转移部分阻止方法

    <强>的index.html

    #*inline
  2. ... {{#each this}} {{#>nothing}} Decorated: {{formatGenderHelper this}} {{* activateFormatter this.gender}} <br /> {{/nothing}} {{/each}} ... 方法

    <强>的index.html

    #*inline
  3. 这里的关键是我们使用... {{#*inline "formattedAuthor"}} Decorated: {{formatGenderHelper this}} <br /> {{/inline}} {{#each this}} {{#>formattedAuthor}} {{* activateFormatter this.gender}} {{/formattedAuthor}} {{/each}} ... 装饰器在每次调用时动态地重新配置部分。第二个内联示例更清楚地说明了这一点。当然可能还有其他很好的用例,但这是我看到装饰器真正闪亮的地方,即允许我们从我们称之为的地方动态地重新配置部分的逻辑或帮助。

    然而,有一个警告:如果我们的部分使用一个助手,它只在从该部分定义之外调用的装饰器中提供(就像我们在上面的例子中那样 2 )如果没有在正确的位置调用装饰器,则部分将无法找到帮助器。这也是为什么最好使用上面两种方法中的任何一种来提供部分:我们将部分的定义保持在与装饰器调用相同的文件中,因此我们可以知道帮助程序仅动态提供而不是全局注册