Search code examples
ember.jstodomvc

Ember.js how to design different representations of Data (with TodoMVC as an example)?


I would like to know what's the best way of designing the display of different representations of the same data model in Ember.js. To ask my question, I'll use the TodoMVC of Ember.JS, which has 3 representations of todo-data:

  1. any todo, i.e. the entire todo list (TodosIndexRoute)
  2. todos that are still active and incomplete (TodosActiveRoute)
  3. todos that have been completed (TodosCompletedRoute)

Currently, you can see each of the 3 by clicking on the words at the bottom of the list, directing to a different URL each time. Since currently each representation has a route, it makes sense that each representation gets its unique URL. The main page displays the entire todo list (1.).

A. What is the best ember.js design to make the main page display all 3 representations (i.e. under just one URL)?

B. How about the best design that displays all 3 on the main page as well as on separate pages?


Currently I only figured out a clumsy way and made this modified TodoMVC app that shows incomplete and completed lists at the bottom of the page.

In index.html, I added new named lists:

{{#each todosactive itemController="todo"}}
    {{ title }},
{{/each}} 

In the js router, I copied TodosActiveRoute and TodosCompletedRoute into TodoIndexRoute, which is code duplication, very bad.

Todos.TodosIndexRoute = Ember.Route.extend({
    setupController: function () {
        var todos = Todos.Todo.find();
        this.controllerFor('todos').set('filteredTodos', todos);

        var todos_active = Todos.Todo.filter(function (todo) {
            if (!todo.get('isCompleted')) {
                return true;
            }
        });

        this.controllerFor('todos').set('todosactive', todos_active);

        ...
});

I feel like I'm missing an elegant way of doing this, but my current ember.js knowledge is very limited. Should I use {{partial}}, {{render}}, render, or something else?

I tried {{ partial }} and {{ render }}, but I can't get them to display any data .

Thanks for helping out.


Solution

  • A) To display all 3 representations in one view, we actually just need the basic model in the single route. The key is for the controller to give you flavors of that model. The other important thing is to use data binding in the handlebars template. You can see the running version here.

    In the IndexRoute, add a model that gets the plain todos list:

    Todos.TodosIndexRoute = Ember.Route.extend({
        model: function(params) {
            return Todos.Todo.find();
        },
        ...
    

    Make a TodosListView that doesn't need to have anything:

    Todos.TodoListView = Ember.View.extend();
    

    In the controller, add 2 computed properties that returns the desired arrays:

    Todos.TodosController = Ember.ArrayController.extend({
        ...
        todosActive: function() {
            return this.filterProperty('isCompleted', false);
        }.property('@each.isCompleted'),
    
        todosCompleted: function() {
            return this.filterProperty('isCompleted', true);
        }.property('@each.isCompleted'),
        ...
    

    Finally, in the HTML template:

    <script type="text/x-handlebars" data-template-name="todos">
        Active:
        {{#view Todos.TodoListView lalaBinding="todosActive"}}
            {{#each view.lala}}
                   {{title}},
            {{/each}}
        {{/view}}
    
        Completed:
        {{#view Todos.TodoListView dataBinding="todosCompleted"}}
            {{#each view.data}}
                    {{title}},
            {{/each}}
        {{/view}}
    
    </script>
    

    note the dataBinding.

    Thanks to the folks on #emberjs irc for helping out.