Double Click to Edit View in Ember
When writing my current Ember app I wanted a view where you can double click to edit an element and it will replace the current item with a textfield. Instead of writing multiple views to handle this double click to edit feature, I wanted to write a reusable view that I can bind a value to and forget about.
The code before making a reusable view out of it was a bit messy. First we had to have a triggerView
which would trigger the editingName
property in the controller which would then show our text field. This text field would respond to the focusOut
event and call the save method in the controller and change editingName
in our controller back to false. There were too many working parts in different places to make the code feel clean.
Here’s the layout for our new reusable view.
All we’re really doing is checking if view.isEditing
is true and show our custom text field if true. The custom text field is nested inside our view and has an action
of save
which means when the textfield has the enter key pressed it will call our save method. If the view property isEditing
isn’t true, then we just show our passed in block.
Actually using the custom view looks like this.
If you don’t know or haven’t put it together, <h1 id="name"></h1>
is our passed in block.
The front end is simple enough but the back end is just a tiny bit tricker.
App.InlineTextField = Ember.View.extend({
layoutName: 'inline/text_field',
doubleClick: function() {
if (!this.get('isEditing')) {
this.set('isEditing', true);
Ember.run.scheduleOnce('afterRender', this, this.focusTextField);
}
},
focusTextField: function() {
var val = this.$('input').val();
this.$('input').focus();
this.$('input').val('');
this.$('input').val(val);
},
textField: Ember.TextField.extend({
focusOut: function() {
this.save();
},
save: function() {
var parentView = this.get('parentView');
var controller = parentView.get('controller');
if (controller.save) {
controller.save();
}
parentView.set('isEditing', false);
},
}),
});
There’s quite a bit to get into here, so let’s go line by line. First we set our layout path (the first snippet I showed off) to inline/text_field
which corresponds to the file inline/text_field.handlebars
.
Next we handle our doubleClick
event. When you double click our view while isEditing
is false we set it to be true and tell Ember to call our this.focusTextField
function after the next render. If we didn’t call Ember.scheduleOnce
we would still have the passed in block rendered instead of the text field.
The focusTextField
method is for setting our cursor to the end of the line. We have to make the text field empty and then put in the original value to make the cursor start at the end of the line rather that the beginning.
Finally we have our custom text field, textField
. All we do is inherit from Ember.TextField
and add a focusOut
event to call our save method. Our save
method calls the save
method on its controller if it exists and always sets our views isEditing
property to false.
There are a lot of things that could be done differently such as setting value
inside of our view rather than passing in a block, or even modifying the code to use a text area instead of a text field. Overall this should be a good starting point to do similar things with views and learn a few things about Ember and view rendering.