Why is everyone still constructing parent-child views using the render method? - javascript

I dare call myself a backbone hacker. I know what the framework can do, and where its limitations are. I also have some experience with a few templating frameworks.
I've seen many tutorials where people explain how to create complex and nested views, and most of them construct it kinda partially using templates, and then within the render method of the parent view, in order to combine the templated child views
To me, this makes no sense why one should deal with the layout rendering, in the declarative code. Coming from Flex, I was taught to never do that. I always left the layout descriptions and variable bindings to the markup, and then the event handling to the declarative (View instance) code which uses this markup.
None of the templating frameworks I tested, however, allows the creation of complex markup, with nested views. One cannot really invoke a template from a template and thus instantiate a View object. This seems technically possible, especially using the data attributes, where we could specify type names.
Then, all the render method of the root level View class has to do is turn this template into HTML markup, then find out what the types of the child objects should be, create a child view instance for any of them, and keep further, in case those child objects should have child objects themselves. Every view is given a model context. Basically all the boilerplate steps that we deal with all the time, but automated at the Backbone.View level.
Anyone else thinking about this? Why does no one seem to be using this?

It should be noted that it is not necessary to use render at all and it is mainly reserved for re-rendering after changes to code has been made. You can bind views directly based on CSS selectors (see the docs for this).
Additionally there is a model binding extension for Backbone which greatly simplifies data-binding and reduces the 'manual' labor required. You might want to check it out.
http://github.com/derickbailey/backbone.modelbinding
Finally I will say this about rendering parent-child relationships. Do not call the DOM in a loop. This is incredibly inefficient and at least one reason people will build up parent-child relationships only in the parents render method. Having each child render itself using say jQuery will result in a lot of work for the browser (if you don't notice this in a modern browser try it in IE8).

I agree that instantiating child views in the render method makes no sense. Although I'd be hesitant to fully automate the process because I often want to pass in additional arguments when initializing a child view, eg:
var childCollection = someLogicToCreateTheChildCollection();
new ChildView({
collection : childCollection
});
So, what I end up doing instead is creating any child views I need in initialize and then in render I render the template and assign the child views to elements in the DOM.
This way my render function isn't the one declaring DOM order (like a lot of examples show by appending)—the template sets the DOM order and the render function just setElement().render()'s the child views.

Related

What is the correct usage for backbonejs view's initialize() and render()?

I find the usage of the different elements of backbonejs quite ambiguous. From my undestanding, this was the intention as backbone didn't want to be a framework, but more of a set of tools/objects.
I understand most parts of backbonejs, but i'm still questioning what is the correct usage for a view's initialize() and render() calls. In other words, what logic should be placed within each.
Could someone explain what is best practice or what is considered correct usage of these calls within a view?
This is a pretty far-ranging question, but I'll give it a try. The key takeway here is that there is no such thing as "the correct usage" for these calls. Backbone is flexible on purpose and meant to adapt to your needs. That's why it still has its place in a world of more sophisticated, but "opinionated" frameworks (which tell you that it's "my way or the highway").
Backbone does not use any magic with respect to rendering. The render() method is a no-op and not even invoked automatically for you. Its existence is nothing more than a hint how things are usually done.
The initialize() method, however, is invoked automatically when the view is instantiated. Backbone guarantees that at that point, the top-level DOM element of the view (the el) has already been created and is ready to have stuff attached to it.
But again, that's pretty minimal: the top-level element is there, but not yet attached to the DOM (unless you passed options.el to the constructor, setting the el to an existing element). Inserting the el into the DOM is your job, too.
So you are free to decide how to wire things up. What I typically do is this:
Most of my views have a template, which is commonly assigned to the template property of the view. (Again, just a convention, no magic involved. You could name it foo.) That template is compiled in initialize().
In initialize(), I set up the relationship with a model or a collection which the view is supposed to represent. Ie, the view observes model/collection events and is made to call render when the data has changed. (You don't have to use a Backbone entity as your data source, of course ... could be anything).
In render(), the data is fed into the template, and the result becomes the innerHTML of the el. Afterwards, I make sure the el is inserted into the DOM if it isn't already.
The first call to render() should happen when the data is ready. The right moment depends on the app. Perhaps render() is the last call in initialize(), or some event will kick it off later on.
If a lot of that sounds like repetitive boilerplate to you, yes, that's exactly what it is. Frameworks like Marionette exist on top of Backbone to take care of that.
But there is a sigificant performance penalty for that framework magic. So when I have to generate a lot of views, I stick to the generic Backbone stuff (and use one of my own components for speeding up the template handling.)

When should I use KnockoutJS Components vs. Templates?

So trying to get my hands dirty with KnockoutJS 3.2. I've read the docs and I've successfully implemented components within my current project. I don't use an AMD, so I'm just using script elements to hold the views.
My question is: If i'm not using the asynchronous loading features, is there any real practical difference to using components rather than templates?
General description of both
As stated in the other answer, a template is only a piece of HTML which can be bound to a viewmodel, or viewmodel section. And a component is composed of a template, and its corresponding viewmodel. Besides, this viewmodel, apart from observables can include some simple business logic, and functionality to communicate with the server.
Coupling and encapsulation
Another important difference is the coupling. A template it's bound to the main viewmodel, and its bound to the main viewmodel's observables, so it's highly coupled to the viewmodel: a change in the viewmodel will break the template, and viceversa. So, if you're reusing a template in several places, and you change it, you have to correct the corresponding viewmodels.
A component is bound to its own viewmodel. It's only coupled to the main viewmodel if there are parameters provided from it. This means that you can easily change the component template as well as the component viewmodel, and, if there are no parameters, or you don't change them, nothing will be broken.
So using components helps in decoupling and modularizing.
Communication between main viewmodel and component
The last section is a double edged sword: if there is a high interaction between the main viewmodel and the template or component, it's much easier to use a template, because all the logic and properties are held in the main viewmodel and the interactions are easily implemented. If you used a component you'd need to provide complex parameters, or even make something to allow the component to expose functionality to the main viewmodel.
Polymorphism
It's not strange to have some parts of an application that require different behaviors and visualization to solve the same kind of task. For example, let's imagine you have to implement a payment system in your application: if you accept for example paypal and credit card payment you have two different visualization and functionalities. If you used templates, you'd need to have the particular implementation of each payment system in the main viewmodel. If you used components, they'd share a common interface (parameters) but each of them would have its own implementation. If tomorrow you had to include a new payment system, it would be easy to implement a new component with the common interface.
NOTE: pay attention to the last paragraph
Binding
In the case of a template the binding it's not done at the template level, but inside it. I.e. each element inside the template must be bound to observables of the main viewmodel. In the case of a component the binding is much simpler: at most, it requires the component name and the parameters, if they exist.
Component registration and custom tags
If you register the component you can use custom tags. This makes the views more easyly readable and understandable: instead of specifying the component name in a binding, you use a tag with the component name, and parameters are passed as attributes.
Dynamic loading
If you use templates you have to dynamically load them by yourself, and, as this is an asynchronous task, you'll have to take care of using the template only when it's already available. That's way in most occasions you'll use inline templates. This is not good if they must be reused in several places.
If you have used some AMD implementation, like require.js, and you understand the benefits of this technology, you'll be happy to know that you can easily use AMD to load component templates and viewmodels. One of the advantages is that you don't have to worry about the template or component being available when you need to use them.
Testability
No matter if you do manual or automated tests, it's much easier to test a bunch of independent components, one by one, that to test a complex viewmodel with or without templates.
My choice
So far, I've exposed facts about templates, and components, and I've tried not to show my personal preferences. However, in this last section, I must say that in most situations I prefer to use components for their advantages:
modularity
low coupling
easy reuse
testability
binding syntax
(optional) dynamic loading
However, templates are also a better fit on some occasions
The last paragraph have to do with big applications. If you're dealing with small applications or simply enhancements of interfaces rendered by another technology (like ASP.NET MVC), you'll probably get none of the advantages of using components. So, you don't need them.
There are other cases when it's not worth using components. For example, if you have to show a list (JavaScript array) of items which have different properties which must be shown in a different way, it's easier to use templates. Note that the choice in this case is because each of the instances doesn't have a complex viewmodel with a lot of functionality, but a simple bunch of properties. In this particular case it's not only not worth, but it can also be counterproductive to use components.
You can understand this last example as polymorphism. But, in this case it's nearly "visual" polymorphism. I.e. each kind of item must be shown in a different way, but there is no need to implement any special logic in each of the components.
However, even in this case, if the templates are complex enough, or must be used in many different places, it's also much better to use a simple component that includes the template as well as a parameter that receives the whole item. So, even in this case, it's not a bad idea to use components.
If you'd read this far, thank you, and I hope you have some criteria to help you choosing the best option.
They aren't completely different. Components are made up of templates (html) and data/logic (view model i.e. JavaScript). When you have a modular view you want to attach a view model to you can utilize components. Here's a link discussing components a bit more: http://www.knockmeout.net/2014/06/knockout-3-2-preview-components.html

Meteor: how can I avoid checking for the existence of a variable or property everywhere?

When programming in Meteor I often find myself having to sprinkle typechecks or existence checks a bunch when writing Template helpers (at least under a couple very common conditions).
A helper for one template depends on a collection loaded by a different template
Any time a template helper operates on a piece of the DOM that another template is responsible for rendering into existence
For example (in the first case):
Template.example.rendered
rev1 = getRev(revId1)
revText1 = html2plain(rev1.text)
where getRev is doing an operation on the Revisions collection that may or may not be loaded by the time the example template is first rendered. So rev1.text will sometimes throw an exception because getRev ends up returning null or undefined if called before Revisions is loaded.
I then end up having to check a ton of variables/objects throughout my code for existence before using any of their properties just to be safe.
I could imagine using a router to not render my example template until after a different collection is ready (but for nested templates, and Session variable changes this doesn't work so hot).
I could imaging wrapping the helper code in a if (isCollectionReady) which might help but doesn't seem best practice.
The question is: Is there a canonical or best practice way to, identify these situations, code for them, or avoid this altogether?
Meteor is designed such that its templates are reactive, so that in most cases you shouldn't need to do DOM manipulations on them. As the underlying data changes, the templates automatically rerender so that they're always showing the latest data. Take a look at the examples in the Meteor docs: they don't use any DOM manipulation code. The templates put the data into the right places, and that's all they need.
In my experience there are two common reasons to need to put code into rendered:
You're loading a widget that needs to be initialized after the template is rendered and ready, like a <select> replacement.
You're doing animations. (In this case, I usually tell my template to put everything in its proper place but with a CSS class that hides the elements, and then all rendered does is animate the reveals.)
It's usually fine for a template to render before its subscription has loaded; at worst, the template will just render blank and then rerender as the data streams in. Also remember that you can subscribe from client-side code other than a template helper, for example Meteor.startup on the client side. Finally don't forget about the created helper; if you really want to wait until a template is loaded before subscribing, that would be a better place to subscribe than rendered, as it gets called sooner.
What DOM manipulations are you doing and why? Assuming you're not using widgets or animations, chances are that you can achieve what you want by using templates on their own without any additional manipulation code.

Managing Backbone.js Page Transitions

I know this is a very commonly discussed topic but I can't find anything that answers my question exactly :)
I'm working on a Backbone.js project at the moment. Router wise I don't instantiate views, models or collections within the router but instead just use the router as one way of dealing with state - the router calls methods on my custom controller object.
My controller then instantiates the different views, models and collections for index, show etc. This is all fine and dandy.
I'm just having a bit of a struggle with how to deal with page transitions. I've read all of the great posts on managing zombies etc, and know that whatever happens I have to have some cleanup system for old views (I'm currently using the .close() method that Derick Bailey blogged about).
If I'm going from #show to #index, or any other route change, I understand that it makes sense to just instantiate new, fresh views, models, etc - which is what I see in pretty much every tutorial. Making sure to cleanup old ones, of course.
But, if I'm already on #show say, and I route to another #show page, all of the views etc that I want are already instantiated and rendered. All I want to change is the data of the models and collections.
So I guess my question is why do I not see people re-using views very much. In my head I was thinking if you're already on the page that you want, it would make more sense to just update the url or urlRoot of the model / collection that that view is linked to and re-fetch. This would then trigger a reset event, and all views that need to can subscribe to this and re-render themselves.
But, as I say, I don't see people doing this. Is it just because it's a really bad idea? If someone is doing something like this, how do you deal with tracking 'refreshable' models and collections?
Thanks!
I think it depends a lot on how you are using your views and how complicated/large they are.
If your views are very simple then it is often just easier to rerender the entire view and replace the existing HTML with the new markup (it might also be faster then traversing the DOM to change the necessary parts. However if you have a more complicated view and there is only a small amount of information changing it is most likely better to listen to the appropate attributes change events (eg. _bind('change:name', this.nameChanged,this)) and then only update that part of the DOM.
Keep in mind that while the convention is to use a render method which renders the element, you can just as easily apply an additional refresh event to only refresh certain parts, you can then just swap models (like #jackwanders suggested) and call the refresh method.

Backbone: Are Views really Controllers?

I'm building my first Backbone.js app and I'm confused about how much responsibility I'm supposed to give to or hide from my Views.
In my example, I'm building a Rich UI Table (similar to YUI's datagrid) that's dynamically generated from a Collection. In my app I call this an "AppTable". In my understanding of MVC, I would imagine that there'd be some kind of AppTable controller which finds the correct Collection, grabs a "dumb" View and passes to the View whatever information from the Collection it needs to render. In this senario, the View would do little more than take the data provided to it and modify the DOM accordingly, maybe even populating a template or attaching event listeners.
Backbone seems to do away with the idea of having a controller mediate between the View and Collection. Instead a View gets initialized with a reference to a Collection and it is View's responsibility to update itself.
Am I understanding this architecture correctly?
Assuming I do, my question then becomes, what happens when my View needs to do more and more? For example, I want column sorting, drag-and-drop for rows, pagination, searching, table control links (like new, copy, delete row... etc), and more. If we stick with a "smart" View paradigm where the View is connected directly to a Collection, do the above functions become attached to View object?
Thinking through this, I could see the View growing from a simple table wrapper to pretty messy beast with lot of functionality attached to it. So, is the View really a controller in this case?
Your understanding of the architecture is correct. Backbone does not recognize the concept of a "controller" in the traditional MVC sense. (In fact, Backbone used to actually have an object called a Controller, but it has been renamed Router to more accurately describe what it does.)
The functions you list (drag-drop, delete rows, sorting, etc.) would all belong in a View. A view describes what you see and responds to user input. Anything involving an event (a click, a keypress, a submit, etc.) all go inside of a view. But your view should never actually manipulate the data; that should be done by its model. You are correct in thinking that a view acts like a controller, because it packages data and sends it to the model, which will then validate/set/save appropriately. Once those actions have occurred, the view re-renders itself to represent the new version of the data inside the model.
One note of caution: your view should not be too strenuously tied to the DOM. It is Backbone convention to have a top-level DOM element that your view is tied to (e.g., a form or a div) and then deal only with its sub-elements. That is appropriate; in general, things like "remove this link from this div" inside your view are not. If you find your view growing unwieldy, you most likely need to break it into subviews, each with their respective behaviors as components of their whole.
My thoughts on this updated below:
I think Josh gave a good answer, however, in my experience, building a few Backbone apps, even medium-complexity apps do need a separate controller class.
To clarify what I mean about a controller: The functionality between the model (or router) and the view that creates and instantiates the new view class and kills (and unregisters events) on the old one. This functionality might be the same for many views (so a direct one-to-one relationship between views and controllers probably isn't needed) but sometimes one needs to pass in a model or other additional extra values.
Right now, I just have one controller with a few if statements for adding some unique data to certain views for most apps I've built but I'm looking at setting up an architecture where it will check to see if a unique controller exists for that view else it falls back to the standard controller. Nothing special, but should do the job.
Update: After six months of building Backbone apps I realized that routers can be split up and extended just like views. (duh?)
Right off the bat, I knew to make a base view of functionality I know that all my views would need. Similarly, I would make base views for each section, like "profile" pages or "inbox" pages that I know would all use the same functionality. This wasn't so clear to me in the beginning with routers, but the previous name of "Controller" hinted at this.
Most people (as in every example of Backbone I've ever seen on the web) just use one monolithic router instantiation to handle all routes but you can actually have 1-to-1 parity of routers to views, or in my case, a base router for checking user auth and such and then one for each major section. That way if you need to pass in certain models or collections to a router on page load, you don't need to add code to one monolithic router, but instead pull up the unique router for that view. I find this is currently better than creating a separate controller class. The base router can be in charge of last instantiated view, etc, so you can kill the last view before instantiating the new one.
TLDR: Use multiple Routers as controllers. I believe that's what they were meant for and it works well.
I've struggled with the same semantic issues when trying to map out a single-page app. In the end I decided that Backbone is using the wrong name.
When you look at a Backbone app in the browser, the View is not actually a view at all, its el member is the view. Backbone.View is either a view controller or, probably more correctly, a presenter.
Some supporting evidence:
you never see a Backbone.View on the screen, its always the el or $el that is applied to the DOM
a Backbone.View does not receive user input, the DOM element receives input and the events are delegated via the events hash of the "view"
a BackBone.View manages model or collection changes and translates these changes to dumb-view (DOM) elements, then applies them to the actual view, e.g. this.$el.append('<p>Cats!')
I think Backbone.Presenter would be a better name, but I can also see the historical issues with there being a former Backbone.Controller and the amount of work renaming introduces.
I have settled on the following structure for my latest project:
an app controller, extended from Backbone.View, tied to the body element
several model collections to cache data retrieved from the server
a Backbone.Router that translates route changes into Backbone events and triggers them on itself
many app controller methods that handle the router events the app controller listens to
an app controller method prepares any needed models, then initiates a presenter (extended from Backbone.View) and attaches it to the body element
All these parts are initiated and owned by the app controller. The presenters do not know why or where they are on the page and only care for their own DOM elements and the changes they receive from this.model.
Have a look at this part of backbone documentation
http://documentcloud.github.com/backbone/#FAQ-tim-toady
References between Models and Views can be handled several ways. Some
people like to have direct pointers, where views correspond 1:1 with
models (model.view and view.model). Others prefer to have intermediate
"controller" objects that orchestrate the creation and organization of
views into a hierarchy. Others still prefer the evented approach, and
always fire events instead of calling methods directly. All of these
styles work well.
So, backbone does not take that decision for you.
I have a very similar use case (table grid with pagination, ordering, live filtering, and forms with client-side validation, master-details relations, etc.)
In my case, I first started with a Router behaving just like a controller, and quite quickly my code got a bit messy.
So I completely removed Routers (I'll add them back later, but just as an addition) and created my own controller (that in fact works as a presenter). It's just a javascript class, with Backbone.extend backed in to handle inheritance.
The idea is that the view recieves all the data it needs to display itself (model, collection, and the el in which it should be parsed), set up listener on dom events, and then executes controller methods. It never directly modifies the data nor it interacts with other views, it tells the controller to do it.
A view can have subviews, and in that case the subview only interacts with the parent view, or directly with the controller.
So far now it seems to work, but anyway things are not so simple as I expected them to be...
I hope to publish it in the next few days.
A different perspective from the other answers here is that, just because you are using the Backbone framework, that doesn't mean that your entire codebase must be wrapped in Backbone classes.
Personally, my controller is an amalgamation of "raw" Javascript and Backbone routes, and I never use Views for control logic at all. IMHO views are for ... well, view logic, and specifically for wrapping elements. If you're using a view for anything that doesn't directly connect to an HTML element you are (again, IMHO) doing something wrong.
Backbone is awesome, but that doesn't mean that it's a silver bullet that can be applied to everything.

Categories

Resources