In the previous step we updated TodoMVC to allow a user to toggle the display of a text <input>
for editing a todo's title. Next, we'll add the behavior that immediately focuses the <input>
when it appears, accepts user input and, when the user presses the <enter>
key or moves focus away from the editing <input>
element, persists these changes, then redisplays the todo with its newly updated text.
To accomplish this, we'll create a new custom component and register it with Handlebars to make it available to our templates.
Create a new file js/views/edit_todo_view.js
. You may place this file anywhere you like (even just putting all code into the same file), but this guide will assume you have created the file and named it as indicated.
In js/views/edit_todo_view.js
create an extension of Ember.TextField
and register it as
a helper:
Todos.EditTodoView = Ember.TextField.extend({
didInsertElement: function() {
this.$().focus();
}
});
Ember.Handlebars.helper('edit-todo', Todos.EditTodoView);
In index.html
require this new file:
<!--- ... additional lines truncated for brevity ... -->
<script src="js/controllers/todo_controller.js"></script>
<script src="js/views/edit_todo_view.js"></script>
</body>
<!--- ... additional lines truncated for brevity ... -->
In index.html
replace the static <input>
element with our custom {{edit-todo}}
component, connecting the value
property, and actions:
Pressing the <enter>
key will trigger the acceptChanges
event on the instance of TodoController
. Moving focus away from the <input>
will trigger the focus-out
event, calling a method acceptChanges
on this view's instance of TodoController
.
Additionally, we connect the value
property of this <input>
to the title
property of this instance of TodoController
. We will not implement a title
property on the controller so it will retain the default behavior of proxying all requests to its model
.
A CSS class edit
is applied for styling.
In js/controllers/todo_controller.js
, add the method acceptChanges
that we called from EditTodoView
:
// ... additional lines truncated for brevity ...
actions: {
editTodo: function() {
this.set('isEditing', true);
},
acceptChanges: function() {
this.set('isEditing', false);
if (Ember.isEmpty(this.get('model.title'))) {
this.send('removeTodo');
} else {
this.get('model').save();
}
},
removeTodo: function () {
var todo = this.get('model');
todo.deleteRecord();
todo.save();
}
},
// ... additional lines truncated for brevity ...
This method will set the controller's isEditing
property to false and commit all changes made to the todo.