Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mustache (or Handlebars) iterating over two lists

I have two arrays:

var content = {
  "girls": ["Maria", "Angela", "Bianca"],
  "digits": ["21.143.191.2", "123.456.78.90", "971.6.17.18.1"]
};

and a template:

<script id="template" type="text/template">
  <ul>
    <li><a href="{{digits}}">{{girls}}</a></li>
  </ul>
</script>

I'd like the end result to be:

<ul>
  <li><a href="21.143.191.2">Maria</a></li>
  <li><a href="123.456.78.90">Angela</a></li>
  <li><a href="971.6.17.18.1">Bianca</a></li>
</ul>

I've tried block mustaches like {{#girls}} {{.}} {{/girls}} and {{#digits}} {{.}} {{/digits}} but no matter which way I nest them I seem to get repeats instead of interlacing.

Any Ideas?

PS: Obviously in the future we'll be asking for IP addresses, not phone numbers.

PPS: None of those are intended to be real IPs, please don't try to contact those girls!

like image 282
Costa Michailidis Avatar asked Mar 03 '12 07:03

Costa Michailidis


2 Answers

You need to rearrange your content so that you can iterate over just one thing. If you combine those two arrays with something like this:

var data = { girls: [ ] };
for(var i = 0; i < content.girls.length; ++i)
    data.girls.push({
        name:   content.girls[i],
        number: content.digits[i]
    });

Then a template like this:

<script id="template" type="text/template">
  <ul>
    {{#girls}}
      <li><a href="{{number}}">{{name}}</a></li>
    {{/girls}}
  </ul>
</script>

should work.

like image 195
mu is too short Avatar answered Oct 16 '22 15:10

mu is too short


With "mu is too short"'s advice. And a few crazy ideas I came up with an interesting approach to complex templating. *It almost works!

So let's say I have this content (or data or view) which I want to put into a template:

var content = {
  title: "Black Book",
  girls: ["blonde", "brunette", "redhead"],
  digits: ['123', '456', '789'],
  calc: function () {
    return 2 + 4;
  }
};

And I have a template like this:

<script type="text/template" id="template">
  <h1>{{title}}</h1>
  <h3>{{calc}}</h3>
  <ul>
    <li><a href="{{digits}}">{{hair}}</a></li>
  </ul>
</script>

And the end result I want is this:

  <h1>Black Book</h1>
  <h3>6</h3>
  <ul>
    <li><a href="123">blonde</a></li>
    <li><a href="456">brunette</a></li>
    <li><a href="789">redhead</a></li>
  </ul>

The problem we'll encounter is that we have arrays (or lists) nested in our original content, and if we tried to Mustache.render(html, content) we'd end up with only one li item or a whole array within one href="" attribute. So sad...

So he's the approach, pass through the template multiple times. The first time, pass through and replace the top level items, and adjust the template for the next pass through. The second time, adjust one of the lists, and adjust the template for the third pass through, etc for how ever many layers of content you have. Here's the new starting template:

<script type="text/template" id="template">
  <h1>{{title}}</h1>
  <h3>{{calc}}</h3>
  <ul>
    {{#hair}}
    {{#digits}}
    <li><a href="{{digits}}">{{hair}}</a></li>
    {{/digits}}
    {{/hair}}
  </ul>
</script>

On the first pass through fill in the top level stuff, and change {{digits}} to {{.}}

$.each(content, function (index, value) {
    template2 = template.replace(/{{title}}/ig, content.title)
                   .replace(/{{calc}}/ig, content.calc)
                   .replace(/{{digits}}/ig, '{{.}}');
});

Now you have this:

  <h1>Black Book</h1>
  <h3>6</h3>
  <ul>
    {{#hair}}
    {{#digits}}
    <li><a href="{{.}}">{{hair}}</a></li>
    {{/digits}}
    {{/hair}}
  </ul>

On the next pass through we'll just call Mustache.render(template2, content.digits); and that should give us:

  <h1>Black Book</h1>
  <h3>6</h3>
  <ul>
    {{#hair}}
    <li><a href="123">{{hair}}</a></li>
    <li><a href="456">{{hair}}</a></li>
    <li><a href="789">{{hair}}</a></li>
    {{/hair}}
  </ul>

And that's where my logic dies, haha. Any help thinking this through would rock! I'm thinking I could take out the {{hair}} block elements and just do a $.each pass through content.girls and stack .replace three times. Or I could try to start with lowest level of content, and work my way up. I dunno.

All this basically leaves me wondering if there's some "logic-less" way for this kind of nesting or multiple pass throughs to be put into mustache does handlebars do it?

like image 31
Costa Michailidis Avatar answered Oct 16 '22 15:10

Costa Michailidis