Backbone multiple event bindings - backbone.js

I have a div with id #content in which I render a view (view.el: "#content") with a model.
In this view I have an event ("click #save": "save").
When I override the view (= I render the same view on a new model, for example) the save event fires twice.
This happens because the this.undelegateEvents(); method unbinds events using the cid and every new view has a different cid.
How can I fix it?

Before you instantiate a new view, you will need to call undelegateEvents on the old view.

Related

Re render a CompositeView's itemview but not it's childViews

I have a CompositeView with a collection. The CompositeView has its own model and view that is pretty complex and changes made it to its childViews need to trigger the CompositeView's view to re render but not its childViews. Is that possible?
I read in the Marionette docs "You can specify a modelView to use for the model. If you don't
specify one, it will default to the Marionette.ItemView." But nothing happens when I try to use this in my CompositeView.
Your CompositeView should listen for change event of own model and should call render on that. In this way the only ItemView associated with the composite view will re-rendered on change of own model not all childView.
this.listenTo(this.model, 'change', this.render)
You can put this line inside initialize method of CompositeView.

backbone model.destroy doesn't remove the model nor from collection

triggering the model.destroy() triggers a delete request to the server and server sents back success:true, I have an event listener on the view.model listening on destroy. after all this I can still see the model still exist on the view. and the collection also doesn't remove the model..
Updated ...
this happens only after updating the model and calling on delete on it again. if the model was there during loading it would be delete but the view still hold a link to the model. so the model is really not made null/destroyed
I think view will not get removed from DOM, when you remove the model that used to render the view. You have to add some listener to remove view when model is removed.
view.listenToOnce(view.model, 'destroy', function(){
view.remove();
})

Backbone underscore update ui from model changes

I using backbone with underscore. I have a button
<%= model.testButtonText %>
This button is rendered in the render function of my view using template.
I am wondering if there is a way to automatically update the button's text when the model.testButtonText changes?
Or do I have to handle it specifically by binding to the model.testButtonText change and then do some jquery to find the element and update the text that way.
If you don't want to bind every element to model change event you can use this plugin: http://rivetsjs.com
Natively Backbone doesn't support ui-bindings.
Since it's tied to the model itself, you can listen for changes in your view to re-render it.
view.listenTo(this.model, 'change', this.render);
A useful extension for re-creating the view when your model changes -- Backbone.ModelBinder.

backbone.js collection events

I develop a jquery & backbone.js web app.
One component has an html table and behind this table is a backbone.js collection.
Any change in this collection should lead to an update of the html table, so I write
this.collection.bind("reset add remove", this.renderRows, this);
So I update the html table, when the whole collection gets new, when a new model gets added and when a model gets removed.
There's also a detail view component that gets called when the user hovers and clicks over a certain row of the html table. At the beginning of this component I get the right model out of the collection
changeModel = this.collection.get(id);
After the user has changed some attributes, I do
changeModel.set(attrs);
and return to the html table. The model in the collection has the correct changed values.
But the html table is not updated as none of the 3 events (reset, add, remove) was triggered.
So I added "replace" to the collection binding
this.collection.bind("replace reset add remove", this.renderRows, this);
and before returning from the detail view I called
this.collection.trigger("replace");
My solution works, but my question is:
Is there any "native" backbone.js solution that is already there and that I have missed and where I do not have to trigger something by myself?
The change events from models bubble up to the collection. (Collection's _onModelEvent -function in the annotated source. The method just basically takes all events from models and triggers them on the collection.
This leads to
Model attribute is set
Model triggers change
Collection catches change
Collection triggers change
So
this.collection.bind("replace reset add remove", this.renderRows, this);
has to be replaced with this
this.collection.bind("change reset add remove", this.renderRows, this);
P.S.
My personal opinion is that you shouldn't redraw the whole table if just one model is changed. Instead make each table row a view in itself that has the corresponding model as its model and then react to attribute changes there. There is no point in redrawing 500 table cells if you're targeting just one.
UPDATE
And nowadays you should use the on -method for binding to events.
collection.on("change reset add remove", this.renderRows, this);
If you're using BB 1.0, and this event is being listened to within a View, I suggest moving to use the new listenTo to bind into events, which also allows for easy unbinding when calling view.remove(). In that case you should do:
// assuming this is the view
this.listenTo(collection, "change reset add remove", this.renderRows);

Adding to a collection from a popup modal with Backbone Marionette

I'm pretty new to Backbone and Marionette and am having a tough time getting my views to communicate.
I've got a composite view that displays a list of items. To add a new item to the list, I have a popup modal that opens in a new item view that is separate from the composite view.
I'm not sure that this is the best way to do this, but in the modal, I created a new instance of the collection with all of the items and added the new item to that collection. This new item shows up in the original composite view, but only after I refresh the page.
I can't seem to figure out how to get the composite view to listen for the add event and render the new model after it is added.
Am I on the right track here? If not, what should I be doing to add to a collection from a modal?
I think I got this figured out. Instead of creating a new collection in the modal view, I passed in the collection from the composite view as a parameter when I created the modal view. Now, when I add a new model in the modal, the 'add' event is automatically triggered on both versions of the collection and the view automatically renders the new model. No need to bind any extra events like I was thinking.
Your solution will work, but means your views are pretty tightly coupled. You might want to look into using events instead (see How do I send a model that was clicked on within a ItemView to another ItemView that is on the same page?)
How your functionality would work with events:
Within the modal, you enter the data for the model to create
When you press the "save" button,
you validate and save the model var myNewModel = ...
you trigger an event: MyApp.MySubApp.trigger("item:add", myNewModel)
In the controllerfor the list view, you listen to that event, and add the new model to the collection.
The handler code in your controller would look something like:
MyApp.MySubApp.on("item:add", function(model){
this.myCollection.add(model);
});
If you'd like to learn more about using events, check out 2 Marionette tutorials I wrote:
http://davidsulc.com/blog/2012/04/15/a-simple-backbone-marionette-tutorial/
http://davidsulc.com/blog/2012/05/06/tutorial-a-full-backbone-marionette-application-part-1/
Both use events to communicate information within the apps.
In addition, basic events are also explained here: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf

Resources