How to show only one item out of many similar items in a template #each loop


#1

I have encountered a problem with filtering in templates when I’m trying to show items only once instead of repeating the same item, though coming as a different property. It is easier to show in code:

{{#each gCard as |card|}}
    Category: {{ card.category }}

    <ul>
        <li><b>{{ card.title }}</b></li>
        <li>{{ card.body }}</li>
        <li>{{ card.comment }}</li>
    </ul>

{{/each}}

This results in category header being repeated several times like this:

Category: first cat title body comment

Category: first cat title body comment

Category: second cat title body comment

I don’t want “first cat” to be repeated twice, only once, like this:

Category: first cat title body comment

title body comment

Category: second cat title body comment

Is it achievable within template or I should deal with data in controller? What would be the Ember way of solving this problem?

Thank you


#2

There probably is some way to do this in the template but I’d say it makes way more sense to do it in the controller from an Ember standpoint. That’s sort of the purpose of the controller. As a general rule of thumb I think the idea is to use as little logic in your templates as possible.

If I was dealing with that sort of data what I’d probably do is make a computed property that returned an object where the keys are categories and the values are arrays of title/body/comment objects. Something like:


Ember.computed('cardsarray', function(){
  // I'm sure there's a much more elegant way to do this but...
  let cardCats = {};
  this.get('cardsarray').forEach((card) => { 
    let cat = get(card, 'category');
    if(!cardCats[cat]) {
      cardCats[cat] = [];
    }
    cardCats[cat].push(card);
  });
  return cardCats;
}),

// results in something like:
{
  cat1: [
    {title: "title", body: "body", comment: "comment}, 
    ...
  ],
  cat2: [...],
  etc...
}

Then in your template you could simply say:

{{each-in categories as |category cards|}}
  Category: {{ category }}
  {{each cards as |card|}}
    <ul>
      <li><b>{{ card.title }}</b></li>
      <li>{{ card.body }}</li>
      <li>{{ card.comment }}</li>
    </ul>
  {{/each}}
{{/each-in}}

#3

Even if you don’t want to install an additional addon, you can also get some inspiration from ember-cli-group-by.


#4

Thank you, I was thinking that it is probably the only way to deal with the object in the controller, however, I thought maybe I missed some helper like {{showOnce}} or something similar, anyway it is true that the logic is better suited in the controller.


#5

That is a pretty cool helper, didn’t know about that one.