Learn how to set up event handlers in your Backbone.js view
In the previous two articles of this series: “Getting Started with Backbone.js Views” (Parts I & II), we learned how to set up a view and optimize it for better performance. The next logical step is event handlers.
While it may be possible that your view will not be interactive, it’s difficult to imagine a mature application that does not involve event handlers. Backbone’s approach to event handlers is a bit of a departure from your standard document.addEventListener and jQuery.click methods. Here, you will add an “events” property to the object that is passed into the Backbone.View.extend method. That “events” property is an object whose key-value pairs are sets strings comprised of an event/selector and event handler.
Example # 1A
1 2 3 |
initialize: function () { this.view = new MessageView({el: $('#main')}); } |
In Example # 1A we have instantiated the MessageView constructor. Implementation details of our Backbone.js router are not at all the focus of this article, but I wanted to point out that when setting up event handlers in a Backbone view, it is important to pass an object to the view constructor. In that object, we have specified an “el” property, whose value is a jQuery DOM object. The reason for this is that it allows Backbone to properly attach our event handlers and then tear down the views DOM elements change.
Example # 1B
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//extend the Backbone.View class var MessageView = Backbone.View.extend({ template: Handlebars.compile( '<div class="messageView mainMessage">' + '<p><b>The Message Is: </b><em>{{message}}</em></p>' + '</div>' ), render: function () { this.$el.html(this.template(this.options)); return this; }, events : { "click .messageView.mainMessage p" : "clickHandler", }, clickHandler : function(){ alert('I was clicked!'); } }); |
In Example # 1B we have added an “events” property to the object that is passed into the Backbone.View.extend method. This property is an object. In this example, that object has one property. The property name is a string that consists of two parts: the name of the event, followed by a CSS selector that identifies the DOM element to be targeted. In this case, the “click” event is specified, and the following CSS selector targets the element: “.messageView.mainMessage p”. Again, that is the key or property name. The value of that property is: “clickHandler“, the name of the function that will handle the event. This example is not very exciting. When the target element is clicked an alert shows the message: ‘I was clicked!’. We can do better.
Example # 1C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//extend the Backbone.View class var MessageView = Backbone.View.extend({ template: Handlebars.compile( '<div class="messageView mainMessage">' + '<p><b>The Message Is: </b><em>{{message}}</em></p>' + '</div>' ), render: function () { this.$el.html(this.template(this.options)); return this; }, events : { "click .messageView.mainMessage p" : "clickHandler", }, clickHandler : function(){ this.$el.find('em').text('I was clicked!'); } }); |
In Example # 1C, we inject the message: “I was clicked” into the DOM, a step up from the alert, but still not too sophisticated. We’ll clean this up in Example # 3.
Example # 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
//extend the Backbone.View class var MessageView = Backbone.View.extend({ template: Handlebars.compile( '<div class="messageView mainMessage">' + '<p><b>The Message Is: </b><em>{{message}}</em></p>' + '<p><i class="reminder">(Click the message abolve to test the click handerl)</i></p>' + '<div class="timestampContainer"></div>' + '</div>' ), render: function () { this.$el.html(this.template(this.options)); return this; }, events : { "click .messageView.mainMessage p" : "clickHandler", "mouseover .messageView.mainMessage p" : "mouseoverHandler", "mouseout .messageView.mainMessage p" : "mouseoutHandler" }, clickHandler : function(){ this.$el.find('em').text('I was clicked!'); }, mouseoverHandler : function(e){ this.$el.find('.messageView.mainMessage').css({ 'background-color' : '#DAA520' }); }, mouseoutHandler : function(e){ this.$el.find('.messageView.mainMessage').css({ 'background-color' : '#ccc' }); } }); |
In Example # 2, we have added two more properties to the “events” object: mouseover and mouseout event handlers. The purpose of this example is to illustrate that you can specify as many event handlers as you need in your “events” object.
Obtaining a Reference to the Target Element
Example # 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
//extend the Backbone.View class var MessageView = Backbone.View.extend({ template: Handlebars.compile( '<div class="messageView mainMessage">' + '<p><b>The Message Is: </b><em>{{message}}</em></p>' + '<p><i class="reminder">(Click the message abolve to test the click handerl)</i></p>' + '<div class="timestampContainer"></div>' + '</div>' ), render: function () { this.$el.html(this.template(this.options)); return this; }, events : { "click .messageView.mainMessage b" : "addTimestamp", "mouseover .timestamp" : "mouseoverHandler", "mouseout .timestamp" : "mouseoutHandler" }, addTimestamp : function(){ renderTimestamp(this.$el); }, addTimestamp : function(){ renderTimestamp(this.$el); }, mouseoverHandler : function(e){ $(e.currentTarget).css({ 'background-color' : '#DAA520' }); }, mouseoutHandler : function(e){ $(e.currentTarget).css({ 'background-color' : '#ccc' }); } }); var AppRouter = Backbone.Router.extend({ routes: { "": "defaultRoute", "message/:text" : "message" }, defaultRoute: function () { //this markup will does not utilize a Backbone view $('#main').html('<div class="mainMessage">This is the default route</div>'); }, initialize: function () { this.view = new MessageView({el: $('#main')}); }, message: function (text) { //pass some data to the view this.view.options.message = text ? text : 'No Message Provided!'; //render the view this.view.render(); } }); var app = new AppRouter(); $(document).ready(function() { Backbone.history.start(); }); |
In Example # 3, we have set up some functionality that is a bit of an improvement over the alert in Example # 1. Each time you click the message, timestamp is injected into the page.
You’ll notice that we are using a function named: “renderTimestamp”. This function is defined in the HTML file. Its implementation details are not particularly important. Suffice to say that when passed a jQuery DOM element object, it injects a time-stamped child element. The purpose of this is simply to demonstrate that we have real-time access to whichever DOM element is the target of an event.
HERE IS THE JS-FIDDLE.NET LINK FOR EXAMPLE # 3: http://examples.kevinchisholm.com/backbone/views/basics/html/part-iii.html
How to Demo:
When the page loads, you will see the default route. If you click “message/hello” or “message/goodbye”, you’ll see our custom routes in action. In either case, the message text has a click handler attached to it.
When you click the message text, you will see a time-stamp injected into the page. No matter how many times you click the message a new time-stamp will be added. When you mouse-over any time-stamp, the background color of that time-stamp will change.
Summary
In this article we learned the basics of how to set up event handlers in a Backbone.js view. We discussed how to specify the “el” property for a view, and then create an “Events” object. We also covered how to configure multiple events, as well as how to reference the target element and manipulate it.
Helpful Links for Backbone.js View Events
http://kevinhamiltonsmith.com/backbone-js-view-dom-events-complete-list/