On adding new model to my collection I don't want the view to be refreshed but I want the model to be appended to my collection and be appended to the view. SO i shouldn't render the view again. Is it possible via Backbone.js? How should I proceed ?
You could have a view that handles the whole layout, and a view that represents a single model. You would make the render method of the latter to return the HTML of a single model, and append the result to a list using the main view. You have a great example of this in the Addy Osmani's book "Developing Backbone.js applications". Take a look at the section where he explains how he renders each task to the todo list of his Todo App, if I understood well, your problem is solved in there.
Related
What is the best way to switch to a different view when user navigates to a different url. In angular there is ng-view that takes care of this and inserts corresponding templates and in ember its all route based.
Is it better to just hide other views elements on routing using css or destroying other views and inserting current view?
EDIT
It would be great if someone could give an example how to re-render the view on navigating back to it again and restoring its previous state.
Eg.
if you have a check-box in a view that user can select to add some item to the cart , but in the middle he/she moves to some other url and then comes back, that check-box should be checked.
I would have a main content view with subviews and call remove on it, which is responsible for cleaning up any subviews too (calling remove on them first and going up the hierarchy tree). The concept of subviews doesn't come for free with backbone but isn't hard to implement. And finally attach a new content view.
This ensures you can cleanup and the browser is using a consistent amount of resources.
I would abstract this into some kind of layout view which has a content subview and a function like setContent(view) which handles the remove of any existing content view and the attach of the new one.
Personally I would have a router with sub routers in modules, e.g. a main router which finds a route starting with "checkout" and passes it over to a sub router in the checkout module which is responsible for attaching a new content view.
In Backbone the implementation is up to you which is both good and bad, depending on how nice you do it ;)
Always remove the view as opposed to just hiding it. If you don't remove (and unbind) your views properly, all bindings, handlers and references to models/DOM elements will linger around.
Depending on the size of your app, you can have a module that handles layouts (as suggested by dominic-tobias), or have a method on the router that takes care of this for you. At its most basic, this method (let's call it _switchView) takes a view and holds onto an instance of the currentView. Upon view change, it removes the current view, sets the new view to the current view and then renders it to the DOM.
Something like this:
_switchView(view) {
this.currentView && this.currentView.remove();
this.currentView = view;
this.$rootEl.html(view.render().$el);
}
I've been learning backbone.js over the past couple of weeks and am about to start using it in anger in an app I'm writing. My question to you is about a use case for models and collections in a Bootstrap 3 navbar.
On my server side I authenticate the user and, based on their profile, assign them a role (author, editor, administrator etc.). I then construct an object that contains the appropriate menu structure for the user's role and pass that to the client using Handlebars. The intent is for the browser to construct the HTML to render the menus according to the properties (key/values) in the object using backbone.
My thoughts are that the navbar itself is a collection of models (navbar); each dropdown menu or link on the navbar is a single model (navbarItem); each of these contains a collection of menu items (navbarItemMembers), these collections being of models of each individual menu item (navbarItemMember). I can then set event listeners against each navbarItemMember to trigger an appropriate route or render action as appropriate.
So, getting to the point... am I over-complicating things? A collection containing models each containing a collection of other models, each of those mapping to a view that renders a on the main page. Seems convoluted to me, but from my (albeit limited) understanding of backbone.js it does seem the right way to do this...?
Advice much appreciated from those more experienced (battle scarred?!) than I. Thank you.
Use a collection when it's going to provide some benefit to you over a plain model. The benefits could be either
Interacting with a RESTful service where you'll want to not just get a list of data but then separately fetch/modify/add/delete individual items is that list
Defining separate Views for each item in the list rather than a having a single View that iterates over the list.
I don't think a basic navbar benefits from either of those. If your navbar has some super fancy elements beyond just links then maybe #2 applies but otherwise keep it simple, use a single model with a single view/template
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'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.
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