How do I load different partials dynamically using handlebars templates?

后端 未结 3 658
慢半拍i
慢半拍i 2021-01-31 05:46

I\'m loading a template with the following data:

\"slides\": [
    {
        \"template\": \"video\",
        \"data\": {
            \"video\": \"\"
        }
          


        
相关标签:
3条回答
  • 2021-01-31 05:51

    As far as I can tell, hbs expects the partials to be known at compile time, which is way before you pass in your data. Let's work around that.

    First, pull in your dynamic partials before rendering, something like:

    // 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);
    });
    

    And define a helper that will act as a dynamic partial

    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;
    });
    

    Finally, modify your main template to look like

    {{#each slides}}
        {{dynamictemplate this.template this.data}}
    {{/each}}
    
    0 讨论(0)
  • 2021-01-31 05:53

    When Handlebars.partials[] returns a raw string it means the partial is not compiled.

    I am not sure but my best guess is that Handlebars compiles the partial internally when it compiles the template which includes the partial. So when you use a helper to include a partial then Handlebars doesn't recognize it and it will not be compiled.

    You can compile the partial yourself. Don't forget to register the compiled partial or you end up compiling every time the partial is required, which hurts performance. Something like this should work.

    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);
    
    0 讨论(0)
  • 2021-01-31 05:59

    I found the above answers a little hard to understand - they leak globals, have single character variables, and some odd naming. So here's my own answer, for my (and your) reference:

    A dynamic partial using 'hbs', express.js default handlebars implementation:

    I used this to make a simple blog making (article-name).md into /blog/(article-name), creating a dynamic partial:

    // 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));
    });
    

    Here's the route. It 404s if the partial doesn't exist, because the blog doesn't exist.

    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 looks like:

    <div class="blog">
        {{ showBlogItem slug }}
    </div>
    
    0 讨论(0)
提交回复
热议问题