Académique Documents
Professionnel Documents
Culture Documents
Swarnendu De
Chapter 4, Working with Collections, covers a number of common problems that developers face while using Backbone collections. We explain how to apply basic and multiple sorting, how to apply filtering to a collection, and how to manage a collection while a mixed set of data is passed from the server. Chapter 5, Routing Best Practices and Subrouting, covers a number of best practices you should follow while working with routers. We also discuss the benefits of using multiple routers or subrouters for complex and large-level applications. Chapter 6, Working with Events, Sync, and Storage, begins by describing the importance of custom events to enhance an application's modularity and reusability. We also discuss using an application-level event manager to work as a centralized PubSub system, and the use of the method to create different data-persistent strategies. Chapter 7, Organizing Backbone Applications Structure, Optimize, and Deploy, is one of the most important chapters that a developer will find very useful if they are developing a complex Backbone application. It talks about the application directory structure, organizing and managing fi les with RequireJS, and the different architectural patterns that every JavaScript developer should follow to develop large-scale application architectures. Chapter 8, Unit Test, Stub, Spy, and Mock Your App, talks about the benefits of unit testing your JavaScript application, and introduces you to the QUnit and SinonJS test frameworks. Appendix A, Books, Tutorials, and References, lists a number of useful Backbone.js resources that you may find helpful. Appendix B, Precompiling Templates on the Server Side, describes the benefits of precompiling JavaScript templates at server side with examples. Appendix C, Organizing Templates with AMD and Require.js, discusses the process of storing and organizing JavaScript templates with the RequireJS, text!, and tpl! plugins.
The routes and actions that will be triggered when the URL fragment matches the specic routes are dened in the routes object of the router:
routes: { 'users' : 'showUsers', 'user/:id' : 'showUserDetails', 'user/:id/update' : 'updateUser' }
Now, let's see how we can create a basic router. Assume that we are developing an application with a few modules, among which the User module is an important one.
var AppRouter = Backbone.Router.extend({ routes: { 'users': 'showUsers', 'user/:id': 'showUserDetails', 'user/:id/update': 'updateUser', 'user/:id/remove': 'removeUser' }, showUsers: function () { // Get all the user details from server and // show the users view }, showUserDetails: function (userId) { // Get the user details for the user id as received }, updateUser: function (userId) {}, removeUser: function (userId) {} });
[ 86 ]
Chapter 5
Quite simple! There are a number of options that modify the routes to get the expected result. For example, you can use "splats" or optional parts in a route; for a detailed overview of routes, refer to the Backbone.js API at http://backbonejs.org/#Router. In the preceding example, all the show methods (showUsers() and showUserDetails()) will most likely create the view instances, send AJAX requests to the server to get their details, and then show the views in the DOM. Similarly, the update and delete methods will also send requests to the server for the desired actions to be taken. Now, assume the User module has multiple other methods in this router along with these CRUD methods. In addition, the entire application has a number of similar modules whose routes will also get added to this router. As a result, the router will soon become a gigantic one with hundreds of lines of code; this is something that is beyond our control. We should take care of a few things while working with routers and avoid such situations. We will look at some good practices in the following section that will make our routers simple, exible, and easy-to-maintain.
This looks simple and works perfectly. But will it not clutter the router if there are 20 or more such methods? Why not create a controller or a high-level application object and add the method there? Then you can call this controller method from the router method as follows:
Backbone.Router.extend({ routes: { "users": "showUsers" }, showUsers: function() { UserController.showUsers(); } }); var UserController = { showUsers: function() { var usersView = new UsersView(); usersView.render(); $("#user_list").html(usersView.el); } }
[ 88 ]
Chapter 5
Now any change in the showUsers() method functionality will not force you to touch the router. There's really not much of a visible differencebut personally, as I have used the second pattern several times and beneted from it, I can guarantee you that the separation of concern will produce a much cleaner router along with a maintainable code base. Also, in this context, we recommend you check out Marionette.AppRouter (https://github.com/marionettejs/backbone.marionette/blob/master/ docs/marionette.approuter.md) and Marionette.Controller (https://
github.com/marionettejs/backbone.marionette/blob/master/docs/ marionette.controller.md). Marionette AppRouter and Controller work in the same way as our UserController and the base router. The controller actually
does the work (such as assembling the data, instantiating the view, displaying them in regions) and can update the URL to reect the application's state (for example, displayed content). The router simply triggers the controller action based on the URL that has been entered in the address bar. Both these classes are quite useful, and you can go for either of them if needed.
The solution is that you can add the regular expression in the routes object in the initialize() method of the router:
initialize: function () { this.route(/^user\/(\d+)/, 'showUserDetails'); }, showUserDetails: function (id) { console.log(id); } [ 89 ]
This is an example where only numbers are allowed in the URL fragment after #user. If you try to open a URL ending with #user/abc, the showUserDetails() method will not be called, but with the URL fragment #user/123, the same method will be triggered. So, this is a very generic example of using a regular expression as a route. Regular expressions are very useful for more complex levels of URL fragments in order to provide a level of restriction.
[ 90 ]
Chapter 5 'company/:id': 'showCompanyDetails', 'company/users': 'showCompanyDetails' }, showHome: function () {}, doLogout: function () {}, showUserDetails: function () {}, searchUsers: function () {}, showCompanyDetails: function () {}, showCompanyDetails: function () {}, });
Now, let's use Backbone.Subroute and see how to dene the base router and module-specic routers. With Subroute, the base router becomes a tiny router that only takes care of the router redirections.
Routing Best Practices and Subrouting if (!App.companyRouter) { App.companyRouter = new App.CompanyRouter('/company'); } }, });
Look at the base router. What we are doing here is pretty simplewe use a wildcard (or splat) to trigger a method that lazily instantiates a subrouter and passes the initial parameter of the hash. Now, because Backbone.Subroute extends Backbone's Router class, we can expect that anything passed after /users/ or /company/ should be taken care of by the respective subrouter, that is, App.UsersRouter or App.CompanyRouter. We can add as many subrouters as we want and the base router won't care about it. Similarly, the subrouters do not know what prex they have. Any changes in the module name or prex should be done only in the base router without modifying the related subrouter.
Backbone.Subroute is a small yet excellent plugin that you should always include
in your application to keep your base router clean. The more modules get added to your application, the more you will understand the benet of subrouters.
[ 92 ]
Chapter 5
Summary
The functionality of the Backbone router is quite simple and easy to learn. For a simple application, you will not nd any problems in maintaining it. The issues will start creeping in once your application grows and your router becomes huge. In this chapter, we discussed the best practices of router management, those that you should always adhere to. We also learned about subrouting, which helps by splitting up the main router into multiple module-specic routers and dividing the tasks among them. In the next chapter, we will discuss Backbone events, custom events, storages, and sync.
[ 93 ]
Alternatively, you can buy the book from Amazon, BN.com, Computer Manuals and most internet book retailers.
www.PacktPub.com