Most Backbone applications either use jQuery or Zepto as their DOM manipulation of choice. I tend to use jQuery as it’s supported across more browsers and has more features – though it is a little heavier in terms of download size (and maybe performance). I also use a lot of jQuery plugins for various controls, to create specific effects, etc. It’s generally easy to do, as Backbone’s views provide direct access to a jQuery element as “this.el” or “this.$el”. From there, we can call standard jQuery code and plugins.
There are some common patterns I’ve noticed for doing this, too. Specifically, when to call a particular jQuery function or plugin largely depends on the purpose of that function and sometimes depends on how that function or plugin is built.
At a very basic level, jQuery manipulations of the DOM can fall in to 1 of 2 categories: DOM-dependent and DOM-independent. Many of the operations that we do in jQuery are dependent on the HTML that we’re manipulating being in the DOM already. Some of them don’t need the HTML to be part of the DOM, though. In those cases, we can work with document fragments that aren’t currently displayed or part of the DOM.
For example, it doesn’t make much sense to call “.slideUp” if the HTML we’re manipulating isn’t currently displayed. The animation that this method causes would still run, but we wouldn’t see anything. The end result would not be visible and we would have wasted the browser’s execution time on this animation. I generally lump visual changes and animations in to the DOM-dependent category because it doesn’t make sense to use these methods if the HTML is not in the DOM yet.
On the other hand, I often call “.hide” on document fragments before they are attached to the DOM. I do this so that when the HTML fragments are finally added to the DOM, they won’t be visible to the user. Then, after I’ve attached the HTML to the DOM, I can call “slideUp” or any of a number of other methods in jQuery, to cause the content to be displayed. I call these methods DOM-independent because they can be called whether we are working with a document fragment that only exists in memory, or working with an element that is already part of the DOM.
Of course, this is a great oversimplification of things. There is a lot of functionality in jQuery that doesn’t even deal with HTML elements or the DOM at all. These would clearly fall in to the DOM-independent category, but I’m not even going to address those right now. And even though this is a simplified way to view jQuery’s functions, it’s generally useful. It also helps us understand when we should call some of these methods when we think about integration with Backbone.
Simple Manipulations And Events
Most of the simple manipulations that we perform with jQuery are DOM-independent. We can call them and manipulate a document fragment or a DOM element directly, whenever we want to. This includes not only showing / hiding HTML elements, but also adding and removing them, attaching events, and more.
Consider this example:
Here we can see a number of jQuery manipulations and events in place.
Starting with the core of Backbone’s View, an HTML element is generated when a view instance is created. This gets populated into “this.el” and cached in a jQuery selector object as “this.$el”.
In the render view, then, we see that we are using jQuery to create additional document fragments. For performance reasons (since it’s possible that the view’s “el” was attached to the DOM without the view knowing it), we’re populating the document fragment with content entirely in memory. This includes the addition of some data and calling “hide” on the fragment. We can manipulate the fragment with DOM-independent functions as much as we want, at this point.
Once we’ve completed the rendering of the HTML contents, we stuff it all in to the view’s el. The el is then attached to the DOM and the content we generated and we can begin using DOM-dependent methods.
We can also attach DOM level events to the fragments that we’ve generated. Since jQuery is turning our strings in to proper document fragments for us, the DOM events are available. That means we can call methods like “.click” and “.blur” on the view’s “el” if we want to. But I generally consider this to be an anti-pattern. There are some cases where you’ll need to manually attach events, and it can be done here in the render method. For the most part, though, we should be using Backbone’s declarative “events” on our views.
DOM Events And Simple Animations
Backbone’s “View” object abstracts a little bit of jQuery’s event system for us, through the use of the declarative “events”.
Surprisingly, DOM events are partially DOM-independent. As I said above, we can add the events to the document fragments before they become part of the DOM. We can even trigger them manually without them being part of the DOM. In general, though, we let the DOM fire it’s events for us.
Allowing the user to fire DOM events through DOM interactions (clicks, blurs, changes, etc) is DOM-dependent, of course. The view must attach any HTML structure that it needs to the DOM before the user can interact with them, to fire these events.
Often when we “click” or “change” or fire off some other DOM level event in our code, we want to respond to this by manipulating the DOM in a visual manner. For example, we might want to call “.hide(‘slow’)” on a portion of the view’s “el” in order to hide some items on the screen with a simple animation. The above example shows this. When you click on the top level “div”, the child “ul” is shown or hidden using the “slideToggle” animation method from jQuery.
jQuery Plugins And UI Controls
There are a large number of jQuery UI controls available, including the jQueryUI suite itself. I’ve used this suite and many other plugins for UI controls with Backbone a lot.
Generally speaking, most jQuery UI controls are partially DOM-independent in that you can call the jQuery plugin method to get them started before the document fragment you’re working with is attached to the DOM. Once the document fragment has been configured with the plugin’s code and additional structure, though, the plugins generally become DOM-dependent (as illustrated in the previous section).
Once the Kendo menu in configured, though, the view’s “el” has to be attached to the DOM (if it isn’t already). When that happens, you’ll see the menu structure in place.
DOM-Dependent UI Controls
I have run in to a few scenarios where a jQuery plugin was entirely DOM-dependent – or at least, my usage of it was. This meant that I could not call the plugin’s method prior to the Backbone view’s “el” being added to the DOM.
The “easy” solution to this is to have the view attach it’s “el” directly to the DOM in some fashion. But as I’ve talked about before, this is a bad idea. Instead, it only takes a few extra lines of code – which can be easily extracted in to something reusable – to make this work.
In this example, I’ve added a method to the view called “onShow”. This method contains the call to the jQuery “Layout Manager” plugin, which in my experience has been entirely DOM-dependent. Note that the “onShow” method doesn’t get called from within the view, though. This is because it’s not the view’s responsibility for adding itself to the DOM. It’s the responsibility of the code that needs the view, to do this.
The code that needs the view will instantiate it, call render and attach the resulting “view.el” to the DOM somehow. This is pretty straight-forward so far. What is does next, though, is check for the existence of an “onShow” method in the view. If that method does exist, it gets called. Since the code that is using the view knows that it has already added the view to the DOM, it knows when to call the “onShow” method. This allows us to write code that relies on DOM-dependent functionality without the view having to know if it’s been added to the DOM or not.
(FWIW: in retrospect, I regret using the Layout Manager plugin that I linked to and showed. It’s caused me a lot of frustration. I find it far easier to use KendoUI’s “Splitter” control, instead.)
Extracting The onShow Method Call
I’ve written this “onShow” method and the code to call it, a countless number of times. It became such a ubiquitous part of my code that I added it to my “RegionManager” in Backbone.Marionette (a region manager is responsible for managing the rendering, display and closing of a view, for a given region of the screen).
I’ve also found it to be very useful to have two additional methods that are called on my views: onClose and onRender. I specifically have onClose and onRender. onClose is called by the region manager when closing an existing view. onRender, though, is called by my base “ItemView” or “CollectionView” in Marionette, as I’ve extracted the core rendering in to these two objects but still want to provide a way for specific views to take advantage of DOM-independent plugins and UI controls.
Context Is Still King
As always, the patterns and implementations that I’ve shown here are entirely contextual. You’ll likely find scenarios where some DOM-independent code should not be called until after the view’s “el” is part of the DOM, for example. Use your judgement, experience and trial-and-error with the various methods and functions that you have to call to get your behavior correct.
Full Disclosure On KendoUI
I want to be up front about my use of KendoUI in this post. I’m using KendoUI in some of these examples and I link to it directly because I love this control suite. I was, however, given a free Telerik Ultimate subscription so that I could continue using Kendo and the other tools. I was asked to talk about Kendo when appropriate, in return for this subscription. When Telerik offered that to me, I gladly accepted – not because I saved a few hundred $, but because I was going to write this anyways and spend my own $ on the control suite. It was simply a win-win situation for me, to get the free subscription and to help spread the word on a control suite that I love using with Backbone.