I've been studying this Backbone tutorial and came across this bit of code:
var LibraryView = Backbone.View.extend({
el:$("#books"),
initialize:function(){
this.collection = new Library(books);
this.render();
},
...
});
The author explains that this.render() makes the view render when its constructor is called.
When would you not want the view to self-render?
The render method does nothing more than adding HTML to the DOM by using jquery's html or append methods. Where you choose to call the render method on the view is an architectural choice.
Backbone is said to apply the MV* pattern where models are bound directly to the view.
As such, the view would render itself upon instantiation, and have the ability to render itself when the model changes.
However, Backbone leave a lot of decisions to the developer and is a flexible library. There is nothing that technically prevents you to use control objects that manage the flow of the views; as such, another object can instantiate and re-render the view as well.
var view = new Bb_View();
view.render();
In the end, render is just a method on the view, and you can define your own methods as well. An example reason why I would call custom methods on the view from outside the view, is when I keep reference to an array of views.
As an event occurs, I loop through the views, I might add some conditions, and then call the custom method on particular views based on the condition.
Related
I have seen examples of managing backbone views and events attached to them in a single page architecture, where you can use view.remove(); for the current view and call the next view using require.js syntax, whenever you navigate to a different view. But can this be also achieved by simply emptying the html of the current view using $(div).html('');? Are both approaches going to have the same result? What are the differences, if any?
One simple difference is
.remove()
Removes a view from the DOM, and calls stopListening to remove any
bound events that the view has listenTo'd.
If your view has these 2 listeners in the initialize.
initialize: function() {
this.listenTo(this.collection, 'reset', this.render);
this.listenTo(this.model, 'change', this.render);
}
Your vies is listening to the model and the collection. So if you use remove to get rid of the view it will unbind the events for the view.
Where as if you do $('div').html() there is still a reference to the view and the methods on the view are still present in the memory along with the listeners which will cause memory leaks in your application. This is just one of the difference and there might be many more.
I'm working my way through my first attempt at using Backbone.Marionette and wondered if there is any reason to use a Backbone.Marionette.ItemView when a simple Backbone.View will suffice?
Thanks!
Marionette's ItemView provides a default render and close method which do a few things for you.
render does the following (amongst other things):
1) Marks view as !this.isClosed (related to showing views in Regions, another Marionette concept)
2) Triggers before and after render events
3) Calls a serializeData method to get data (defaults to data from either this.model or this.collection.
4) Gets the template (possibly from TemplateCache) and renders via Marionetter.Renderer
5) Binds UI elements
In addition to this "free" render method, you also get close functionality.
Of course, if you are using a CollectionView/ItemView combination (which is very powerful) or a CompositeView/ItemView, you HAVE to use an ItemView.
Outside of those cases, one big benefit is that you KNOW your view is going to be compatible with Marionette Regions. Ideally, in a Marionette app, you use separate regions to show your views, like so:
var myView = new MyView();
// render and display the view
MyApp.mainRegion.show(myView);
// closes the current view
MyApp.mainRegion.close();
If MyView is a Marionette ItemView, this will work like a charm. If it is just a raw Backbone View, you will probably need to do some work to make sure that it works as planned.
In my apps, I typically just opt for using ItemView as the basis for all of my non-Collection and non-Composite Views.
I am new to backbone.js and attempting to use patterns that I have used in other languages. Some of them work and some have fallen quite flat. My questions is this - how should I reference my model from within a view. For example, I have 5 identicals views that I passed a model from a collection of models. When the user clicks one of the 5 views, I need it to use the model that it was created with. Right now, I am getting null for this.model anytime the user clicks the view.
You need to pass the model in the view constructor as stated in the oficial doc http://backbonejs.org/#View-constructor
then you can access the model from the view with just this.model
if your getting undefined and you have passed the model in the view's constructor, maybe is because of the context when the callback function is being called,
have you checked that?
I use backbone.js and have a model without a collection.
In the view I call fetch on the model with a callback to render the view.
this.user.fetch({success: function(d) { self.randomUserView.render() }})
how can I make the view update automatically when the model change? e.g. I don't want to specify the above callback every time I call fetch. I tried to bind the view to many model events on initialize but this did not work.
On the view, add an event handler to the view's model:
initialize: function() {
this.model.on('change',this.render,this);
}
Backbone is event-driven, not callback driven framework (although technically they are callbacks). And your approach does not seem to be native to Backbone. When you do fetch(), user model will automatically trigger "add" event. All you need to do is in the corresponding view add this in initialize:
initialize: function() {
... your code...
this.model.bind('add', this.render);
}
This way you subscribe to this even only once in the view init and don't have to ever pass explicit callbacks.
Actually if you want to have a view refresh on fetch on a collection you need to bind RESET!
this.model.bind('reset', this.render, this);
Update is only fired if the current collection is edited.
ps bindAll is dangerous and lazy. (and probably going to cause you problems down the line)
I'm trying to learn Backbone from someone else's Backbone app in combination with the documentation. There are two things I don't understand about it that I can't figure out from the documentation. Hope someone might be able to explain...
Gist of the app
It's an app where you can drag and drop company names into boxes.
The app has a Company View, a Company Model and a Companies Collection.
It also has a Bucket View, a Bucket Model, and Buckets Collection
It also has a general App View that's not associated with any model.
Problems...
First- Is it weird that a view would never be rendered?
The App View is instantiated like this
window.App = new AppView();
and it gets different things going in the app (populating the buckets with company names etc and setting up some events). However, the App View is never rendered. The Bucket View and the Company View, on the other hand, are both rendered at different points in the code. For example,
var view = new BucketView({model: bucket});
this.$("#bucket-list").append(view.render().el);
But never that App View. This App View also has no render function. So is it weird that it has a View that's never rendered? Should its code be somewhere else?
Second Considering that App view is never rendered, is there any reason why they would have to change the default setting of el to the name of the main container div in the layout? For example, in the App view, they do this...
el: $("#mainapp"),
However, if this view's never rendered, is there any reason to change the default setting of el?
When you create a Backbone.View instance normally, it will immediately generat an el on the view for you. This is used as the placeholder for all of the HTML that the view will manage, and you generally populate the view's el with your HTML in the render method, as you've already noted.
In some cases, though, you don't want to render a completely new set of HTML elements. Instead, you'll want to manage some existing HTML that's already part of the DOM. In this case, you can easily attach a backbone view to the existing DOM element by specifying the el in the constructor, as you've shown with the el: $("#mainapp") line.
When a Backbone view sees that it already has an el, it does not generate it's own. Instead, it uses what it was handed.
So, to directly answer your two questions:
1) First- Is it weird that a view would never be rendered?
No, because ...
2) if this view's never rendered, is there any reason to change the default setting of el?
The question is slightly off in a manner that that can't be directly answered. In reality, the view is never rendered because they are setting the el in the call to the constructor.