I construct a CompositeView by passing it a collection. The collection gets its data via a url. I'm using the defer/promise technique to wait till the collection is populated before constructing the View.
Later I call fetch on the collection again, modifying the url.
To my surprise the CompositeView is re-rendered with the new data in the Collection. I thought I would have to do something e.g.:
collectionEvents: {
"sync" : "render"
}
But I'm not doing anything. No event binding at all. I thought in marionette I would have to handle this 'manually'.
This looks like something to do with CollectionView: Automatic Rendering. Does this happen with models and item views as well? And why do some tutorials etc. explain about binding?
Thanks
--Justin Wyllie
Yes but the only thing that will be re-rendered will be the collection, if you are using a CompositeView to display a model and a collection, the model part will not be re-rendered, you have to set an event for that.
So the CompositeView has the same behavior of the collectionView and it will re-render the collection whenever theres a change in the data.
And to your second question this does not happens in the ItemViews when the model changes.
this you have to do it on your own when its best for you application needs.
Related
Is there a way to gather more information about the changes from within the Backbone.JS collection change event. What I would like to figure out is whether or not it possible to to know what the collection change was; was a model updated, was one added or removed from the collection and also, for every of these, figure out which one.
Different events
When model is added to collection
collection.on('add',this.someFunc,this);
When a model is removed from a collection.
collection.on('remove',this.someFunc,this);
There is no change event on collection but you need to listen on models change event for change
in model:
initialize:function(){
this.on('change',function(){
this.collection.trigger('change');
});
}
Now on collection you can hear for change event
collection.on('change',this.someFunc,this);
refer this for list of all backbone built-in events
Simple question: What is the best way to fire an event 'only once'?
I have a Collection in backbone with multiple models. Sometimes multiple models' attributes are updated at once, firing multiple 'change' events on the Collection.
What is the best way to fire the 'change' event only once, grouping all attribute changes together?
My best idea at the moment is using a timer but this will only capture the first model attribute change.
All suggestions, ideas and solutions are valued. Thank you :).
Context:
In this case the event fires a very computationally intensive function, therefore multiple runs must be avoided.
Whenever you are updating the attributes on the models in bulk, pass {silent:true} as an option, which will suppress any events from being fired.
Then trigger a custom event for which a view or multiple views listening to the same.
You can "debounce" the method in your collection that responds to change events, though you'll have to manually figure out which models changed:
Col = Backbone.Collection.extend({
modelChanged: _.debounce(function() {
// handle model changes
}, delayInMs),
initialize: function() {
this.collection.on('change', this.modelChanged, this);
}
})
You can try resetting the collection, rather than adding the elements. See Collection reset method description:
reset collection.reset([models], [options])
Adding and removing models one at a time is all well and good, but sometimes you have so many models to change that you'd rather just update the collection in bulk. Use reset to replace a collection with a new list of models (or attribute hashes), triggering a single "reset" event at the end. Returns the newly-set models. For convenience, within a "reset" event, the list of any previous models is available as options.previousModels.
As documentation says, if you use reset, instead of add you will get a single reset event in the end.
I have a Backbone view which represents a collection. When this collection is synced with the server, and new models are added to the collection, I would like to hide all the view instances that represent these new models in the collection, whilst continuing to display the old models' view instances. How can I do this?
I'm assuming you're using a Marionette.CollectionView or Marionette.CompositeView here, right? That being the case, you are trying to prevent these from showing the newly added models, when the come back from the server and are added to your collection, right?
I can see a few different ways of doing this, most of which begin at the same place: a collection that filters based on an attribute that tells you whether or not to show the model. You would need to have some piece of data on the models that tells you wether to show them or not... I'm not sure what this would look like off-hand, but once you have the logic set up for this, I think the rest of it becomes easier.
A Proxy Collection
My preferred method of handling this in the CompositeView or CollectionView would be to create the view instance with a proxy collection - one that is filtered based on the value to show or hide the models.
I've talked about proxy collections before, and I have a working JSFiddle to show how to build them, here: http://jsfiddle.net/derickbailey/7tvzF/
You would set up a filtered collection like this, and then send the filtered collection to your actual view instance:
var filtered = new FilteredCollection(myOriginalCollection);
filtered.filter({
showThisOne: true
});
var view = new MyCompositeView({
collection: filtered
});
myOriginalCollection.fetch();
From here, it comes down to how you want to manage the filtering and fetch/sync of the original collection. But I think the over-all solution hinges on the proxy/decorator collection and being able to filter the collection down to only the list of items that you want.
Views in Bbone are not automatically updated when the underlying model/collection is changed. You have to explicitly listen for events: change/destroy for models and add/change/remove/reset for collections and call render().
As WiredPrairie suggests, if you've registered during view initialization for example to listenTo() any of these events and explicitly render(), you can always use stopListening() to reverse the effect.
An alternative, in case it's a one-of case of suppressing the view from showing the changes, is to check manually in your view's render() which models have been changed and use the previous state of the changed attributes to avoid showing the new values. Check out: model.hasChanged() and model.previousAttributes() as well as the options.previousModels in case of a collection reset.
I am trying to create a real-time application and there is a collection that I am constantly fetching using setInterval. The problem I am having is that when I fetch my collection Backbone rerenders the whole collection and if I set my fetch interval too short then the events binded to the views associated with the elements in my collection don't fire the click events binded to them reliably (presumably because it was busy rerendering?). How should I structure this?
I'm assuming based on your question that you have a single view rendering your entire collection, bound to the 'sync' event. If instead you create views to render the individual elements of your collection and, on 'sync' iterate through the models in the collection, rendering new ones and updating the views associated with models which have changed you will achieve what I think you want.
I'm new to backbone and am a bit stuck. Basically I want to update a collection on the change of a select. Currently on the change of the select I call Collection.fetch() but this appends the new models in the view. I was under the impression that when fetch is called, it removes the previous models which should then cause the related views to be removed, or am I incorrect?
Any help is appreciated!
It does by default, unless you've specified {add: true}.
The reason that the elements are being appended in the view will be because you are appending them without clearing out the old. When the reset event is fired in your view you could consider emptying your container before appending.
Remember, with backbone you are handling the DOM manipulation yourself. The View is not automagically updated along with your Collections & Models.