28

So this is the general gist of my data (copied the look from chrome webkit inspector).

> Object
  > Fruit: Array[2]
    > 0: Object
       name: "banana"
       color: "yellow"
       animalthateats: "monkey"
       id: 39480
    > 1: Object
    length: 2
  > Vegetables: Array[179]
  > Dairy: Array[2]
  > Meat: Array[3]
  > __proto__: Object

And this is what I want to do (in general):

<select>
  <option value="">All Shows (default)</option>
  <optgroup label="Fruit">
    <option value="39480">Banana</option>
    <option value="43432">Strawberry</option>
  </optgroup>
  <optgroup label="Vegetables">
    <option value="3432">Broccoli</option>
  </optgroup>
</select>

I'm sorta new to the whole templating thing, and it definitely seems non-straightforward to accomplish... if I can use jQuery anyway that will work too, but preferably just with this setup.

Rey
  • 3,639
  • 5
  • 33
  • 40

5 Answers5

21

use just "this"

`<script id="some-template" type="text/x-handlebars-template">
<option value="none">Selec</option>
{{#each data}}
    <optgroup label="{{@key}}">
    {{#each this}}
        <option value="{{id}}">{{name}}</option>
    {{/each}}
    </optgroup>
{{/each}}
</script>`

http://jsfiddle.net/rcondori/jfav4o6u/

ron
  • 399
  • 3
  • 7
11

Your current data format presents you with two problems:

  1. Handlebars really wants to iterate over arrays, not objects.
  2. JavaScript objects have no reliable order.

You'll have better luck if you can rearrange your data to be nested arrays, something like this:

var foods  = { /* what you already have */ };
var for_hb = [
        { name: 'Fruit',      foods: foods.Fruit },
        { name: 'Vegetables', foods: foods.Vegetables },
        //...
];

You can do that with something simple like this:

var for_hb = [ ];
for(var k in foods)
    for_hb.push({name: k, foods: foods[k]});
for_hb.sort(function(a, b) {
    a = a.name.toLowerCase();
    b = b.name.toLowerCase();
    return a < b ? -1
         : a > b ? +1
         :          0;
});

var html = compiled_template({ groups: for_hb });

Then your template is simple:

<select>
  <option value="">All Shows (default)</option>
  {{#each group}}
    <optgroup label="{{name}}">
    {{#each foods}}
      <option value="{{id}}">{{name}}</option>
    {{/each}}
  {{/each}}
</select>

You could write a helper to iterate over an object but you'd still have to specify the keys in an array if you wanted to be sure of a sensible display order.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • Good answer. I'm still new to really utilizing Javascript in building applications... and I couldn't wrap my head around how I would organize the data with an array... I would have never thought of simply just putting 'name:' and then iterating based on that. – Rey Sep 14 '12 at 14:34
  • I also like how you created an object and assigned the other object... I was wondering about that... like how do I loop over an array that has no name.. so you just throw it inside of an object so you can give it a name... clever. – Rey Sep 14 '12 at 15:13
1

You can do this via a custom component see example, this is not supported by our default {{each}} helper (and that is intentional).

Sample Data:

a = {a:'muhammad', b :'asif', c: 'javed', username: 'maxifjaved'}

**

Online Demo for iterate throw an Object

http://emberjs.jsbin.com/yuheke/1/edit?html,js,output

**

Muhammad Asif Javed
  • 533
  • 1
  • 7
  • 19
0

I'm more of a Mustache man :-{)

But from the docs over here it looks like this kind of thing will do it:

<select>
  <option value="">All Shows (default)</option>
  <optgroup label="Fruit">
    {{#each Fruit}}
    <option value="{{id}}">{{name}}</option>
    {{/each}}
  </optgroup>
  <!-- repeat for others-->
</select>
Alex
  • 3,732
  • 5
  • 37
  • 59
  • ...you hardcoded not only the optgroup for Fruit, but you manually specified Fruit for the loop...I want to make an optgroup for each food type, and then options inside of those optgroups for their respective foods. – Rey Sep 14 '12 at 14:16
  • just nest the loops as mentioned by mu. – Alex Sep 15 '12 at 02:05
0

As far as Handlebars-only solutions, I've implemented this logic:

{{#each Listings}} 

<a href="javascript:void(0)" title="" ><img src="    {{DefaultImage}}" alt=" {{Make}} {{Model}}" /> </a>
Asim
  • 13
  • 6