Run Template in Template (recursion) within unders

2019-02-04 08:18发布

I am using backbone.js and underscore.js to build an javascript application. Since hours of reading and trying to run a template within a template like below, it is getting more and more frustrating.

My template using the build in underscore.js template engine:

<script id="navigation_template" type="text/template">
  <div><%= title %>
      <% _.each(children, function(child) { %>
          <% render_this_template_recursively(child) %>
      <% }); %>
  </div>
</script>

I would like to render this template for every child element ( render_this_template_recursively(child) ).

How can I do this?

Thanks

5条回答
【Aperson】
2楼-- · 2019-02-04 08:43

I implemented this recently using backbone-relational. I created a fiddle that I thought might be helpful if you want to see a working solution: http://jsfiddle.net/blaisco/ADKrK/

I've posted the relevant bits below.

The view:

var FolderView = Backbone.View.extend({
    el: $("#main"),

    template: _.template($("#folder-tmpl").html()),

    render: function () {
        this.$el.html(this.template({
            "folder": parentFolder.toJSON(),
            "templateFn": this.template
        }));
        return this;
    }
});

The html/template:

<ul id="main"></ul>

<script type="text/template" id="folder-tmpl">
    <li>
        <a href="#" class="folder"><%= folder.title %></a>
        <% if(folder.children.length) { %><ul><% } %>
        <% _.each(folder.children, function(child) { %>
            <%= templateFn({"folder": child, "templateFn": templateFn}) %>
        <% }); %>
        <% if(folder.children.length) { %></ul><% } %>
    </li>
</script>
查看更多
Luminary・发光体
3楼-- · 2019-02-04 08:44

A recursive template can look something like this:

<ul>
    <% entries.forEach(function (entry) { %>
    <li>
        <%= entry.title %>
        <%
        if (entry.children) {
            print(tmpl({
                entries: entry.children,
                tmpl: tmpl
            }));
        }
        %>
    </li>
    <% }); %>
</ul>

First, pre-compile your template:

entriesTmpl = _.template(entriesTmpl);

Then call it while passing both your data and the template itself:

$el.html(entriesTmpl({
    entries: entryTree,
    tmpl: entriesTmpl
});
查看更多
倾城 Initia
4楼-- · 2019-02-04 08:46

I've not personally tried this but _.template returns a function (I've named it templateFn to emphasize that), so you could pass it into the template like this:

var templateFn = _.template($('#navigation_template').html());

$(this.el).html(templateFn({model: this.model, templateFn: templateFn}));

Notice that i'm passing in the whole model (assuming that your model has a children property which is itself a collection of backbone models) and your template would be changed to:

<script id="navigation_template" type="text/template">
  <div><%= model.escape('title') %>
      <% _.each(model.children, function(child) { %>
          <%= templateFn(child, templateFn) %>
      <% }); %>
  </div>
</script>

Good luck. I hope this works for you

查看更多
5楼-- · 2019-02-04 08:52

I just successfully tried this. I tested it with only pure UnderscoreJS, no BackboneJS but functionally it shouldn't matter.

Here is the code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script type="text/javascript" src="underscore.js"></script>    
<style>

.container {
  position: relative;
  margin-bottom: 20px;
}

#container {
  position: relative;
  margin: auto;
}

.fib-box {
  position: absolute;
  top: 0px;
  left: 0px;
  background: rgba(0,68,242,0.15);
  border: 1px solid rgba(0,0,0,0.20); 
}

.header {
  padding-bottom: 10px;
}

</style>
  </head>
  <body> 

    <div class="header">
        <h3>Render Fibonacci With UnderscoreJS</h3>
        <form id="updateCount">
            <input type="text" value="13" id="fibSequence" />
            <input type="submit" value="Update" />
        </form>
    </div>

    <div class="container">
    <div id="container">

    </div>    
    </div>

<script type="text/template" id="template">
<% if(depth){ %>
<div class='fib-box' data-depth='<%= depth %>' style='width: <%= val %>px; height: <%= val %>px;'></div>
<% print(template(getFibObj(depth-1))) %>
<% } %>
</script>

<script type="text/javascript">

var template;

$(document).ready(function(){

    template = _.template($("#template").text());

    $("#updateCount").submit( function(){

        $("#container").html( template( getFibObj($("#fibSequence").val()) ) );

        var width = $("#container .fib-box:first").css("width");
        $("#container").css( {width: width, 'min-height': width} );

        return false;
    });

    $("#updateCount").submit();
});

function getFibObj(i){
    return {depth: i, val: fib(i)};
}

function fib(i){
    return ( i == 0 || i == 1 ) ? i : fib(i-1) + fib(i-2);
}

 </script>

  </body>
</html>
查看更多
smile是对你的礼貌
6楼-- · 2019-02-04 09:03

I've tried to use example presented by timDunham and Ates Goral, but it did not work for me, so I've made a little upgrade for it. Find it below.

view:

    template: _.template($("#tree").html()),

    render: function () {
        this.$el.html(this.template({
            options: this.collection.toJSON(),
            templateFn: this.template
        }));
    }

and template:

<script type="text/template" id="tree">
<ul>
    <% _.each(options, function (node) { %>
        <li><%= node.title %></li>
        <% if (node.children) { %>
            <%= templateFn({ options: node.children, templateFn: templateFn }) %>
        <% } %>
    <% }); %>
</ul>

And it works pretty good for me. The main difference, as you can see, is the passing configuration object into templateFn, instead of arguments. Hope you'll find it useful.

查看更多
登录 后发表回答