web-dev-qa-db-ja.com

ハンドルバーテンプレートを使用してさまざまなパーシャルを動的にロードするにはどうすればよいですか?

次のデータを含むテンプレートを読み込んでいます。

"slides": [
    {
        "template": "video",
        "data": {
            "video": ""
        }
    },
    {
        "template": "image",
        "data": {
            "image": ""
        }
     }
]

テンプレートでこれらのスライドをループし、構成されたテンプレートに基づいて部分をロードします

{{#each slides}}
    {{> resources_templates_overlay_video }}
{{/each}}

この部分的なロードを(構成されたテンプレートに基づいて)動的に行うにはどうすればよいですか?

require-handlebars-plugin を使用しています

18
Daan Poron

私の知る限り、hbsは、コンパイル時にパーシャルが認識されることを期待しています。これは、データを渡す前の方法です。それを回避しましょう。

まず、レンダリングする前に、次のように動的パーシャルをプルします。

// I required the main template here for simplicity, but it can be anywhere
var templates = ['hbs!resources/templates/maintemplate'], l = data.slides.length;
for (var i=0; i<l; i++ )
    templates.Push('hbs!resources/templates/overlay/'+data[i].template);

require(templates, function(template) {
    var html = template(data);
});

そして、動的パーシャルとして機能するヘルパーを定義します

define(['Handlebars'], function (Handlebars) {

    function dynamictemplate(template, context, opts) {
        template = template.replace(/\//g, '_');
        var f = Handlebars.partials[template];
        if (!f) {
            return "Partial not loaded";
        }

        return new Handlebars.SafeString(f(context));
    }

    Handlebars.registerHelper('dynamictemplate', dynamictemplate);
    return dynamictemplate;
});

最後に、メインテンプレートを次のように変更します

{{#each slides}}
    {{dynamictemplate this.template this.data}}
{{/each}}
15
nikoshr

上記の答えは少し理解しにくいと思いました-それらはグローバルをリークし、単一の文字変数を持ち、いくつかの奇妙な名前が付いています。だからここに私の(そしてあなたの)参考のために、私自身の答えがあります:

'hbs'を使用した動的パーシャル、express.jsのデフォルトのハンドルバー実装

これを使用して、_(article-name).md_を/blog/(article-name)に変換し、動的な部分を作成する簡単なブログを作成しました。

_// Create handlebars partials for each blog item
fs.readdirSync('blog').forEach(function(blogItem){
    var slug = blogItem.replace('.md','')
    var fileContents = fs.readFileSync('blog/'+blogItem, 'utf8')
    var html = marked(fileContents)
    var compiledTemplate = hbs.compile(html);
    hbs.registerPartial(slug, compiledTemplate);
})

// Create 'showBlogItem' helper that acts as a dynamic partial
hbs.registerHelper('showBlogItem', function(slug, context, opts) {
    var loadedPartial = hbs.handlebars.partials[slug];
    return new hbs.handlebars.SafeString(loadedPartial(context));
});
_

これがルートです。ブログが存在しないため、パーシャルが存在しない場合は404秒になります。

_router.get('/blog/:slug', function(req, res){
    var slug = req.param("slug")
    var loadedPartial = hbs.handlebars.partials[slug];
    if ( ! loadedPartial ) {
        return res.status(404).json({ error: 'Article not found' })
    }
    res.render('blog', {
        slug: slug
    });
})
_

_/views/blog.hbs_は次のようになります:

_<div class="blog">
    {{ showBlogItem slug }}
</div>
_
3
mikemaccana

いつ Handlebars.partials[]は、部分がコンパイルされていないことを意味する生の文字列を返します。

よくわかりませんが、Handlebarsは、パーシャルを含むテンプレートをコンパイルするときに、パーシャルを内部的にコンパイルするのが最善の推測です。したがって、ヘルパーを使用してパーシャルを含めると、ハンドルバーはそれを認識せず、コンパイルされません。

コンパイル 部分的に自分でできます。コンパイルされたパーシャルを登録することを忘れないでください。そうしないと、パーシャルが必要になるたびにコンパイルされてしまい、パフォーマンスが低下します。このようなものが機能するはずです。

var template = Handlebars.partials['templatename'],
    fnTemplate = null;

if (typeof template === 'function') {
  fnTemplate = template;
} else {
  // Compile the partial
  fnTemplate = Handlebars.compile(partial);
  // Register the compiled partial
  Handlebars.registerPartial('templatename', fnTemplate);  
}

return fnTemplate(context);
2
harco gijsbers