Mike
Mike

Reputation: 4091

Ember.js: Passing arguments to render helper

Say I have two objects in my application: 1) Topic, 2) Categories.

Topic has a route /topic/:topic_id

Categories doesn't have a URL route. It contains the list of all available categories that topics can be in.

On the page for Topic, I would like to show a list of all categories, while highlighting the category that the topic is a part of (the 'active' category)


Original Solution

I had originally solved this with a component as follows (a lot of code removed for brevity):

Component Template:

(Goes trough each category and lists them. If the current one is active, it says so.)

<script type="text/x-handlebars" id="components/category-list">
  {{#each categories}}
    {{#if this.active}} Active -> {{/if}}
    {{this.name}}
    <br />
  {{/each}}
</script>

Component Object:

(Goes through the models via the CategoriesController, marks one category as the current active category for that topic via a "current" parameter passed in from the {{category-list}} component helper)

App.CategoryListComponent = Ember.Component.extend({
  tagName: '',
  didInsertElement: function () {
    var categories = App.CategoriesController;
    var current = this.get('current').get('id');

    categories.get('content').forEach(function (c) {
      if (c.id === current) {
        c.active = true;
      }
    });

    this.set('categories', categories);
  }.observes('current')
});

Displaying the Category List:

In the Topic view ('category' is the property of Topic that says what category the topic is in):

{{category-list current=category}}

This all works, but I have a feeling that it is not the correct way to go about solving the problem. Components strike me as something that should be very reusable, and this really only is just an encapsulated part of one view.


Second Attempt

Now I am trying to use the category list as a view. So now instead of just a Component, I have a CategoriesRoute (not hooked up in the router though), a CategoriesController, and a CagetoriesView.

When the Topic resource loads up, it sets up the categories controller with the loaded model data:

App.TopicRoute = Ember.Route.extend({
  model: function (params) {
    return Em.RSVP.hash({
      topic: this.store.find('topic', params.topic_id),
      categories: this.store.find('category')
    });
  },

  setupController: function (controller, context) {
    this._super(controller, context.topic);
    this.controllerFor('categories').set('model', context.categories);
  }
});

The CategoriesController is just a standard array controller:

App.CategoriesController = Ember.ArrayController.extend({});

The CategoriesView is also very simple:

App.CategoriesView = Ember.View.extend({
  templateName: 'categories',
  tagName: ''
});

And finally the categories template:

<script type="text/x-handlebars" id="components/category-list">
  {{#each categories}}
    {{this.name}}
    <br />
  {{/each}}
</script>

I am rendering the list with the {{render}} helper in the Topic template:

{{render "categories" }}

The Problem:

The above seems to work fine in terms of showing the list of categories. However, I can't figure out how to tell the view which category is active (the category in which the topic is in).

I looked around on the internet, and it looks like the {{render}} helper used to allow for an optional options hash (which is how I solved the problem with a Component in my first attempt), but it seems to have been removed in some recent version of Ember.

I found a StackOverflow entry that mentioned making my own {{render}} helper, but it looks like that is to dynamically change models, or something of that nature. I'd like to keep the models backing for the categories view, I just need to be able to tell it which category is active via the Topic.category property.

Or, was my first attempt the better solution? I am very new to Ember, so I'm not sure what would be the best strategy here. My instinct tells me I should use my second attempt rather than the first, but I am not positive.

Any help is very appreciated.

Upvotes: 0

Views: 1404

Answers (1)

Hrishi
Hrishi

Reputation: 7138

You are right in saying that components must be re-usable everywhere and should not be tied to any particular controller. I would use a view for this. The way I would do is, I would have a

App.CategoriesController = Em.ArrayController.extend({ 
  itemController: 'category',

  //some other stuff here

});

for categories and then have an itemController called

App.CategoryController = Em.ObjectController.extend({ 
  setActiveState: function() {
   if (this.get('parentController.current.id') === this.get('content.id')) {
     this.set('active', true);
    }
  }

});

and in the template, you could say

{{#each category in categories}}
  {{category.name}}
{{/each}}

Upvotes: 1

Related Questions