Reputation: 13431
how would i add inline editing on attributes of a model,
for example, when i have a Player
model
var Player = Backbone.Model.extend({
defaults: {
id: 0,
name: '',
points: 0
},
initialize: function(){
// irrelevant stuff happening here...
},
rename: function(newName){
this.set({ name: newName });
}
});
and a playerRow
view
var PlayerRow = Backbone.View.extend({
tagName: 'li',
className: 'player',
events: {
'click span.score': 'score',
'blur input.name': 'rename',
'click div.playername': 'renderRename'
},
initialize: function(){
_.bindAll(this, 'render', 'rename');
this.model.bind('change', this.render);
},
render: function(){
var template = Tmpl.render("playerRow", { model : this.model });
$(this.el).html(template);
return this;
},
renderRename: function() {
// i was thinking of switching the DOM into a textfield here
},
rename: function(){
var inpt = $(this.el).find('input.name');
var newName = (inpt.val() != '') ? inpt.val() : 'no-name';
this.model.rename(newName);
}
});
and my playerRow template
<script type="text/template" id="playerRow-template">
<% if ( model.get('name') == '' ) { %>
<div class="state-edit"><input type="text" class="name" name="name"></input></div>
<% } else { %>
<div class="playername"><%= model.get('name') %></div>
<% } %>
</script>
either i set a certain property of my model that holds the state (default or edit), which triggers a re-render and in my template instead of testing if name == ''
i can test on that state property.
or i do it inline like i say in my comment in renderRename i just swap the DOM into an input field but i think this is a bad way to do it. Would this cause troubles with the already bound events? like 'blur input.name': 'rename'
i doubt creating a new view for the edit is the best way, because i want inline editing, for just this one name field, i don't want all the rest of the player template to be duplicate in the player template and the editplayer template.
so, bottomline, my question: what is the best way, to handle inline editing
Upvotes: 4
Views: 4583
Reputation: 18915
A different option altogether:
Inline edititing making use of the html EditableContent feature. No need for changing/cluttering the DOM, great user experience if done correctly, supported in all major browsers.
A couple of js-editors make use of this, most notably Aloha Editor (check for browser support), but for attribute editing without needing much else (e.g rich text editing etc) you can easily roll your own.
EDIT: June 2012:
Rolling your own becomes much easier when using the excellent range Library: http://code.google.com/p/rangy/
Hth, Geert-Jan
Upvotes: 9
Reputation: 33074
I like to have an extra input field in the view that is hidden by default. (This is closest to your option (2), but it avoids conditionals in the template or adding elements on-the-fly.)
So the template might look something like this:
<div class="show-state">
... <%= name %> ...
<input type="button" value="edit"/>
</div>
<div class="edit-state"> <!-- hidden with display: none in CSS -->
... <input type="text" value="<%= name %>"/> ...
</div>
Essentially, it's a view with two states, "showing" and "editing". When the user clicks "edit", I call this.$('.show-state').hide(); this.$('.edit-state').show();
to flip the state.
Once the edit gets submitted or canceled, I just have the view rerender itself (after talking to the server and updating the model's attributes if necessary) to revert to the original "show" state and reset the input field.
P.S. Keep in mind that my code enables XSS because it does not escape name
.
Upvotes: 0