Search code examples
ember.jsember-router

Ember expand child controller/view


How do I structure this to work?

I have Projects which have many notes. Notes are listed using an itemController. I need these notes to have an expanded view which can be toggled by the route (it's the show view for a note inside of the project). How can I get a route to toggle a specific note that's listed on the page to expand?


Solution

  • You can use the the official Ember Guides for help: http://emberjs.com/guides/. The example there is with a simple application with many posts (in your case projects) and each post has many comments (in your case notes). The only thing missing is the option to toggle a note, instead of open it permanently.

    Using the Guide only, your router should look something like this:

    App.Router.map(function () {
        this.resource('project', {
            path: '/project/:project_id'
        }, function () {
            this.resource('note', { path: '/note/:note_id' }, function () {});
        });
    });
    
    
    App.ProjectController = Ember.ObjectController.extend({
        toggle: function(note) {
            var isOpen = !note.get('isOpen');
            if (isOpen) {
                this.transitionTo('note', note);
            } else {
                this.transitionTo('project', this.get('content'));
            }
    
            this.get('notes').forEach(function(note) {
                note.set('isOpen', false);
            });
    
            note.set('isOpen', isOpen);
        }
    });
    

    Then, your project template should list all the notes and provide a place to open a note and view it:

    <script type="text/x-handlebars" data-template-name="project">
        {{#each note in notes}}
          <li>
            <button type="button" {{action toggle note}}>
              {{note.name}}
            </button>
          </li>
        {{/each}}
    
        {{outlet}}
    </script>
    
    <script type="text/x-handlebars" data-template-name="note">
      {{description}}
    </script>
    

    To clarify things: ProjectController is an ObjectController with a content set to the currently opened project. ProjectController#notes is where all the notes for the currently loaded project will be. The project/note.handlebars will simply describe the note, as you desire it to be shown inside the project page.

    Here is a working fiddle (with some boilerplate code added): http://jsfiddle.net/ZcspT/6/

    EDIT:

    Here is the version without routes (only the different parts):

    App.Router.map(function () {
        this.resource('project', {
            path: '/project/:project_id'
        });
    });
    
    App.NoteView = Ember.View.extend({
        templateName: 'note',
        content: null,
        classNameBindings: ['content.isOpen::hidden']
    });
    
    
    App.ProjectController = Ember.ObjectController.extend({
        toggle: function(note) {
            var isOpen = !note.get('isOpen');
            this.get('notes').forEach(function(note) {
                note.set('isOpen', false);
            });
    
            note.set('isOpen', isOpen);
        }
    });
    

    The templates:

    <script type="text/x-handlebars" data-template-name="project">
        {{#each note in notes}}
          <li>
            <a {{action toggle note}} href="#">{{note.name}}</a>     
          </li>
        {{/each}}
    
        <div id="noteSection">
           {{#each note in notes}}
             {{view App.NoteView contentBinding="note"}}
           {{/each}}
        </div>
    </script>
    

    The stylesheet:

    .hidden {
      display: none;
    }
    

    Example: http://jsfiddle.net/ZfWhc/1/