Advertisement
Scroll to top
Read Time: 8 min
Final product imageFinal product imageFinal product image
What You'll Be Creating

Overview

Backbone views provide a useful convention and abstraction for user interfaces. However, to include UI functionality in your app that Backbone, on its own, was not designed to support, you’ll need to consider how to effectively integrate custom or third-party functionality into your Backbone app. As a result, developers must navigate challenges and avoid tricky conflicts between the external libraries and Backbone.

Intro to Backbone.js

Backbone is a fantastic way to organize your client-side code. With abstractions like models, views, and collections, Backbone helps serious developers write well-organized, scalable applications. 

While there are many alternatives to Backbone, including Angular and Ember, Backbone provides developers with incredible freedom to write and organize their code in natural and comfortable ways without being too opinionated about what the Document Object Model (DOM) looks like.

The Skinny on Backbone Views

Views are one of the most powerful and flexible components in Backbone. According to the authors of Backbone:

Backbone views are almost more convention than they are code — they don’t determine anything about your HTML or CSS for you, and can be used with any JavaScript templating library.

They are used to manipulate what users see in their browser, and they facilitate communication with models. As a result, in the paradigm of Model-View-Controller, it is useful to think about Backbone Views as both view and controller.

This has serious implications when developing applications with significant user interaction. In fact, there are many situations where you might want to use some other library to manipulate the DOM. Data visualization and web-based gaming are two examples where you might prefer to have another library handle some of your user-facing view rendering. As a result, you might consider using jQuery, d3.js, crossfilter, or three.js for some of your DOM manipulation needs.

Fortunately, there are ways to make Backbone play nicely with these other DOM manipulators.

Manipulating the Document Object Model in Backbone

Before we get into it, let’s review DOM manipulation in Backbone. Let’s start with a basic view object.

1
var SomeView = Backbone.View.extend({ 
2
    // Some definition stuff here 

3
}); 
4
5
var aView = new SomeView();

Great. Now, let’s tell the view how to render itself by defining a .render() method.

1
var SomeView = Backbone.View.extend({ 
2
    // define how to render something 

3
    render: function() { 
4
        // get some HTML 

5
        var htmlContent = "<p>This some HTML that will be inserted into the DOM</p>"; 
6
        
7
        // insert the html

8
        this.$el.html(htmlContent); 
9
        
10
        // return an instance of the object for chaining

11
        return this; 
12
    } 
13
});

There are several things going on here, so let’s take it step by step.

Defining a .render() Method

First, we define a .render() method that encapsulates the logic necessary to render HTML. Note that Backbone comes with a .render() method out of the box. However, it doesn’t do anything. It was designed to be overwritten with custom logic!

Getting HTML Content

The above example assumes that you get HTML somewhere. You can use underscores _.template(). Alternatively, we can use other templating libraries, like Handlebars (my personal favorite). All that really matters is that, somehow, we get some HTML content.

What the Hell is el?

We need a place to put the HTML content; that’s what el is for. Like .render(), el is an attribute that comes with Backbone Views out of the box. It references the HTML element (and all its children) contained in this view. In the above example, we did not specify el. By default, el is a div. However, we could have easily set the parent element like so:

1
var SomeView = Backbone.View.extend({ 
2
    el: "article", ... 
3
}); 
4
5
var aView = new SomeView();
6
7
console.log(aView.el); // an empty "article" HTML element

There is also $el, which is just el wrapped in jQuery. We'll see later on that $el plays a powerful role in mastering Backbone views.

Returning this

Finally, we return a reference to the object itself to allow for chaining. While not strictly required, returning this is a convention. Without return this, we would need some way to access the element’s HTML content. The following code illustrates an alternative solution.

1
/** 

2
 * If render() returns nothing, we are really 

3
 * accessing the `el` property of undefined, which does not 

4
 * exist!

5
 */
6
aView.render().el; // Should throw an error 

7
 
8
// Try accessing the HTML 

9
console.log(aView.el); // Should be empty (but defined!) 

10
11
// add HTML to the DOM of 'aView' 

12
aView.render(); 
13
14
// Try accessing the HTML again 

15
console.log(aView.el) // Should contain the HTML

Uhh, Nothing Is on the Screen!

Good point. Even though we called .render(), there isn’t anything on the screen—what gives?

That is because we haven’t interacted with the DOM yet. All we did was generate some HTML and represent it in a JavaScript object called aView. Since we now have access to the generated HTML, all we have to do is append or insert the HTML in your web app’s DOM.

To move things along, we’ll also set up a mini-app so that when the page loads, the view appears. Below are what your HTML and JavaScript should look like.

Basic HTML Setup

1
<html>
2
    <head>
3
        <meta charset="utf-8">
4
        <title>My Awesome Backbone App</title> 
5
        <!-- Include your CSS Here -->
6
        <link rel="stylesheet" type="text/css" href="/css/styles.css" />
7
        
8
        <!-- Include JS dependencies --> 
9
        <!-- Backbone depends on underscore and, in this example, 

10
             depends on jQuery. Please note the order of the 

11
             dependencies --> 
12
        <script src="/js/lib/jquery.js"></script>
13
        <script src="/js/lib/underscore.js"></script>
14
        <script src="/js/lib/backbone.js"></script>    
15
    </head>
16
    <body>
17
        <div class="app"></div> 
18
        <!-- Include your custom Backbone code in the below script -->
19
        <script src="/js/app.js"></script>            
20
    </body>
21
</html>

Here’s What Is Going On in App.js

1
// Create a view 

2
var SomeView = Backbone.View.extend({ 
3
    initialize: function() {}, 
4
    render: function() { 
5
        var someHTML = "<p>This is some HTML</p>"; 
6
        this.$el.html(someHTML); 
7
        return this; 
8
    } 
9
}); 
10
11
// Create a router

12
var Router = Backbone.Router.extend({ 
13
    // define your routes 

14
    routes: { "": "home" }, 
15
    home: function() { 
16
        var aView = new SomeView(); 
17
        $('.app').html(aView.render().el); 
18
    } 
19
}); 
20
21
// Instantiate your router 

22
new Router(); 
23
24
// Start tracking history 

25
Backbone.history.start();

Go to your local server/browser, load up the page, and your application should be running!

Using Backbone and jQuery Simultaneously

Backbone’s flexibility allows our use of third-party libraries to manipulate the DOM. One scenario is when you want to use jQuery and Backbone simultaneously to manipulate your views. Below is an updated example.

1
var SomeView = Backbone.View.extend({ 
2
    
3
    // Manipulate DOM indirectly by creating HTML content in a 

4
    // Backbone View 

5
    render: function() { 
6
        var someHTML = "<p>Some HTML</p><p class='empty'><p>"; 
7
        this.$el.html(someHTML); 
8
        return this;
9
    }, 
10
    
11
    // Manipulate DOM directly from within the Backbone View

12
    renderWithJQuery: function() { 
13
        var otherHTML = "<p>Other HTML</p>"; 
14
        $('.app').append(otherHTML); 
15
        
16
        // may not make sense to return 'this' 

17
    }, 
18
    
19
    // another render method, to keep things interesting 

20
    specialRender: function() { 
21
        this.$('.empty').append("<span>No longer empty!</span>"); 
22
        return this; 
23
    } 
24
}); 
25
26
// Later in your app... 

27
28
// create the view 

29
var aView = new SomeView(); 
30
31
// change the DOM to reflect the newly created view 

32
$('.app').html(aView.render().el); 
33
34
// append more content directly to the DOM using jQuery within 

35
// a Backbone view object 

36
aView.renderWithJQuery();

The code above will result in two paragraphs on the page. The first paragraph contains “Some HTML”. The second paragraph contains “Other HTML”.

To test your understanding of this, reverse the method calls like so:

1
// SomeView is already defined 

2
3
var aView = new SomeView(); 
4
5
aView.renderWithJQuery(); 
6
7
$('.app').html(aView.render().el);

The code above will result in one paragraph: “Some HTML”. In both cases, there is also a <p> element with nothing in it. We’ll discuss this in a moment.

Manipulating the DOM in Backbone Views Efficiently

Understanding the magic of efficient DOM manipulation (and traversal) requires an understanding of this.$el and this.$(). By using this.$el, we are scoping DOM manipulation to the content contained in the view. By using this.$(), we are scoping DOM traversal to the DOM tree within the view.

As a result, in the Backbone context, some uses of $() (instead of this.$()) could be inefficient. For example, let’s say we wanted to traverse the DOM to find some element. We might use any of the common DOM traversal methods, including .find(), .children(), .closest(), .first(), and so on.

If we know, a priori, that the element we seek lies somewhere within the view’s DOM, then we should use this.$() to avoid searching a larger DOM tree unnecessarily. If the element we seek lies outside of the view’s DOM, then we’ll need to use $().

For example, the .specialRender() method uses localized DOM traversal to ensure that we search for elements with class empty within the context of the view. If found, it sets the HTML content of those elements to include a span and the text "No longer empty".

Conclusion

In this article we reviewed Backbone views, discussed how to render Backbone views in the DOM, and explored how to make Backbone play nicely with other libraries you might want to use to manipulate the DOM. We also learned about localized DOM traversal and identified methods to efficiently and inefficiently traverse the DOM.

The next part of this article will delve deeper into more complicated examples of getting multiple libraries to work together in manipulating the DOM.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.