I have a backbone collection that is dependent on another collection in my Rails application. I want to make sure that the view that displays the dependent collection is emptied out and the dependent collections is 'reset' it its view as well as corresponding records from the server are deleted. Is there an easy way to do so or do I have to loop through the collection and fire off model.destroy calls for all models in the dependent collection when the last record from the existing collection is removed?
Backbone Collections have a reset() (docs) method that will take a list of models as an argument. If you pass no argument, it will empty the entire Collection. However, this will not by default remove the models themselves from the server as you probably saw.
There's also a sync() (docs) on the Collection that will sync the collection (or all the models in the collection) to the server. Of course if you've run reset() the Collection is now empty, so that doesn't really help.
In the end I think that you will have to loop through the Collection to destroy each model (unless you want to take a serverside approach to limit your calls), but you should be able to extend your Collection and add a destroyCollection() method, or simply extend the already present reset collection to call the destroy() on the models before it resets the collection to empty.
If this doesn't help maybe provide a higher up example of what you're trying to achieve and maybe there's an even simpler way?
Related
For my setup I have two sub-views (on the same View) that render the same type of Models, however each view uses a totally different set of Model (one displays the latest ones, the other is split in 4 subviews per category). Using filter() on a Collection doesn't work because I need 4 posts per Category and about 20 new ones.
Since they are both on the same page, when I update the model on one view, I want the same model to be updated on the second view.
I tried a couple of things:
Use one Collection on the mainView, fetch inside the mainView and give this common Collection to the subViews. This is working as long as both subViews are using the same set of Models, which I am not.
Use custom events and a Collection in each subView. When Model is updated, send a global Backbone.trigger with the modified Model, catch it on the other side and do stuff as needed. This is also working but the implementation is really not pretty or efficient. Having all the Models listen for change and only act if their id is the correct one seems counter productive.
Use one Collection on the mainView and one per subView, the idea being that the Collection on the mainView holds all the items and distribute them to each subView's Collection as needed. This works but fetching the data, duplicating in the main Collection and the other subView Collection is kind of a pain and requires me to hold an instance on mainView inside each subView, which I don't really want to do because each subView is a "component" and can be use in multiple places.
People online seem to do the Events way most of the time, but I wonder if someone has a better idea.
Thanks a lot.
I am building a SPA and am trying to figure out a safe and clean way to delete all backbone entities when navigating away from one section of the application. I am aware of the Model.destroy(), View.remove() and Collection.reset() methods. My main concerns are:
Model.destroy() takes care of destroying the model on the server. Does one still need to manually delete the Javascript model?
Similariy, I realize that View.remove() will remove the view from the DOM. How should one safely get rid of the view object?
Collection.reset() clears the models in the collection. Will this also delete the underlying Javascript model objects or do they need to be explicitly deleted?
How would one get rid of the collection object itself?
My questions may seem simple to some but they have been confusing me for a while. I have not found any useful information regarding this exact problem which is why I decided to post here. I am also a relatively new to Javascript and am unaware of Javascript's garbage collection scheme. Does Javascript have a garbage collector and will it take care of deleting all such objects?
I am also looking into understanding the best way to remove Views.
View.remove() only removes the view from the DOM. My guess is that one still needs to take care of removing/destroying the underlying Model and unbinding all event listeners. Is that correct?
I often use _.bindAll to change the context of a function call. I have not come across a way to unbind this binding. My understanding says that this is unnecessary. Am I right?
Here is a good resource for learning about garbage collection in javascript:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management
To summarize, the only thing you need to worry about with Backbone is removing custom event handlers in your view, and a common way to do this is to override remove and remove the handlers before calling Backbone.View.prototype.remove. You don't need to manually remove events that you declared in the events property of the view, if you are using that.
To be a little more specific, lets consider the three types of objects you are asking about in turn. If you are using the backbone router, then you are probably creating a view object in a router method, maybe assigning it to a var, and then setting the html somewhere on the page. When the user navigates away, a different router method is invoked, and the reference you created to this view is unreachable. It will get garbage collected assuming you didn't create it as a property on window or your root level object or something like that.
The remove method is about removing the view from the DOM. The garbage collector takes care of removing the view from memory. The remove method is a convenient place to put any cleanup code that you need to run before taking the view off the page, so unhook your custom event handlers here.
Likewise, model.destroy is not about destroying the model object stored in memory, its about sending an AJAX DELETE request to the server. Model objects are garbage collected like everything else, and will go away once they are unreachable. If the only references to a model are contained within a view, then removing that view will cause the model to be garbage collected. Same goes for collections.
And for your last point, the underscore bind will not be an issue. Its about binding context (the value of this that a function is invoked with), not about binding event handlers. Remove those event handlers as usual.
Model.destroy() takes care of destroying the model on the server. Does one still need to manually delete the Javascript model?
Yes, you still need to manually delete the model. Model.destroy() does not delete it.
Similariy, I realize that View.remove() will remove the view from the DOM. How should one safely get rid of the view object?
Remove all references to it. If nothing is pointing at your object it will get garbage collected. Generally speaking, unless you go out of your way to make sure references to an object stay alive (such as global variables) or get careless with .on() you should be ok.
Note that using .listenTo() on your views instead of .on() makes your life easier. Memory leaks with views used to be a big problem when we just had .on()(See here for more).
Collection.reset() clears the models in the collection. Will this also delete the underlying Javascript model objects or do they need to be explicitly deleted?
How would one get rid of the collection object itself?
Does Javascript have a garbage collector and will it take care of deleting all such objects?
As long as there's no remaining reference to your objects they will get garbage collected.
I already described the birds-eye view of this (make sure you're no longer referencing your objects!), but here is a pretty good article about garbage collection in the context of Backbone.
View.remove() only removes the view from the DOM. My guess is that one still needs to take care of removing/destroying the underlying Model and unbinding all event listeners. Is that correct?
Note that it also calls .stopListening(), which unbinds your listeners if you used .listenTo() in your views. You do not need to remove/destroy the underlying model to let it get GC'd, again as long as there are no remaining references to it. Using .listenTo() with a model is a reference to it, but if you .remove() your view that will remove that reference.
I often use _.bindAll to change the context of a function call. I have not come across a way to unbind this binding. My understanding says that this is unnecessary. Am I right?
It's not clear to me what you would be trying to achieve by "unbinding," so I would say that it isn't necessary.
I am new to backbonejs and I cannot find answer to my query in backbone docs.
I'd like to create CollectionView and use as part of other view without collection and wondering if its possible.
Short answer is No
Standard Collection View work flow:
Collection view iterate over collection. On every iteration instancing new ModelView and provide iteration model as data and delegate render to ModelView instance. ModelView instance render data and keeps template.
So u have to keep collection to iterate with of replace it with something else to iterate with.
I have a main collection of models that I then filter into 3 separate collections (Think categorized menu). I have a timer to do a fetch on my main collection to make sure it is in sync. Each of my filtered collections is the basis for a Marionette CollectionView and renders properly the first time through. As soon as my main collection fetch is completed by the timer, each filtered collection refreshes with the main collection's data.
Update: My guess is, that since I am wrapping my filtered collection in a new Backbone.Collection, The reset is applying to each of my collections that share the same models, and so the fetch triggering the reset on my collection, actually triggers the reset on all my filtered collections as well, and then populates it with the full collection.
How do I get around this?
It seems to me that you are sharing certain objects by reference. If you would like to contain 3 isolated collections based on some original shared state, but without creating any relation to that state, I would copy all data and create new objects. This can be done via _.extend.
It is possible I may be misunderstanding your situation altogether. Some context/code would be helpful.
The issue was me. :)
I wasn't thinking, and I was creating new instances of the main collection type, even for my filtered collections. This was creating the timer on all the filtered collections too, and was, of course, refreshing the filtered collections with the main collection data.
I have a backend Dictionary that is used for synchronization (ie. to both a filestore and a webservice).
Off the top of this I need to generate lists/enumerables for the WPF frontend to consume. What is the difference between either hooking an enumerable up to the dictionary, and calling PropertyChanged when it is updated to using an ObservableCollection and having it automatically called its CollectionChanged.
Synchronizing occurs in the background automatically, and some elements may be removed, others may be updated. I want to propagate this information to the WPF frontend and user smoothly. (ie. if one item is removed, the whole display shouldn't have to be reinitialized). I also want to add animation when items are added and removed (ie. fade in and out) - is this possible if I replace the whole list or will it cause every single item to fade in again?
So should I:
1) use an observable collection and write some fancy synchronization logic between the dictionary and the collection?
2) use linq extension methods to convert the dictionary to an enumerable and simply call propertychanged on the enumerable whenever it changes?
3) synchronize between a dictionary and a list, by replacing the list whenever it is updated?
Also, how would any of these work with sorting and filtering operations that are performed just for the UI? (ie. if I need to filter some elements out of the dictionary based upon user selection, should I use a similar method as the one you have recommended?)
If you "replace" any IEnumerable<T> when you get a change, the entire list will be refreshed in the UI.
In order to avoid that, you'll need to implement INotifyCollectionChanged, and provide a collection which implements this. Instead of replacing the collection, you handle the elements, which in turn fires the appropriate events.
ObservableCollection<T> handles this for you. Personally, if you need to keep this in a dictionary, but want to synchronize it to a list, you may want to consider making a custom collection, possibly based around SortedDictionary. A standard Dictionary has no sense of ordering, which means that there'd be no way to implement INotifyCollectionChanged appropriately.