0
votes

I'm looking for 'The Ember Way' to implement a somewhat specific master-detail scenario.

Basically I want to implement something like an accordion, where the title is clickable and reveals more information about the specific item.

{{#each item in items}}
 <li>
    {{#link-to "item" item}}
        <h3>{{item.name}}</h3>
        <p>{{item.url}}</p>
    {{/link-to}}

    {{ what to use here instead of outlet }}
</li>
{{/each}}

There should be URL for every item, so I think using a view for displaying the detail is a no-go.

Using outlets inside an each helper is not possible AFAIK.

I suppose one way of doing it would be tracking collapsed and opened items in the controller, but this does not seem very elegant.

Another idea was having one outlet and using didInsertElement with some DOM manipulation in order to move it inside the correct < li > - but again this is far from ideal.

Any help would be appreciated.

2

2 Answers

2
votes

You don't need to use an {{outlet}} for all routes. You can define a route just to setup controllers.

What you need is to define App.PersonRoute as a nested route inside the accordion's route.
Use App.PersonRoute's setupController to update the accordian's controller with the current person.

For example, let's assume the template that has the accordion is the application template. Define a child route called `person':

App.Router.map(function() {
  this.route('person', { path: ':person_id' });
});


App.PersonRoute = Ember.Route.extend({  
  setupController: function(controller, model) {
    this.controllerFor('application').set('selected', model);
    this._super.apply(this, arguments);
  }
});

And then you can use an item controller to check if current person is selected:

{{#each itemController='personItem'}}
  {{#linkTo "person" this}}{{name}}{{/linkTo}}
  {{#if isSelected}} 
     {{partial "person"}} {{! or whatever you wish to do }}
  {{/if}}
{{/each}}

With the item controller:

App.PersonItemController = Ember.ObjectController.extend({
  needs: 'application',
  isSelected: function() {
    return this.get('model') === this.get('controllers.application.selected');
  }.property('controllers.application.selected', 'model')
});

Working jsbin: http://jsbin.com/ucanam/1587/edit

0
votes

It sounds like you might want to use render. Here's a JSBin showing a very rough accordion type feature in Ember.

http://jsbin.com/ucanam/1313/edit

Templates:

  <script type="text/x-handlebars" data-template-name="index">
    <h2>Index Content:</h2>
    <ul>
      {{#each itemController='person'}}
        <li>
          <span {{action toggleActive}}>{{firstName}} {{lastName}}</span>
          {{#if active}}
            {{render 'person' this}}
          {{/if}}
        </li>
      {{/each}}
    </ul>
  </script>
  <script type="text/x-handlebars" data-template-name="person">
    <hr/>
      Details about {{firstName}} {{lastName}} could go here.
    <hr/>
  </script>

Route:

App.IndexRoute = Ember.Route.extend({
  model: function(){
      return [
        {firstName: 'Kris', lastName: 'Selden', active:false},
        {firstName: 'Luke', lastName: 'Melia', active:false},
        {firstName: 'Formerly Alex', lastName: 'Matchneer', active:false}
      ];
  }
});

Item Controller:

App.PersonController = Ember.ObjectController.extend({
  actions : {
    toggleActive : function(){
      this.set('active', !this.get('active'));
    }
  }
});