I'm implementing view/edit Views in backbone.js for a contacts manager. The web suggested creating a Contact class with child views called ContactView and ContactEdit. The problem is, these need to occupy the same el in the DOM, so I can't nest the children inside the parent. That's because from the outside, I want parent views to only refer to Contact, as if the children were private. I tried this and it works the first time I render():
initialize: function() {
this.view[0] = new CL.Views.ContactView({model: this.model, el: this.el});
this.view[1] = new CL.Views.ContactEdit({model: this.model, el: this.el});
},
render: function() {
this.view[0].render();
return this;
}
But then I can't swap the views. I tried this.view[0].remove() and everything I can think of, but just can't get the browse and edit views to swap with each other using the same el.
I'm thinking that this means it will be better to have two templates inside one view and just exchange them, which already mostly works. I'm thinking it's backbone.js doesn't handle inheritance well for views at the same level in the DOM.
I'd prefer to avoid backbone.js extensions, but am up for following whatever patterns they implement. I'm trying to do this the "right" way because view/edit is such a common pattern for the forms in our app.
P.S. Another way to state this problem is, how does one hide a view and replace it with another view in backbone.js, if there is no parent view enclosing them?
Thanks in advance for any help you can provide.
I do not quite understand if you want to have a view for a Collection
of Models
or do you want a view for dealing with a single Model
?
then you can stick with one view. Just have some events listening for your actions enabling or disabling editing features. (You can do this even by setting up contenteditable="true" on dom elements)
I strongly advise to use some tools like backbone.marionette or chaplinjs. They will save you a ton of time.
Following examples are for Backbone.Marionette
example template
<script type="text/template" id="contact-view-template">
<span data-bind="firstName"></span>
<span data-bind="lastName"></span>
<span data-bind="email"></span>
<a href="#" data-action="edit">
<a href="#" data-action="save" style="display:none">
</script>
The view code:
ContactView = Marionette.ItemView.extend({
template:"#contact-view-template",
events:{
"click [data-action=edit]":"edit",
"click [data-action=save]":"save"
},
edit:function(){
this.$("[data-action=edit]").hide();
this.$("[data-action=save]").show();
this.$("[data-bind]").attr("contenteditable",true);
},
save:function(){
var value = {};
_.each(this.$("[data-bind]",function(el){
value[el.dataset['bind']]= $(el).val() || $(el).text();
}));
this.model.set(value);
// add your validation here
this.model.save();
}
});
ContactListEditView = Marionette.CompositeView.extend({
itemView:ContactView.extend({
tagName:"li"
}),
itemViewContainer:"ul",
template:_.template("<h1>ContactList</h1><p>feel free to edit</p><ul></ul>")
});
(i hope I haven't made any serious errors):
ContactEditView = Marionette.ItemView.extend({
template:"#contact-edit-view", // your template & bindings
events:{
"click [data-action=save]":"save"
},
save:function(){
var value = {};
_.each(this.$("[data-bind]",function(el){
value[el.dataset['bind']]= $(el).val() || $(el).text();
}));
this.model.set(value);
this.model.save();
}
});
ContactListView = Marionette.CompositeView.extend({
itemView:Marionette.ItemView.extend({
template:"#contact-view-template",
events:{
"click [data-action=edit]":"edit"
},
edit:function(){
this.trigger("edit",this);
}
}),
regions:{
"edit":"[data-region=edit]"
},
initialize:function(){
this.on("itemview:edit",function(view){
this.edit.show(new ContactEditView({model:view.model}));
}.bind(this));
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With