Samuel Lindblom
Samuel Lindblom

Reputation: 819

Where does view logic go in ember.js?

In one of my templates I would like to take an integer from the model and create html from it. I have a Customer model property called starRating with the value 3. From that value I would like to inject this html into the Customer template:

<i style="color: #dddddd" class="icon-star"></i>
<i style="color: #dddddd" class="icon-star"></i>
<i style="color: #dddddd" class="icon-star"></i>
<i style="color: #dddddd" class="icon-star-empty"></i>
<i style="color: #dddddd" class="icon-star-empty"></i>

Where do I put the logic which creates that html? I tried adding a computed property to the view but the whole function definition gets injected in the page as plaintext. Creating a helper/component seems excessive for this tiny snippet that will only be used once in the page.

Upvotes: 0

Views: 272

Answers (1)

intuitivepixel
intuitivepixel

Reputation: 23322

There might be many solutions to do something like a dynamic rating bar, so here is my try.

StarRatingComponent

Define a new component (see here for more info on components) that holds the logic for the star rating, and the best of all it's reusable. Note also that it's dynamic in terms of how many stars the rating bar will show, the number is defined in the customer model (as you will see below) for simplicity, but could come from everywhere:

App.StarRatingComponent = Ember.Component.extend({
  maxStars: 0,
  starRating: 0,
  stars: [],
  didInsertElement: function() {
    this.initStars();
    this.setStars();
  },
  initStars: function() {
    var stars = [], i = 0;
    for(i = 0; i < this.get('maxStars'); i++){
      stars.pushObject(Em.Object.create({empty:true}));
    }
    this.set('stars', stars);
  },
  setStars: function() {
    var counts = [], i = 0;
    for(i = 0; i < this.get('starRating'); i++){
      this.get('stars').objectAt(i).set('empty', counts[i]);
    }
  }
});

Pseudo Customer model

I've just defined a pseudo model since I don't know how your's looks like, that holds the information:

App.Customer = DS.Model.extend({
  starRating: DS.attr('number'),
  maxStarRating: DS.attr('number', {defaultValue: 5})
});

star-rating component template

Now let's backup our rating bar with a template that will render based on how the component is parametrized (more on this below)

<script type="text/x-handlebars" id="components/star-rating">
  {{#each star in stars}}
    <i style="color: #AA2567" {{bindAttr class=":glyphicon star.empty:glyphicon-star-empty:glyphicon-star"}}></i>
  {{/each}}
</script>

Implementation

Now having everything setup, the actual implementation is fairly simple, with this line:

{{star-rating starRating=customer.starRating maxStars=customer.maxStarRating}}

we render out component providing the rating value starRating and how many stars the dynamic bar should render with maxStars, as you will see in the demo we use the information randomly generated (for simplicity) in our models:

...
{{#each customer in model}}
  <li>Rating: {{customer.starRating}}
  {{star-rating starRating=customer.starRating maxStars=customer.maxStarRating}}</li>
{{/each}}
...

Maybe this is not the solution you where after, but I guess it get's you in the right direction on how you could do it.

See here for a working demo.

Hope it helps.

Upvotes: 1

Related Questions