mardi 22 décembre 2015

Using components instead controllers in EmberJS v2

I am beginner in EmberJS. I have made todomvc for ember v2 for learning Ember.

My implementation works without controller. I use components instead controllers. Because in documentation I see

Controllers are very much like components, so much so that in future versions of Ember, controllers will be replaced entirely with components.

But I think it is some ugly solution. Now I will explain why.

This is template for todo item component for my todolist app/templates/components/todo-item.hbs:

<li class="{{if isCompleted 'completed'}} {{if isEditing 'editing'}}">
    {{#if isEditing}}
        {{input-focused class="edit" value=item.title focus-out="acceptChanges" insert-newline="acceptChanges"}}
    {{else}}
      {{input type="checkbox" checked=isCompleted class="toggle"}}
      <label {{action "editTodo" on="doubleClick"}}>{{item.title}}</label><button {{action "removeTodo"}} class="destroy"></button>
    {{/if}}
</li>

It has acceptChanges and removeTodo events. And in js part of component I have handlers:

//app/components/todo-item.js
import Ember from 'ember';

export default Ember.Component.extend({

    updateTodoAction: 'updateTodo',
    deleteTodoAction: 'deleteTodo',

    isEditing: false,

    // some lines removed for brevity

    actions: {
      editTodo: function() {
        this.set('isEditing', true);
      },

      acceptChanges: function() {
        this.set('isEditing', false);
        this.sendAction('updateTodoAction', this.get('item'), this.get('item.title'));
      },

      removeTodo: function () {
        this.sendAction('deleteTodoAction', this.get('item'));
      }
    }
});

In js code of component I don't work with storage. I send this.sendAction(), and my route will handle it. And todos-route works with storage. Please look at todos route:

// app/routes/todos.js
import Ember from 'ember';

export default Ember.Route.extend({
    model() {
        return this.store.findAll('todo');
    },

    actions: {
        // some lines removed from here for brevity

        updateTodo: function(todo, title) {
            if (Ember.isEmpty(title)) {
                this.send('deleteTodo', todo);
            } else {
                todo.save();
            }
        },

        deleteTodo: function(todo) {
            todo.deleteRecord();
            todo.save();
        },

       // some lines removed from here for brevity
    }
});

When user clicks on remove button, it generates removeTodo action and it will handled in removeTodo() in js part of component. And then removeTodo() function calls this.sendAction('deleteTodoAction' ... ), which generates deleteTodo action. This action will handled in todos route in deleteTodo() method. I have todo.save() in this method.

The acceptChanges action works much like removeTodo, but it sets property isEditing = false before calling this.sendAction.

I have following chain for actions

component template -> component js -> route

I think for deleteTodo() will be better to exclude component js part. But how? In updateTodo() I need component js part, because I set value for isEditing property. But for calling route I need updateTodoAction property. And it is ugly for me. Can it work without updateTodoAction property? How?

Also I'd like to see any your comments about my solution (components instead controllers) or any part of my code.

Thank you, friends!




Aucun commentaire:

Enregistrer un commentaire