Single page application with Backbone.js on Rails

If you want to start a single page application (SPA) with a heavy front-end interface and you don’t have time to build your own Javascript MVC – you should definitely choose Backbone.js.

We are currently building a SPA that talks to an API written on Ruby on Rails. Choosing the right MVC Javascript framework from start was a crucial thing. From all frameworks released in the wild the most suitable ones for me seem to be Sammy.js and Backbone.js.

Judging by the features of the framework I could have chosen Sammy.js. It has a nice API and useful functions that Backbone.js is lacking. The multiple template type support for Sammy is also a plus.

On the other hand, Backbone.js seemed to be pretty wild and small compared to Sammy. The default templating system is Underscore.js that seemed to be pretty simple, based on micro templates.

After some testing I went with Backbone.js. The fact that it’s light and integrates beautifully with Ruby on Rails accentuated the choice. The missing features can be easily added by some extra programming. The micro templates are faster compared to HAML or Mustache. The only ugly thing is the pour readability of the templates but the new Rails has a cure for this, providing the integration of Jammit templates that are automatically compiled to micro templates on the first app run with the help of the jammit gem. Same thing with the CoffeScript files that are automatically compiled to javascript and glued on the first run.

A very important thing is to keep an intuitive app structure on front-end (which I didn’t do in the beginning). Keep all the models, collections, routers and views in separate files and folders. The most suitable structure for our team was this one:

/assets
    /javascripts
        /app
            /models
                user.coffee
                profile.coffee
                comment.coffee
            /collections
                users.coffee
                comments.coffee
            /routers
                main.coffee
            /views
                /users
                    add.coffee
                    list.coffee
                    search.coffee
                /profiles
                    edit.coffee
                    list.coffee
                /comments
                    add.coffee
                    list.coffee
            app.coffee
            index.js

The app.coffee has the main router initialization and also the templates manager configuration and loading. index.js has a list of all the files that have to be loaded and converted to raw javascript.

As for the templates loading and caching I used my custom jQuery plugin that I forked from markdagleish on GitHub and adjusted so it integrates smoothly with Undercore.js.

Backbone.js didn’t disappoint me so far. Seems to be simple, easy, light and fun. Tried it with Rails and NodeJS. Integrates very well with jQuery and Zepto.js. Use it with no fear :)

jQuery Doom Windows Plugin – Simple Javascript Dialogs

Looking for a tiny modal dialogs library? Then this one is for you.

Doom Windows is easy to style, configure and extend. It also has a couple of shortcut functions that make it easy to use.

Display modal dialogs, confirm windows and alerts in one line of code: dAlert(‘Error!’), dConfirm(‘Are you sure?’), dWindow(‘<p>Text</p>’).

I created this plugin because I wanted to get rid of jQuery UI in my projects as it was too big and slow.

Easy steps to include the plugin:

  1. Include the doom_windows_style.css style
  2. Include the jquery.doomWindows.js file
  3. Make windows: dWindow(‘<img src=”http://maps.google.com/maps/api/staticmap?center=40.714728,-73.998672&zoom=14&size=400×400&sensor=false” alt=”Google Maps” width=”400″ height=”400″ />’)

Implementation examples

Display Google Maps in a separate dialog:

$('#view-map-bt').click(function () {
	dWindow('<img src="http://maps.google.com/maps/api/staticmap?center=40.714728,-73.998672&zoom=14&size=400x400&sensor=false"
 alt="Google Maps" width="400" height="400" />');
});

//or:

$('#view-map-bt').click(function () {
	$('<img src="http://maps.google.com/maps/api/staticmap?center=40.714728,-73.998672&zoom=14&size=400x400&sensor=false"
 alt="Google Maps" width="400" height="400" />').doomWindows({buttons:false, buttonClick: function (btType, win) {btType === 'close' && win.close();}});
});

Confirm modal box:

$('#view-map-bt').click(function () {
	dConfirm('Are you sure you want to delete this item?', function (btType, win) {
		(btType === 'no' || btType === 'close') && win.close();
		if (btType === 'yes') {
			// some ajax to delete item here
			win.close();
			dAlert('Item deleted!');
		}
	});
});

Alert modal:

$('#alert-bt').click(function () {
	dAlert('Omg! A fake error occured! Do not panic!');
});

Load remote content with Ajax:

$('#remote-bt').click(function () {
	dWindow(false, {
		ajaxUrl: $(this).attr('href'),
		cacheAjaxResult: true,
		wrapperId: 'log-in-window',
		minHeight: 317,
		minWidth: 430
	});
	return false;
});

Please check out for more examples on the DEMO page.

Advanced options that can be set:

styles ({position: ‘absolute’, ‘z-index’: 999, top: false, left: false}):
Window default styles.
width (‘auto’):
Set up a custom width of the window.
height (‘auto’):
Set up a custom height of the window.
minWidth (‘auto’):
Set up a custom min-width style.
minHeight (‘auto’):
Set up a custom min-height style.
overlay: (true):
Show or hide window overlay.
wrapp: (true):
Buy default the content is wrapped in a div of ‘doom-win’ class.
wrapperClass (‘doom-win’):
Set the deafult wrapper class.
wrapperId (false):
Give a unique id to your window so it’s easier to style it.
wrapperHtml (‘<div><div class=”doom-win-content”></div></div>’):
Set up a custom html window wrapper.
buttons ({ok:’Ok’}):
Bottom buttons and button text.
headerButtons ({close:’Close’}):
Header buttons and button text.
buttonsTranslate ([]):
Text translate for buttons.
buttonsTranslate (‘<div class=”doom-win-bt-cnt-header”><ul class=”doom-win-bt-list”>{buttons}</ul></div>’):
Header buttons html wrapper structure.
buttonsWrapperHtml (‘<div class=”doom-win-bt-cnt”><ul class=”doom-win-bt-list”>{buttons}</ul></div>’):
Bottom buttons html wrapper structure.
buttonHtml (‘<li class=”doom-win-bt-{buttonType}”><button data-type=”{buttonType}”><span>{buttonText}</span></button></li>’):
Message button HTML structure.
buttonClick (null):
A callback function when for all the buttons. Get the buttons key (ok, close, yes, no) and the window object as args. I.e.: function (btType, win) {btType === ‘close’ && win.close();}
closeOnEsc (true):
Close window on Escape keyboard button click.
ajaxUrl (null):
Set the ajax url if you want to load content remotely.
afterAjax (null):
After ajax callback function. Gets the ajax response as arg.
ajaxData (null):
Set some custome request query params for ajax.
cacheAjaxResult (false):
Set this if you want the ajax content to be cached in the browser.
onShow (null):
Callback function after the window is created and displayed.
Please support this free plugin developement and

jQuery Novice To Ninja – Book Review

jQuery Novice To Ninja Book Review

Recently a friend asked me what will be a good book to start learning jQuery with a more practical approach. My answer was ‘jQuery Novice To Ninja’ by Earle Castledine and Craig Sharkie. It was a really fun book to read with a lot of code examples.

You start by learning about the jQuery syntax, objects and chaining then you go deeply into how to build beautiful animations, custom events and plugins. You are introduced to jQuery UI and how to use it properly.

The book contains a lot of info about Ajax requests and how to handle them easily with jQuery.

In the end you can find some code examples about how to build a rating stars mechanism, some UI tools and plugins.

I also found some code snippets saved from the book that I can share.

Effects

Toggle vieweing with isVisible:

$('#toggleButton').click(function() {
	if ($('#disclaimer').is(':visible')) {
		$('#disclaimer').hide();
	} else {
		$('#disclaimer').show();
	}
});

Animate elements on scroll, make the site header scroll with the page:

$(window).scroll(function() { 
	$('#header').css('top', $(document).scrollTop()); 
});

//or

$(window).scroll(function() {
	$('#header').stop().animate({top: $(document).scrollTop()},'slow','easeOutBack');
});

Scroll to top animation quirck for all browsers:

$('a[href=#]').click(function() {
	$('html, body').animate({scrollTop: 0},'slow'); 
	return false; // Return false to cancel the default link action
}

Switch from fluid to fixed layout:

if ($('body').width() > 900) {
	$('')
	.appendTo('head');
} else {
	$('link[href=wide.css]').remove();
}

Preload images:

$('');

Remove selective elements:

$('#celebs tr').remove(':contains("Singer")');

Timers:

setInterval(function() {
	$('#green').css('left', ++greenLeft);
}, 200);

var redLeft = parseInt($('#red').css('left'));
function moveRed() {
	setTimeout(moveRed, 200);
	$('#red').css('left', ++redLeft);
}
moveRed();

clearInterval();
clearTimeout();

Ajax

Basic usage:

$('#biography').load('computadors.html div:first');
$('div#results').load('search.php', 'q=jQuery&maxResults=10');
$.ajaxSetup({
	type: 'POST'
	url: 'send.php',
	timeout: 3000
});

Access Ajax global events (ajaxSuccess, ajaxSend, ajaxComplete, ajaxError, ajaxStop):

$("#msg").ajaxError(function(event, request, settings) {
	$(this).html("Error requesting page " + settings.url + "!");
});
$('#ajaxInProgress').ajaxStart(function() { 
	$(this).addClass('progress'); 
}).ajaxStop(function() { 
	$(this).removeClass('progress');
});

Get number of ajax requests:

$.active

Load external script in your code:

$.getScript('http://view.jquery.com/trunk/plugins/color/jquery.color.js', function() {
	$('body').animate({'background-color': '#fff'}, 'slow');
});

Plugins

Wrapp your plugin:

function($) {
	// Shell for your plugin code
	$.fn.highlightOnce = function() {
		// Plugin code
	}
})(jQuery);

Set plugin defaults:

$.fn.highlightOnce.defaults = {
	color : '#fff47f',
	duration : 'fast'
};

Create your own selectors:

$.extend($.expr[':'], {
	abovethefold: function(el) { 
		return $(el).offset().top < $(window).scrollTop() + $(window).height();
	}
});

Events

Create event:

// Home-made event object!
var e = $.Event('click');
e.pageX = 100;
e.pageY = 100;
$('p').trigger(e);

Get events with:

$('element').data('events');

Namespace your events:

$('p').bind('mouseover.colorize', function() {
	$(this).css('background-color', 'lemonchiffon') 
}).bind('mouseout.colorize', function() { 
	$(this).css('background-color', '');
}).click(function() {
	$(this).trigger('mouseout.colorize').unbind('.colorize');
});

Trigger non-namespaced events:

$('p').trigger('mouseout!');

Handle custom events like mobile touch events:

$(document).bind('touchstart', function(e) {
	var original = e.originalEvent;
	var x = original.changedTouches[0].pageX;
	var y = original.changedTouches[0].pageY;
	$('#block').css({top: y, left: x});
});

Define your sepcial events (never used this):

jQuery.event.special.multihover = {
	setup: function(data, namespaces) {
	// Do when the first event is bound
	},
	add: function(handler, data, namespaces) {
		// Do every time you bind another event
	},
	remove: function(namespaces) {
		// Do when an event is unbound
	},
	teardown: function(namespaces) {
		// Do when the last event is unbound
	},
	handler: function(e) {
		// Do your logic
	}
}

Other stuff

Use .one(‘mouseover’, function (){}) to bind the event once.

Call functions with call to pass the scope:

// Fire the setUp callback in a plugin
$.isFunction(options.setup) && options.setup.call(this);

Use utility functions:

$.isArray(), $.isFunction(), $.isEmptyObject(), $.isPlainObject()

Use andSelf to add current elemnt to the jQuery selector:

$(this).prevAll().andSelf().addClass('rating-over');

Use attributes functions to filter elements:

$(list).children().attr('selected', function(i, selected) {
	return !selected;
});

Use toggleClass with function:

$(this).toggleClass('opened', x == 1);

Use pushStack to add elements to the stack:

jQuery.fn.surrounds = function() {
	var prev = this.index() == 0 ? 
	this.siblings(':last') : 
	this.prev();
	var next = this.index() == this.siblings().length ? 
	this.siblings(':first') : 
	this.next();
	var newStack = prev.add(next);
	return this.pushStack(newStack, 'surrounds', '');
};
$('#categories li:first').surrounds().css('color', 'red').end().css('color', 'blue');

Some knowledge about Javascript bad parts:

JavaScript treats all these values as truthy:

  • true
  • 1 (because it’s a non-zero number)
  • ’0′ (because it’s a non-empty string)
  • ‘false’ (because it’s a non-empty string)
  • function() {} (any function)
  • {} (any object)
  • [] (any array)

And these values are falsy:

  • false
  • 0 (the number zero)
  • ” (an empty string)
  • null
  • undefined
  • NaN (a special number value meaning Not a Number)

Nice book to begin learning jQuery. What else can you recommend?

Shuffle Arrays with Javascript

Working with random values in Javascript is like leaving in a cave. The only thing you can work with is Math.random() that returns a random number between 0 and 1. If you need a 0 to 10 value – multiply it by 10 (parseInt(Math.random()) or Match.floor(Math.random() * 10)) … That’s all random stuff you have in Javascript.

I needed a shuffling function to randomize one Array’s elements so the only thing was to build one:

 
// Add new property to javascript array object
Array.prototype.shuffle = function() {
	for (var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
	return this;
};

Attache it to the Array prototype object so you can access it as object’s own method:

 
alert([1, 2, 3, 4, 5].shuffle());
alert(['one', 'two', 'three', 'four', 'five'].shuffle());

Do you have any other ideas or functions to improve the randomize process in Javascript?

jQuery Performance Tips Cheat Sheet

I was hunting for jQuery performance tricks for a while to tune my heavy dynamic web app. After digging in a lot of articles decided to make a list of the best common performance tips. I also built a handy jQuery Performance Cheat Sheet that can be printed or placed on my desktop.

Selectors performance tips:

1. Always Descend From an #id

This is the golden rule of the jQuery selectors. The fastest way to select an element in jQuery is by ID:

$('#content').hide();

or select multiple elements descending from an ID:

$('#content p').hide();
2. Use Tags Before Classes

The second fastest selector in jQuery is the Tag selector ($(‘head’)) because it maps to a native JavaScript method, getElementsByTagName(). The best way is to prefix a class with a tag name (and descend from an ID):

var receiveNewsletter = $('#nslForm input.on');

The class selector is among the slowest selectors in jQuery; in IE it loops through the entire DOM. Avoid using it whenever possible. Never prefix an ID with a tag name. For example, this is slow because it will loop through all <div> elements looking for the ‘content’ ID:

var content = $('div#content'); // VERY SLOW, AVOID THIS

Also, DON’T descend from multiple IDs:

var traffic_light = $('#content #traffic_light'); // VERY SLOW, AVOID THIS
3. Use Sub-queries

Cache the parent object then run queries on it:

var header = $('#header');

var menu = header.find('.menu');
// or
var menu = $('.menu', header);

See live example →

4. Optimize selectors for Sizzle’s ‘right to left’ model

As of version 1.3, jQuery has been using the Sizzle Javascript Selector Library which works a bit differently from the selector engine used in the past. Namely it uses a ‘right to left’ model rather than a ‘left to right’. Make sure that your right-most selector is really specific and any selectors on the left are more broad:

var linkContacts = $('.contact-links div.side-wrapper');

instead of:

var linkContacts = $('a.contact-links .side-wrapper');
5. Use find() rather than context

Indeed, the .find() function seems to be faster. But this counts more when you have a lot of traversing a page with lots of DOM elements:

var divs = $('.testdiv', '#pageBody'); // 2353 on Firebug 3.6
var divs = $('#pageBody').find('.testdiv'); // 2324 on Firebug 3.6 - The best time
var divs = $('#pageBody .testdiv'); // 2469 on Firebug 3.6
6. Harness the Power of Chaining

It’s better to chain the jQuery methods than to cache the selectors:

$('li.menu-item').click(function () {alert('test click');})
                     .css('display', 'block')
                     .css('color', 'red')
                     fadeTo(2, 0.7);
7. Write your own selectors

If you have selectors that you use often in your script – extend jQuery object $.expr[':'] and write your own selector. In the next example I create a selector abovethefold that returns a set of elements that are not visible:

$.extend($.expr[':'], {
	abovethefold: function(el) {
		return $(el).offset().top < $(window).scrollTop() + $(window).height();
	}
});
var nonVisibleElements = $('div:abovethefold'); // Select the elements

DOM manipulation performance tips:

8. Cache jQuery Objects

Cache elements that you query often:

var header = $('#header');
var divs = header.find('div');
var forms = header.find('form');
9. Wrap everything in a single element when doing any kind of DOM insertion

DOM manipulation is very slow. Try to modify your HTML structure as little as possible.

var menu = '<ul id="menu">';
for (var i = 1; i < 100; i++) {
    menu += '<li>' + i + '</li>';
}
menu += '</ul>';
$('#header').prepend(menu);

// Instead of doing:

$('#header').prepend('<ul id="menu"></ul>');
for (var i = 1; i < 100; i++) {
    $('#menu').append('<li>' + i + '</li>');
}
10. Use object detection even if jQuery doesn’t throw an error

It’s great that jQuery methods don’t throw a ton of errors at your users, but that doesn’t mean that as a developer you should just rely on that. Even though it won’t throw an error, jQuery will have to execute a number of useless functions before determining that an object doesn’t exist. So use a quick object detection before calling any methods on a jQuery object that may or may not exist.

11. Use direct functions rather than their convenience counterparts

For better performance you can use direct functions like $.ajax() rather than $.get(), $.getJSON(), $.post() because the last ones are shortcuts that call the $.ajax() function.

12. Store jQuery results for later

Usually you have a general javascript application object – App. Keep your often used jQuery selects in it for later:

App.hiddenDivs = $('div.hidden');
// later in your application:
App.hiddenDivs.find('span');
13. Use jQuery’s internal data() method to store state

Don’t forget about using .data() function to store stuff for your elements:

$('#head').data('name', 'value');
// later in your application:
$('#head').data('name');
14. Use jQuery’s utility functions

Don’t forget about jQuery Utilities functions that can be very handy. My favorites are $.isFunction(), $.isArray() and $.each().

15. Add a JS class to your HTML attribute

Firstly, as soon as jQuery has loaded you use it to add a “JS” class to your HTML tag.

$('HTML').addClass('JS');

Because that only happens when javascript is enabled, you can use it to add CSS styles which only work if the user has JavaScript switched on, like this…

/* In your css */
.JS #myDiv{display:none;}

So, what this means is that we can hide content when JavaScript is switched on and then use jQuery to show it when necessary (e.g. by collapsing some panels and expanding them when the user clicks on them), while those with JavaScript off (and search engine spiders) see all of the content, as it’s not hidden. I’ll be using this one a lot in the future.

Read more on this →

Events performance tips:

16. Defer to $(window).load

Sometimes it’s faster to use $(window).load() than $(document).ready() because the last one occurs before all the DOM elements are downloaded. You should test this before you use it.

17. Leverage Event Delegation (a.k.a. Bubbling)

When you have a lot of elements in a container and you want to assign an event to all of them – use delegation to handle it. Delegation provides you with the ability to bind only one event to a parent element and then check on what child the event acted (target). It’s very handy when you have a big table with a lot of data and you want to set events to the TDs. Grab the table, set the delegation event for all the TDs:

$("table").delegate("td", "hover", function(){
	$(this).toggleClass("hover");
});

Read more →

18. Shorthand for the ready event

If you want to save some bits on compressing your js plugin – replace the $(document).onready() event:

// Instead of:
$(document).ready(function (){
    // your code
});

// you can do:

$(function (){
    // your code
});

Testing jQuery:

19. jQuery Unit Testing

The best way to test a Javascript code is the human way :) But, you still can use some automated tools like Selenium, Funcunit, QUnit and QMock to test your code (especially plugins). I will discuss this in another post because there’s a lot to say about it.

20. Benchmark Your jQuery Code

Always benchmark your code and see which query is slower to replace it. You can achieve this with the Firebug console. Also you can use some of my jQuery shortcut functions to make your testing easier:

// Shortcut to log data to the Firebug console
$.l($('div'));

// Get the UNIX timestamp
$.time();

// Log the execution time of a JS block to Firebug
$.lt();
$('div');
$.lt();

// Run a block of code in a for loop to test the execution time
$.bm("var divs = $('.testdiv', '#pageBody');"); // 2353 on Firebug 3.6

General jQuery performance tips:

21. Use latest version of jQuery

The newest version is usually the best one. Also don’t forget to test your code after changing your jQuery core version. Sometimes it’s not fully backward compatible.

22. Use HTML 5

The new HTML 5 standard comes with a lighter DOM structure in mind. Lighter DOM structure means less elements to traverse for jQuery and better load performance. So, switch to it when possible.

23. Append style tags when styling 15 or more elements

When styling a few elements it is best to simply use jQuery’s css() method, however when styling 15 or more elements it is more efficient to append a style tag to the DOM. This way you get rid of hard coding styles in your scripts.

$('<style type="text/css"> div.class { color: red; } </style>')
.appendTo('head');
24. Don’t load code that isn’t needed

It’s a good technique to break your Javascript code in multiple files and load them only on the pages that need them. This way you don’t load unnecessary JS code and selectors. It’s also easy to manage your code this way.

25. Keep download times to a minimum with one compressed master JS file.

After you decide what javascript files you want to load – compress them and glue in one file. This can be done automatically with open source tools like Minify integrated in your backend code or combining them and minifying with online tools like JSCompressor , YUI Compressor or Dean Edwards JS packer. I prefer the JSCompressor from the online tools.

26. Combine jQuery with raw Javascript where needed

It’s a beauty to work with jQuery but don’t forget that it’s just a framework for Javascript. So you can switch between jQuery code and raw Javascript functions where needed to gain more performance.

27. Load the framework from Google Code

Always load jQuery from Google CDN in your production application – it delivers the script fast from the user’s nearest cache location.
This way you save a server request and also the client has the chance to load the jQuery script instantly from his browser cache if he visited another site that loads the jQuery from Google CDN.

// Link the minified version by specific version
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
28. Lazy load content for speed and SEO benefits

Load chunks of your sites by Ajax to save server side loading time. You can start with the usual sidebar widgets.

Special thanks to Paul Irish, Addy Osmani, Jon Hobbs-Smith and Dave Artz for providing lots of information about jQuery performance.

Thanks to @maxescu who designed this beautiful wallpapers!

What other jQuery performance tips do you suggest?

Please support this wonderful wallpapers and

Switch to our mobile site