Backbone.js	
	




    Обзор
Что	даёт?	
• Наследование	
• Модели	(Models)	
• Коллекции	[Underscore	JS]	
• Представления	(Views)	
• Событийно‑ориентированные	коммуникации	
  (Events)	
• Персистентность	(Sync)	
    – возможность	прозрачного	сохранения	состояния	своих	объектов	в	
      промежутках	времени	между	запусками	программ	

• Маршрутизация	и	HTML5	pushState	
• Потенциальная	возможность	тестирования	
  (Jasmine/QUnit/SimonJS)
Модели	
• Модель	‑	это	одна	запись.	
• Содержит	интерактивные	данные	
• Реализует	
   –   Конвертацию	
   –   Валидацию	
   –   Вычисление	свойств	
   –   Контроль	доступа	
• Реализуется	посредством	наследования	стандартного	класса	
  Backbone.Model	
• Базовый	класс	набор	необходимых	и	вспомогательных	

  методов	для	работы	со	свойствами	(get/set,	escape,	has,	
  toJSON,	fetch,	isValid,	validate,	save	и.т.п.)
Пример	
                                    	




var	Photo	=	Backbone.Model.extend({
				defaults:	{
								src:	'placeholder.jpg',
								title:	'an	image	placeholder',
								coordinates:	[0,0]
				},
				initialize:	function()	{
								this.on("change:src",	function()	{
												var	src	=	this.get("src");
												console.log('Image	source	updated	to	'	+	src);
								});
				},
				changeSrc:	function(	source	)	{
								this.set({	src:	source	});

				}
});

var	somePhoto	=	new	Photo({	src:	"test.jpg",	title:"testing"});
somePhoto.changeSrc("magic.jpg");	//	which	triggers	"change:src"	and	logs	update
Пример	валидации	
                  	




var	Photo	=	Backbone.Model.extend({
				validate:	function(attribs){
								if(attribs.src	===	undefined){
												return	"Remember	to	set	a	source	for	your	image!";
								}
				},

				initialize:	function(){
								console.log('this	model	has	been	initialized');
								this.on("error",	function(model,	error){
												console.log(error);
								});
				}
});


var	myPhoto	=	new	Photo();
myPhoto.set({	title:	"On	the	beach"	});
//logs	Remember	to	set	a	source	for	your	image!
Коллекции	
• Позаимствованы	из	http://underscorejs.org/	
   – Унаследовали	все	методы	
• Множество	моделей,	для	которого	реализованы:	
   – Фильтрация	
   – Сортировка	
   – Агрегация	
• Реализуются	посредством	наследования	стандартного	класса	
  Backbone.Collection	
• Базовый	класс	также	реализует	полезные	методы	(get,	set,	
  length,	push,	pop,	sort,	create,	fetch,	pluck,	where,	...)	

• Позволяют	централизовано	работать	с	несколькими	моделями	
• Можно	написать	свой	comparator
Пример	коллекции	
                 	




var	PhotoCollection	=	Backbone.Collection.extend({
				model:	Photo
});	
	
var	a	=	new	Photo({	title:	'my	vacation'}),
				b	=	new	Photo({	title:	'my	holiday'}),
				c	=	new	Photo({	title:	'my	weekend'});

var	photoCollection	=	new	PhotoCollection([a,b]);
photoCollection.add(c);

photoCollection.remove([a,b]);
photoCollection.remove(c);
Пример	коллекции	
                   	




var	PhotoCollection	=	new	Backbone.Collection();
PhotoCollection.on("add",	function(photo)	{
		console.log("I	liked	"	+	photo.get("title")	+	'	it's	this	one,	right?	'		+	photo.get("src"));
});

PhotoCollection.add([
		{title:	"My	trip	to	Bali",	src:	"bali‑trip.jpg"},
		{title:	"The	flight	home",	src:	"long‑flight‑oofta.jpg"},
		{title:	"Uploading	pix",	src:	"too‑many‑pics.jpg"}
]);	
	
var	sortedByAlphabet	=	PhotoCollection.sortBy(function	(photo)	{
				return	photo.get("title").toLowerCase();
});
Представления	
• Главная	идея	‑	собрать	интерфейс	из	
  представлений,	связанных	с	моделью	
• Реиспользуемый	элемент	
  пользовательского	интерфейса	
• Не	содержит	вёрстку	документа	
• Часто	ассоциирован	с	моделью	

• Создается	посредством	наследования	
  базового	класса	Backbone.View
Пример	представления	
           	




var	PhotoSearch	=	Backbone.View.extend({
				el:	$('#results'),
				render:	function(	event	){
								var	compiled_template	=	_.template(	$("#results‑template").html()	);
								this.$el.html(	compiled_template(this.model.toJSON())	);
								return	this;	//recommended	as	this	enables	calls	to	be	chained.
				},
				events:	{
								"submit	#searchForm":		"search",
								"click	.reset":	"reset",
								"click	.advanced":	"switchContext"
				},
				search:	function(	event	){
								//executed	when	a	form	'#searchForm'	has	been	submitted
				},
				reset:	function(	event	){

								//executed	when	an	element	with	class	"reset"	has	been	clicked.
				},
				switchContext:	function(	event	){
								//executed	when	an	element	with	class	"advanced"	has	been	clicked.
				}
});
Пример	представления	
           	




•   el	‑	это	DOM‑элемент	представления	
tagName:	'p',	//	required,	but	defaults	to	'div'	if	not	set
className:	'container',	//	optional,	you	can	assign	multiple	classes	to	this	property	like	so	'container	
homepage'
id:	'header',	//	optional	
•   Код	выше	создаст	следующий	DOMElement	(но	не	добавит	его	в	
    дерево):	
<p	id="header"	class="container"></p>	
•   Фунция	render()	определяет	отображение	представления	на	странице	
•   Исходные	данные	обычно	задаются	в	JSON‑формате	
•   Для	её	реализации	чаще	всего	используется	сторонний	
    js‑шаблонизатор	(например:	
    http://documentcloud.github.com/underscore/#template)	
     – Сюда	то	и	уходит	весь	быдлокод	;)
Пример	шаблонизатора	
var	compiled	=	_.template("hello:	<%=	name	%>");
compiled({name	:	'moe'});
	
=>	"hello:	moe"

var	list	=	"<%	_.each(people,	function(name)	{	%>	<li><%=	name	%></li>	<%	});	%>";
_.template(list,	{people	:	['moe',	'curly',	'larry']});
	
=>	"<li>moe</li><li>curly</li><li>larry</li>"

var	template	=	_.template("<b><%=	value	%></b>");
template({value	:	'<script>'});
	
=>	"<b>&lt;script&gt;</b>"
Маршрутизация	(Router)	
   	




• До	версии	0.5	назывался	Controller	;)	
• Мэпит	ссылки	(URL)	на	функции	в	js	
  – Адресация	в	веб‑приложении	
  – Работа	с	историей	в	браузере	
       • на	низком	уровне:	hashchange	или	HTML5	
         pushState	
       • После	того	как	создали	все	роутеры	нужно	
        скомандовать	startBackbone.history.start,	чтобы	
        история	начала	вестись
var	GalleryRouter	=	Backbone.Router.extend({
				routes:	{
								"about"	:	"showAbout",	http://unicorns.com/#	<about
								"photos/:id"	:	"getPhoto",	//	http://unicorns.com/#photos/5
								"search/:query"	:	"searchPhotos",	//	http://unicorns.com/#search/lolcats
								"search/:query/p:page"	:	"searchPhotos",	//	http://unicorns.com/#search/lolcats/p1
								"photos/:id/download/*imagePath"	:	"downloadPhoto",		
								//	http://unicorns.com/#photos/5/download/files/lolcat‑car.jpg
								"*other"				:	"defaultRoute"	//	http://unicorns.com/#	<anything
				},

				showAbout:	function(){
				},

				getPhoto:	function(id){
								console.log("You	are	trying	to	reach	photo	"	+	id);
				},

				searchPhotos:	function(query,	page){
								var	page_number	=	page	||	1;
								console.log("Page	number:	"	+	page_number	+	"	of	the	results	for	"	+	query);
				},

				downloadPhoto:	function(id,	path){
				},

				defaultRoute:	function(other){
								console.log("Invalid.	You	attempted	to	reach:"	+	other);
				}
});

var	myGalleryRouter	=	new	GalleryRouter();
Зачем	нужен?	
• Придать	структуру	клиентскому	коду	
• Упростить	CRUD	данных	с	сервера	
  (персистентность)	
• Синхронизация	объектов	на	сервере,	js	и	DOM	
• Уменьшить	рост	количества	кода	на	
      – Модели	
      – Представления	
      – Маршрутизацию	
• Что‑то	ещё	(я	не	всё	про	него	знаю)
Персистентность	
                 	




• Реализуется	посредством	функции	Backbone.sync	
   – Она	вызывается	при	каждой	попытке	прочитать/записать	данные	для	
     модели	с	сервера	(fetch/save	...)	
       • url	запроса	определяется	свойством	model.url()	или	model.urlRoot()	
   – По	умолчанию	использует	jQuery.ajax	
   – Может	быть	переопределена,	например	чтобы	использовать	WebSockets	
   – По	умолчанию	преобразует	команды	в	следующие	REST‑запросы:	
   – create	→	POST			/collection
     read	→	GET			/collection[/id]
     update	→	PUT			/collection/id
     delete	→	DELETE			/collection/id	
   	

   Пример	обработчика	на	RoR:	
   def	update
   		account	=	Account.find	params[:id]
   		account.update_attributes	params
   		render	:json	=>	account
   end
Где	почитать?	
• Официальная	документация	(http://backbonejs.org/)	
    – Не	хочешь	учить	англ?	http://backbonejs.ru/	
• Developing	Backbone.js	Applications	
  (http://addyosmani.github.com/backbone‑fundamentals/)
  	
   –   Основы	
   –   Примеры	(готовый	TODO‑лист)	
   –   Тестирование	
   –   Модульность	

   – Расширения	
• Для	чайников:	http://habrahabr.ru/post/127049/	
• Презентация	про	альтернативу:	
  http://prezi.com/plv0byja9ubh/mvvm‑knockoutjs/
Альтернативы	
•   Knockout	(http://knockoutjs.com/)	
•   Ember.js	(http://emberjs.com/)	
•   AngularJS	(http://angularjs.org/)	
•   SpineJS	(http://spinejs.com/docs/index)	
    – Очень	любопытный	аналог	
    – Написан	на	coffee‑script	

      (http://coffeescript.org/)

Backbone.js