Вы находитесь на странице: 1из 30

3/16/2016

Backbone.js

start

Sync
Backbone.sync
Backbone.ajax
Backbone.emulateHTTP
Backbone.emulateJSON

View
extend

Backbone.jsgivesstructuretowebapplicationsbyprovidingmodelswithkeyvalue

constructor / initialize

bindingandcustomevents,collectionswitharichAPIofenumerablefunctions,

el

viewswithdeclarativeeventhandling,andconnectsitalltoyourexistingAPIovera

$el
setElement

RESTfulJSONinterface.

attributes
$ (jQuery)
template
render

TheprojectishostedonGitHub,andtheannotatedsourcecodeisavailable,aswell
asanonlinetestsuite,anexampleapplication,alistoftutorialsandalonglistofreal

remove

worldprojectsthatuseBackbone.BackboneisavailableforuseundertheMIT

events

softwarelicense.

delegateEvents
undelegateEvents

YoucanreportbugsanddiscussfeaturesontheGitHubissuespage,onFreenode

Utility

IRCinthe #documentcloud channel,postquestionstotheGoogleGroup,addpagesto

Backbone.noConflict

thewikiorsendtweetsto@documentcloud.

Backbone.$

F.A.Q.

BackboneisanopensourcecomponentofDocumentCloud.

Why Backbone?
More Than One Way To Do It
Nested Models & Collections
Loading Bootstrapped Models

Downloads&Dependencies

(Right-click, and use "Save As")

Extending Backbone
Traditional MVC
Binding "this"

DevelopmentVersion(1.3.2)

72kb,Fullsource,tonsofcomments

Working with Rails

Examples

ProductionVersion(1.3.2)

DocumentCloud
USA Today

7.5kb,Packedandgzipped
(SourceMap)

Todos

EdgeVersion(master)

Unreleased,useatyourownrisk

Rdio
Hulu
Quartz
Earth
Vox
Gawker Media

Backbone'sonlyharddependencyisUnderscore.js(>=1.8.3).ForRESTfulpersistence
andDOMmanipulationwithBackbone.View,includejQuery(>=1.11.0),andjson2.js

Flow

forolderInternetExplorersupport.(MimicsoftheUnderscoreandjQueryAPIs,such

Gilt Groupe

asLodashandZepto,willalsotendtowork,withvaryingdegreesofcompatibility.)

Enigma
NewsBlur
WordPress.com
Foursquare
Bitbucket
Disqus

GettingStarted

Delicious

WhenworkingonawebapplicationthatinvolvesalotofJavaScript,oneofthefirst

Khan Academy

thingsyoulearnistostoptyingyourdatatotheDOM.It'salltooeasytocreate

IRCCloud
Pitchfork

JavaScriptapplicationsthatendupastangledpilesofjQueryselectorsandcallbacks,

Spin

alltryingfranticallytokeepdatainsyncbetweentheHTMLUI,yourJavaScriptlogic,

ZocDoc

andthedatabaseonyourserver.Forrichclientsideapplications,amorestructured

Walmart Mobile
Groupon Now!

approachisoftenhelpful.

Basecamp
Slavery Footprint
Stripe
Airbnb

WithBackbone,yourepresentyourdataasModels,whichcanbecreated,validated,
destroyed,andsavedtotheserver.WheneveraUIactioncausesanattributeofa

SoundCloud Mobile

modeltochange,themodeltriggersa"change"eventalltheViewsthatdisplaythe

- Art.sy

model'sstatecanbenotifiedofthechange,sothattheyareabletorespond

Pandora

accordingly,rerenderingthemselveswiththenewinformation.InafinishedBackbone

Inkling
Code School

app,youdon'thavetowritethegluecodethatlooksintotheDOMtofindanelement

CloudApp

withaspecificid,andupdatetheHTMLmanuallywhenthemodelchanges,the

SeatGeek

viewssimplyupdatethemselves.

Easel
- Jolicloud
Salon.io

Philosophically,Backboneisanattempttodiscovertheminimalsetofdatastructuring

TileMill

(modelsandcollections)anduserinterface(viewsandURLs)primitivesthatare

Blossom
Trello
Tzigla

Change Log

http://backbonejs.org/#changelog

generallyusefulwhenbuildingwebapplicationswithJavaScript.Inanecosystem
whereoverarching,decideseverythingforyouframeworksarecommonplace,and
manylibrariesrequireyoursitetobereorganizedtosuittheirlook,feel,anddefault
behaviorBackboneshouldcontinuetobeatoolthatgivesyouthefreedomto

1/57

3/16/2016

Backbone.js
designthefullexperienceofyourwebapplication.
Ifyou'renewhere,andaren'tyetquitesurewhatBackboneisfor,startbybrowsing
thelistofBackbonebasedprojects.
Manyofthecodeexamplesinthisdocumentationarerunnable,becauseBackboneis
includedonthispage.Clicktheplaybuttontoexecutethem.

ModelsandViews

ThesinglemostimportantthingthatBackbonecanhelpyouwithiskeepingyour
businesslogicseparatefromyouruserinterface.Whenthetwoareentangled,change
ishardwhenlogicdoesn'tdependonUI,yourinterfacebecomeseasiertoworkwith.
Model

View

Orchestratesdataandbusinesslogic.

ListensforchangesandrendersUI.

Loadsandsavesfromtheserver.

Handlesuserinputandinteractivity.

Emitseventswhendatachanges.

Sendscapturedinputtothemodel.

AModelmanagesaninternaltableofdataattributes,andtriggers "change" events


whenanyofitsdataismodified.Modelshandlesyncingdatawithapersistencelayer
usuallyaRESTAPIwithabackingdatabase.Designyourmodelsastheatomic
reusableobjectscontainingallofthehelpfulfunctionsformanipulatingtheirparticular
bitofdata.Modelsshouldbeabletobepassedaroundthroughoutyourapp,andused
anywherethatbitofdataisneeded.
AViewisanatomicchunkofuserinterface.Itoftenrendersthedatafromaspecific
model,ornumberofmodelsbutviewscanalsobedatalesschunksofUIthatstand
alone.Modelsshouldbegenerallyunawareofviews.Instead,viewslistentothemodel
"change" events,andreactorrerenderthemselvesappropriately.

Collections

ACollectionhelpsyoudealwithagroupofrelatedmodels,handlingtheloadingand
savingofnewmodelstotheserverandprovidinghelperfunctionsforperforming
aggregationsorcomputationsagainstalistofmodels.Asidefromtheirownevents,
collectionsalsoproxythroughalloftheeventsthatoccurtomodelswithinthem,
allowingyoutolisteninoneplaceforanychangethatmighthappentoanymodelin
thecollection.

APIIntegration
BackboneispreconfiguredtosyncwithaRESTfulAPI.SimplycreateanewCollection
withthe url ofyourresourceendpoint:

http://backbonejs.org/#changelog

2/57

3/16/2016

Backbone.js
varBooks=Backbone.Collection.extend({
url:'/books'
});

TheCollectionandModelcomponentstogetherformadirectmappingofREST
resourcesusingthefollowingmethods:
GET/books/....collection.fetch();
POST/books/....collection.create();
GET/books/1...model.fetch();
PUT/books/1...model.save();
DEL/books/1...model.destroy();

WhenfetchingrawJSONdatafromanAPI,aCollectionwillautomaticallypopulate
itselfwithdataformattedasanarray,whileaModelwillautomaticallypopulateitself
withdataformattedasanobject:
[{"id":1}].....populatesaCollectionwithonemodel.
{"id":1}.......populatesaModelwithoneattribute.

However,it'sfairlycommontoencounterAPIsthatreturndatainadifferentformat
thanwhatBackboneexpects.Forexample,considerfetchingaCollectionfroman
APIthatreturnstherealdataarraywrappedinmetadata:
{
"page":1,
"limit":10,
"total":2,
"books":[
{"id":1,"title":"PrideandPrejudice"},
{"id":4,"title":"TheGreatGatsby"}
]
}

Intheaboveexampledata,aCollectionshouldpopulateusingthe "books" array


ratherthantherootobjectstructure.Thisdifferenceiseasilyreconciledusinga parse
methodthatreturns(ortransforms)thedesiredportionofAPIdata:
varBooks=Backbone.Collection.extend({
url:'/books',
parse:function(data){
returndata.books;
}
});

ViewRendering

EachViewmanagestherenderinganduserinteractionwithinitsownDOMelement.If
you'restrictaboutnotallowingviewstoreachoutsideofthemselves,ithelpskeepyour
interfaceflexibleallowingviewstoberenderedinisolationinanyplacewherethey
mightbeneeded.
BackboneremainsunopinionatedabouttheprocessusedtorenderViewobjectsand
theirsubviewsintoUI:youdefinehowyourmodelsgettranslatedintoHTML(orSVG,
orCanvas,orsomethingevenmoreexotic).Itcouldbeasprosaicasasimple
Underscoretemplate,orasfancyastheReactvirtualDOM.Somebasicapproaches
torenderingviewscanbefoundintheBackboneprimer.

http://backbonejs.org/#changelog

3/57

3/16/2016

Backbone.js

RoutingwithURLs

Inrichwebapplications,westillwanttoprovidelinkable,bookmarkable,andshareable
URLstomeaningfullocationswithinanapp.UsetheRoutertoupdatethebrowser
URLwhenevertheuserreachesanew"place"inyourappthattheymightwantto
bookmarkorshare.Conversely,theRouterdetectschangestotheURLsay,
pressingthe"Back"buttonandcantellyourapplicationexactlywhereyouarenow.

Backbone.Events
Eventsisamodulethatcanbemixedintoanyobject,givingtheobjecttheabilityto
bindandtriggercustomnamedevents.Eventsdonothavetobedeclaredbeforethey
arebound,andmaytakepassedarguments.Forexample:
varobject={};
_.extend(object,Backbone.Events);
object.on("alert",function(msg){
alert("Triggered"+msg);
});
object.trigger("alert","anevent");

Forexample,tomakeahandyeventdispatcherthatcancoordinateeventsamong
differentareasofyourapplication: vardispatcher=_.clone(Backbone.Events)

on

object.on(event,callback,[context])

Alias:bind

Bindacallbackfunctiontoanobject.Thecallbackwillbeinvokedwhenevertheevent
isfired.Ifyouhavealargenumberofdifferenteventsonapage,theconventionisto
usecolonstonamespacethem: "poll:start" ,or "change:selection" .Theevent
stringmayalsobeaspacedelimitedlistofseveralevents...
book.on("change:titlechange:author",...);

Callbacksboundtothespecial "all" eventwillbetriggeredwhenanyeventoccurs,


andarepassedthenameoftheeventasthefirstargument.Forexample,toproxyall
eventsfromoneobjecttoanother:
proxy.on("all",function(eventName){
object.trigger(eventName);
});

AllBackboneeventmethodsalsosupportaneventmapsyntax,asanalternativeto
positionalarguments:
book.on({
"change:author":authorPane.update,
"change:titlechange:subtitle":titleView.update,
"destroy":bookView.remove
});

Tosupplyacontextvaluefor this whenthecallbackisinvoked,passtheoptional


lastargument: model.on('change',this.render,this) or model.on({change:
this.render},this) .

http://backbonejs.org/#changelog

4/57

3/16/2016

Backbone.js

off

object.off([event],[callback],[context])

Alias:unbind

Removeapreviouslyboundcallbackfunctionfromanobject.Ifnocontextis
specified,alloftheversionsofthecallbackwithdifferentcontextswillberemoved.If
nocallbackisspecified,allcallbacksfortheeventwillberemoved.Ifnoeventis
specified,callbacksforalleventswillberemoved.
//Removesjustthe`onChange`callback.
object.off("change",onChange);
//Removesall"change"callbacks.
object.off("change");
//Removesthe`onChange`callbackforallevents.
object.off(null,onChange);
//Removesallcallbacksfor`context`forallevents.
object.off(null,null,context);
//Removesallcallbackson`object`.
object.off();

Notethatcalling model.off() ,forexample,willindeedremovealleventsonthemodel


includingeventsthatBackboneusesforinternalbookkeeping.

trigger

object.trigger(event,[*args])

Triggercallbacksforthegivenevent,orspacedelimitedlistofevents.Subsequent
argumentstotriggerwillbepassedalongtotheeventcallbacks.

once

object.once(event,callback,[context])

Justlikeon,butcausestheboundcallbacktofireonlyoncebeforebeingremoved.
Handyforsaying"thenexttimethatXhappens,dothis".Whenmultipleeventsare
passedinusingthespaceseparatedsyntax,theeventwillfireonceforeveryevent
youpassedin,notonceforacombinationofallevents

listenTo

object.listenTo(other,event,callback)

Tellanobjecttolistentoaparticulareventonanotherobject.Theadvantageof
usingthisform,insteadof other.on(event,callback,object) ,isthatlistenToallows
theobjecttokeeptrackoftheevents,andtheycanberemovedallatoncelateron.
Thecallbackwillalwaysbecalledwithobjectascontext.
view.listenTo(model,'change',view.render);

stopListening

object.stopListening([other],[event],[callback])

Tellanobjecttostoplisteningtoevents.EithercallstopListeningwithnoarguments
tohavetheobjectremoveallofitsregisteredcallbacks...orbemorepreciseby
tellingittoremovejusttheeventsit'slisteningtoonaspecificobject,oraspecific
event,orjustaspecificcallback.
view.stopListening();
view.stopListening(model);

listenToOnce

object.listenToOnce(other,event,callback)

JustlikelistenTo,butcausestheboundcallbacktofireonlyoncebeforebeing
removed.

CatalogofEvents
Here'sthecompletelistofbuiltinBackboneevents,witharguments.You'realsofree
totriggeryourowneventsonModels,CollectionsandViewsasyouseefit.The
Backbone objectitselfmixesin Events ,andcanbeusedtoemitanyglobaleventsthat

yourapplicationneeds.
"add"(model,collection,options)whenamodelisaddedtoacollection.

http://backbonejs.org/#changelog

5/57

3/16/2016

Backbone.js
"remove"(model,collection,options)whenamodelisremovedfromacollection.
"update"(collection,options)singleeventtriggeredafteranynumberofmodelshavebeenadded
orremovedfromacollection.
"reset"(collection,options)whenthecollection'sentirecontentshavebeenreset.
"sort"(collection,options)whenthecollectionhasbeenresorted.
"change"(model,options)whenamodel'sattributeshavechanged.
"change:[attribute]"(model,value,options)whenaspecificattributehasbeenupdated.
"destroy"(model,collection,options)whenamodelisdestroyed.
"request"(model_or_collection,xhr,options)whenamodelorcollectionhasstartedarequestto
theserver.
"sync"(model_or_collection,response,options)whenamodelorcollectionhasbeen
successfullysyncedwiththeserver.
"error"(model_or_collection,response,options)whenamodel'sorcollection'srequesttothe
serverhasfailed.
"invalid"(model,error,options)whenamodel'svalidationfailsontheclient.
"route:[name]"(params)Firedbytherouterwhenaspecificrouteismatched.
"route"(route,params)Firedbytherouterwhenanyroutehasbeenmatched.
"route"(router,route,params)Firedbyhistorywhenanyroutehasbeenmatched.
"all"thisspecialeventfiresforanytriggeredevent,passingtheeventnameasthefirstargument
followedbyalltriggerarguments.

Generallyspeaking,whencallingafunctionthatemitsanevent( model.set ,
collection.add ,andsoon...),ifyou'dliketopreventtheeventfrombeingtriggered,

youmaypass {silent:true} asanoption.Notethatthisisrarely,perhapseven


never,agoodidea.Passingthroughaspecificflagintheoptionsforyourevent
callbacktolookat,andchoosetoignore,willusuallyworkoutbetter.

Backbone.Model
ModelsaretheheartofanyJavaScriptapplication,containingtheinteractivedataas
wellasalargepartofthelogicsurroundingit:conversions,validations,computed
properties,andaccesscontrol.YouextendBackbone.Modelwithyourdomain
specificmethods,andModelprovidesabasicsetoffunctionalityformanaging
changes.
Thefollowingisacontrivedexample,butitdemonstratesdefiningamodelwitha
custommethod,settinganattribute,andfiringaneventkeyedtochangesinthat
specificattribute.Afterrunningthiscodeonce, sidebar willbeavailableinyour
browser'sconsole,soyoucanplayaroundwithit.
varSidebar=Backbone.Model.extend({
promptColor:function(){
varcssColor=prompt("PleaseenteraCSScolor:");
this.set({color:cssColor});
}
});
window.sidebar=newSidebar;
sidebar.on('change:color',function(model,color){
$('#sidebar').css({background:color});
});
sidebar.set({color:'white'});
sidebar.promptColor();

extend

Backbone.Model.extend(properties,[classProperties])

TocreateaModelclassofyourown,youextendBackbone.Modelandprovide
instanceproperties,aswellasoptionalclassPropertiestobeattacheddirectlytothe
constructorfunction.
extendcorrectlysetsuptheprototypechain,sosubclassescreatedwithextendcan
befurtherextendedandsubclassedasfarasyoulike.

http://backbonejs.org/#changelog

6/57

3/16/2016

Backbone.js
varNote=Backbone.Model.extend({
initialize:function(){...},
author:function(){...},
coordinates:function(){...},
allowedToEdit:function(account){
returntrue;
}
});
varPrivateNote=Note.extend({
allowedToEdit:function(account){
returnaccount.owns(this);
}
});

Briefasideon super :JavaScriptdoesnotprovideasimplewaytocallsuperthefunctionofthe


samenamedefinedhigherontheprototypechain.Ifyouoverrideacorefunctionlike set ,or save ,
andyouwanttoinvoketheparentobject'simplementation,you'llhavetoexplicitlycallit,alongthese
lines:

varNote=Backbone.Model.extend({
set:function(attributes,options){
Backbone.Model.prototype.set.apply(this,arguments);
...
}
});

constructor/initialize

newModel([attributes],[options])

Whencreatinganinstanceofamodel,youcanpassintheinitialvaluesofthe
attributes,whichwillbesetonthemodel.Ifyoudefineaninitializefunction,itwillbe
invokedwhenthemodeliscreated.
newBook({
title:"OneThousandandOneNights",
author:"Scheherazade"
});

Inrarecases,ifyou'relookingtogetfancy,youmaywanttooverrideconstructor,
whichallowsyoutoreplacetheactualconstructorfunctionforyourmodel.
varLibrary=Backbone.Model.extend({
constructor:function(){
this.books=newBooks();
Backbone.Model.apply(this,arguments);
},
parse:function(data,options){
this.books.reset(data.books);
returndata.library;
}
});

Ifyoupassa {collection:...} astheoptions,themodelgainsa collection


propertythatwillbeusedtoindicatewhichcollectionthemodelbelongsto,andisused
tohelpcomputethemodel'surl.The model.collection propertyisnormallycreated
automaticallywhenyoufirstaddamodeltoacollection.Notethatthereverseisnot
true,aspassingthisoptiontotheconstructorwillnotautomaticallyaddthemodelto
thecollection.Useful,sometimes.
If {parse:true} ispassedasanoption,theattributeswillfirstbeconvertedby
parsebeforebeingsetonthemodel.

get

model.get(attribute)

Getthecurrentvalueofanattributefromthemodel.Forexample: note.get("title")

http://backbonejs.org/#changelog

7/57

3/16/2016

Backbone.js

set

model.set(attributes,[options])

Setahashofattributes(oneormany)onthemodel.Ifanyoftheattributeschangethe
model'sstate,a "change" eventwillbetriggeredonthemodel.Changeeventsfor
specificattributesarealsotriggered,andyoucanbindtothoseaswell,forexample:
change:title ,and change:content .Youmayalsopassindividualkeysandvalues.

note.set({title:"March20",content:"Inhiseyessheeclipses..."});
book.set("title","AScandalinBohemia");

escape

model.escape(attribute)

Similartoget,butreturnstheHTMLescapedversionofamodel'sattribute.Ifyou're
interpolatingdatafromthemodelintoHTML,usingescapetoretrieveattributeswill
preventXSSattacks.
varhacker=newBackbone.Model({
name:"<script>alert('xss')</script>"
});
alert(hacker.escape('name'));

has

model.has(attribute)

Returns true iftheattributeissettoanonnullornonundefinedvalue.


if(note.has("title")){
...
}

unset

model.unset(attribute,[options])

Removeanattributebydeletingitfromtheinternalattributeshash.Firesa "change"
eventunless silent ispassedasanoption.

clear

model.clear([options])

Removesallattributesfromthemodel,includingthe id attribute.Firesa "change"


eventunless silent ispassedasanoption.

id

model.id

Aspecialpropertyofmodels,theidisanarbitrarystring(integeridorUUID).Ifyouset
theidintheattributeshash,itwillbecopiedontothemodelasadirectproperty.
Modelscanberetrievedbyidfromcollections,andtheidisusedtogeneratemodel
URLsbydefault.

idAttribute

model.idAttribute

Amodel'suniqueidentifierisstoredunderthe id attribute.Ifyou'redirectly
communicatingwithabackend(CouchDB,MongoDB)thatusesadifferentuniquekey,
youmaysetaModel's idAttribute totransparentlymapfromthatkeyto id .
varMeal=Backbone.Model.extend({
idAttribute:"_id"
});
varcake=newMeal({_id:1,name:"Cake"});
alert("Cakeid:"+cake.id);

cid

model.cid

Aspecialpropertyofmodels,thecidorclientidisauniqueidentifierautomatically
assignedtoallmodelswhenthey'refirstcreated.Clientidsarehandywhenthemodel
hasnotyetbeensavedtotheserver,anddoesnotyethaveitseventualtrueid,but
alreadyneedstobevisibleintheUI.

attributes

model.attributes

Theattributespropertyistheinternalhashcontainingthemodel'sstateusually

http://backbonejs.org/#changelog

8/57

3/16/2016

Backbone.js
(butnotnecessarily)aformoftheJSONobjectrepresentingthemodeldataonthe
server.It'softenastraightforwardserializationofarowfromthedatabase,butitcould
alsobeclientsidecomputedstate.
Pleaseusesettoupdatetheattributesinsteadofmodifyingthemdirectly.Ifyou'dlike
toretrieveandmungeacopyofthemodel'sattributes,use _.clone(model.attributes)
instead.
DuetothefactthatEventsacceptsspaceseparatedlistsofevents,attributenamesshouldnotinclude
spaces.

changed

model.changed

Thechangedpropertyistheinternalhashcontainingalltheattributesthathave
changedsinceitslastset.Pleasedonotupdatechangeddirectlysinceitsstateis
internallymaintainedbyset.Acopyofchangedcanbeacquiredfrom
changedAttributes.

defaults

model.defaultsormodel.defaults()

Thedefaultshash(orfunction)canbeusedtospecifythedefaultattributesforyour
model.Whencreatinganinstanceofthemodel,anyunspecifiedattributeswillbeset
totheirdefaultvalue.
varMeal=Backbone.Model.extend({
defaults:{
"appetizer":"caesarsalad",
"entree":"ravioli",
"dessert":"cheesecake"
}
});
alert("Dessertwillbe"+(newMeal).get('dessert'));

RememberthatinJavaScript,objectsarepassedbyreference,soifyouincludeanobjectasadefault
value,itwillbesharedamongallinstances.Instead,definedefaultsasafunction.

toJSON

model.toJSON([options])

Returnashallowcopyofthemodel'sattributesforJSONstringification.Thiscanbe
usedforpersistence,serialization,orforaugmentationbeforebeingsenttotheserver.
Thenameofthismethodisabitconfusing,asitdoesn'tactuallyreturnaJSONstring
butI'mafraidthatit'sthewaythattheJavaScriptAPIforJSON.stringifyworks.
varartist=newBackbone.Model({
firstName:"Wassily",
lastName:"Kandinsky"
});
artist.set({birthday:"December16,1866"});
alert(JSON.stringify(artist));

sync

model.sync(method,model,[options])

UsesBackbone.synctopersistthestateofamodeltotheserver.Canbeoverridden
forcustombehavior.

fetch

model.fetch([options])

Mergesthemodel'sstatewithattributesfetchedfromtheserverbydelegatingto
Backbone.sync.ReturnsajqXHR.Usefulifthemodelhasneverbeenpopulatedwith
data,orifyou'dliketoensurethatyouhavethelatestserverstate.Triggersa
"change" eventiftheserver'sstatediffersfromthecurrentattributes. fetch accepts
success and error callbacksintheoptionshash,whicharebothpassed (model,
response,options) asarguments.

//Pollevery10secondstokeepthechannelmodeluptodate.
setInterval(function(){
channel.fetch();
},10000);

http://backbonejs.org/#changelog

9/57

3/16/2016

Backbone.js

save

model.save([attributes],[options])

Saveamodeltoyourdatabase(oralternativepersistencelayer),bydelegatingto
Backbone.sync.ReturnsajqXHRifvalidationissuccessfuland false otherwise.The
attributeshash(asinset)shouldcontaintheattributesyou'dliketochangekeys
thataren'tmentionedwon'tbealteredbut,acompleterepresentationofthe
resourcewillbesenttotheserver.Aswith set ,youmaypassindividualkeysand
valuesinsteadofahash.Ifthemodelhasavalidatemethod,andvalidationfails,the
modelwillnotbesaved.IfthemodelisNew,thesavewillbea "create" (HTTP POST ),
ifthemodelalreadyexistsontheserver,thesavewillbean "update" (HTTP PUT ).
Ifinstead,you'donlylikethechangedattributestobesenttotheserver,call
model.save(attrs,{patch:true}) .You'llgetanHTTP PATCH requesttotheserver

withjustthepassedinattributes.
Calling save withnewattributeswillcausea "change" eventimmediately,a
"request" eventastheAjaxrequestbeginstogototheserver,anda "sync" event

aftertheserverhasacknowledgedthesuccessfulchange.Pass {wait:true} ifyou'd


liketowaitfortheserverbeforesettingthenewattributesonthemodel.
Inthefollowingexample,noticehowouroverriddenversionof Backbone.sync receives
a "create" requestthefirsttimethemodelissavedandan "update" requestthe
secondtime.
Backbone.sync=function(method,model){
alert(method+":"+JSON.stringify(model));
model.set('id',1);
};
varbook=newBackbone.Model({
title:"TheRoughRiders",
author:"TheodoreRoosevelt"
});
book.save();
book.save({author:"Teddy"});

saveaccepts success and error callbacksintheoptionshash,whichwillbepassed


thearguments (model,response,options) .Ifaserversidevalidationfails,returna
non 200 HTTPresponsecode,alongwithanerrorresponseintextorJSON.
book.save("author","F.D.R.",{error:function(){...}});

destroy

model.destroy([options])

DestroysthemodelontheserverbydelegatinganHTTP DELETE requestto


Backbone.sync.ReturnsajqXHRobject,or false ifthemodelisNew.Accepts
success and error callbacksintheoptionshash,whichwillbepassed (model,
response,options) .Triggersa "destroy" eventonthemodel,whichwillbubbleup

throughanycollectionsthatcontainit,a "request" eventasitbeginstheAjaxrequest


totheserver,anda "sync" event,aftertheserverhassuccessfullyacknowledgedthe
model'sdeletion.Pass {wait:true} ifyou'dliketowaitfortheservertorespond
beforeremovingthemodelfromthecollection.
book.destroy({success:function(model,response){
...
}});

UnderscoreMethods(9)
BackboneproxiestoUnderscore.jstoprovide9objectfunctionson
Backbone.Model.Theyaren'talldocumentedhere,butyoucantakealookatthe
Underscoredocumentationforthefulldetails
keys
values
pairs

http://backbonejs.org/#changelog

10/57

3/16/2016

Backbone.js
invert
pick
omit
chain
isEmpty

user.pick('first_name','last_name','email');
chapters.keys().join(',');

validate

model.validate(attributes,options)

Thismethodisleftundefinedandyou'reencouragedtooverrideitwithanycustom
validationlogicyouhavethatcanbeperformedinJavaScript.Bydefault save checks
validatebeforesettinganyattributesbutyoumayalsotell set tovalidatethenew
attributesbypassing {validate:true} asanoption.
Thevalidatemethodreceivesthemodelattributesaswellasanyoptionspassedto
set or save .Iftheattributesarevalid,don'treturnanythingfromvalidateiftheyare

invalidreturnanerrorofyourchoosing.Itcanbeassimpleasastringerrormessage
tobedisplayed,oracompleteerrorobjectthatdescribestheerrorprogrammatically.If
validatereturnsanerror, save willnotcontinue,andthemodelattributeswillnotbe
modifiedontheserver.Failedvalidationstriggeran "invalid" event,andsetthe
validationError propertyonthemodelwiththevaluereturnedbythismethod.

varChapter=Backbone.Model.extend({
validate:function(attrs,options){
if(attrs.end<attrs.start){
return"can'tendbeforeitstarts";
}
}
});
varone=newChapter({
title:"ChapterOne:TheBeginning"
});
one.on("invalid",function(model,error){
alert(model.get("title")+""+error);
});
one.save({
start:15,
end:10
});

"invalid" eventsareusefulforprovidingcoarsegrainederrormessagesatthe

modelorcollectionlevel.

validationError

model.validationError

Thevaluereturnedbyvalidateduringthelastfailedvalidation.

isValid

model.isValid()

Runvalidatetocheckthemodelstate.
varChapter=Backbone.Model.extend({
validate:function(attrs,options){
if(attrs.end<attrs.start){
return"can'tendbeforeitstarts";
}
}
});
varone=newChapter({
title:"ChapterOne:TheBeginning"
});
one.set({
start:15,
end:10
});

http://backbonejs.org/#changelog

11/57

3/16/2016

Backbone.js
if(!one.isValid()){
alert(one.get("title")+""+one.validationError);
}

url

model.url()

ReturnstherelativeURLwherethemodel'sresourcewouldbelocatedontheserver.
Ifyourmodelsarelocatedsomewhereelse,overridethismethodwiththecorrectlogic.
GeneratesURLsoftheform: "[collection.url]/[id]" bydefault,butyoumay
overridebyspecifyinganexplicit urlRoot ifthemodel'scollectionshouldn'tbetaken
intoaccount.
DelegatestoCollection#urltogeneratetheURL,somakesurethatyouhaveit
defined,oraurlRootproperty,ifallmodelsofthisclassshareacommonrootURL.A
modelwithanidof 101 ,storedinaBackbone.Collectionwitha url of
"/documents/7/notes" ,wouldhavethisURL: "/documents/7/notes/101"

urlRoot

model.urlRootormodel.urlRoot()

Specifya urlRoot ifyou'reusingamodeloutsideofacollection,toenablethedefault


urlfunctiontogenerateURLsbasedonthemodelid. "[urlRoot]/id"
Normally,youwon'tneedtodefinethis.Notethat urlRoot mayalsobeafunction.
varBook=Backbone.Model.extend({urlRoot:'/books'});
varsolaris=newBook({id:"1083lemsolaris"});
alert(solaris.url());

parse

model.parse(response,options)

parseiscalledwheneveramodel'sdataisreturnedbytheserver,infetch,andsave.
Thefunctionispassedtheraw response object,andshouldreturntheattributeshash
tobesetonthemodel.Thedefaultimplementationisanoop,simplypassingthrough
theJSONresponse.OverridethisifyouneedtoworkwithapreexistingAPI,orbetter
namespaceyourresponses.
Ifyou'reworkingwithaRailsbackendthathasaversionpriorto3.1,you'llnoticethat
itsdefault to_json implementationincludesamodel'sattributesunderanamespace.
TodisablethisbehaviorforseamlessBackboneintegration,set:
ActiveRecord::Base.include_root_in_json=false

clone

model.clone()

Returnsanewinstanceofthemodelwithidenticalattributes.

isNew

model.isNew()

Hasthismodelbeensavedtotheserveryet?Ifthemodeldoesnotyethavean id ,it
isconsideredtobenew.

hasChanged

model.hasChanged([attribute])

Hasthemodelchangedsinceitslastset?Ifanattributeispassed,returns true if
thatspecificattributehaschanged.
Notethatthismethod,andthefollowingchangerelatedones,areonlyusefulduringthecourseofa
"change" event.

book.on("change",function(){
if(book.hasChanged("title")){
...
}
});

changedAttributes

model.changedAttributes([attributes])

Retrieveahashofonlythemodel'sattributesthathavechangedsincethelastset,or

http://backbonejs.org/#changelog

12/57

3/16/2016

Backbone.js
false iftherearenone.Optionally,anexternalattributeshashcanbepassedin,

returningtheattributesinthathashwhichdifferfromthemodel.Thiscanbeusedto
figureoutwhichportionsofaviewshouldbeupdated,orwhatcallsneedtobemade
tosyncthechangestotheserver.

previous

model.previous(attribute)

Duringa "change" event,thismethodcanbeusedtogetthepreviousvalueofa


changedattribute.
varbill=newBackbone.Model({
name:"BillSmith"
});
bill.on("change:name",function(model,name){
alert("Changednamefrom"+bill.previous("name")+"to"+name);
});
bill.set({name:"BillJones"});

previousAttributes

model.previousAttributes()

Returnacopyofthemodel'spreviousattributes.Usefulforgettingadiffbetween
versionsofamodel,orgettingbacktoavalidstateafteranerroroccurs.

Backbone.Collection
Collectionsareorderedsetsofmodels.Youcanbind "change" eventstobenotified
whenanymodelinthecollectionhasbeenmodified,listenfor "add" and "remove"
events, fetch thecollectionfromtheserver,anduseafullsuiteofUnderscore.js
methods.
Anyeventthatistriggeredonamodelinacollectionwillalsobetriggeredonthe
collectiondirectly,forconvenience.Thisallowsyoutolistenforchangestospecific
attributesinanymodelinacollection,forexample: documents.on("change:selected",
...)

extend

Backbone.Collection.extend(properties,[classProperties])

TocreateaCollectionclassofyourown,extendBackbone.Collection,providing
instanceproperties,aswellasoptionalclassPropertiestobeattacheddirectlytothe
collection'sconstructorfunction.

model

collection.model([attrs],[options])

Overridethispropertytospecifythemodelclassthatthecollectioncontains.Ifdefined,
youcanpassrawattributesobjects(andarrays)toadd,create,andreset,andthe
attributeswillbeconvertedintoamodelofthepropertype.
varLibrary=Backbone.Collection.extend({
model:Book
});

Acollectioncanalsocontainpolymorphicmodelsbyoverridingthispropertywitha
constructorthatreturnsamodel.
varLibrary=Backbone.Collection.extend({
model:function(attrs,options){
if(condition){
returnnewPublicDocument(attrs,options);
}else{
returnnewPrivateDocument(attrs,options);
}
}
});

http://backbonejs.org/#changelog

13/57

3/16/2016

Backbone.js

modelId

collection.modelId(attrs)

Overridethismethodtoreturnthevaluethecollectionwillusetoidentifyamodelgiven
itsattributes.Usefulforcombiningmodelsfrommultipletableswithdifferent
idAttribute valuesintoasinglecollection.

Bydefaultreturnsthevalueoftheattributes' idAttribute fromthecollection'smodel


classorfailingthat, id .Ifyourcollectionusesamodelfactoryandthosemodelshave
an idAttribute otherthan id youmustoverridethismethod.
varLibrary=Backbone.Collection.extend({
modelId:function(attrs){
returnattrs.type+attrs.id;
}
});
varlibrary=newLibrary([
{type:'dvd',id:1},
{type:'vhs',id:1}
]);
vardvdId=library.get('dvd1').id;
varvhsId=library.get('vhs1').id;
alert('dvd:'+dvdId+',vhs:'+vhsId);

constructor/initialize

newBackbone.Collection([models],[options])

WhencreatingaCollection,youmaychoosetopassintheinitialarrayofmodels.The
collection'scomparatormaybeincludedasanoption.Passing false asthe
comparatoroptionwillpreventsorting.Ifyoudefineaninitializefunction,itwillbe
invokedwhenthecollectioniscreated.Thereareacoupleofoptionsthat,ifprovided,
areattachedtothecollectiondirectly: model and comparator .
Pass null for models tocreateanemptyCollectionwith options .
vartabs=newTabSet([tab1,tab2,tab3]);
varspaces=newBackbone.Collection(null,{
model:Space
});

models

collection.models

RawaccesstotheJavaScriptarrayofmodelsinsideofthecollection.Usuallyyou'll
wanttouse get , at ,ortheUnderscoremethodstoaccessmodelobjects,but
occasionallyadirectreferencetothearrayisdesired.

toJSON

collection.toJSON([options])

Returnanarraycontainingtheattributeshashofeachmodel(viatoJSON)inthe
collection.Thiscanbeusedtoserializeandpersistthecollectionasawhole.The
nameofthismethodisabitconfusing,becauseitconformstoJavaScript'sJSONAPI.
varcollection=newBackbone.Collection([
{name:"Tim",age:5},
{name:"Ida",age:26},
{name:"Rob",age:55}
]);
alert(JSON.stringify(collection));

sync

collection.sync(method,collection,[options])

UsesBackbone.synctopersistthestateofacollectiontotheserver.Canbe
overriddenforcustombehavior.

UnderscoreMethods(46)
BackboneproxiestoUnderscore.jstoprovide46iterationfunctionson
Backbone.Collection.Theyaren'talldocumentedhere,butyoucantakealookat
theUnderscoredocumentationforthefulldetails
Mostmethodscantakeanobjectorstringtosupportmodelattributestylepredicates

http://backbonejs.org/#changelog

14/57

3/16/2016

Backbone.js
orafunctionthatreceivesthemodelinstanceasanargument.
forEach(each)
map(collect)
reduce(foldl,inject)
reduceRight(foldr)
find(detect)
findIndex
findLastIndex
filter(select)
reject
every(all)
some(any)
contains(includes)
invoke
max
min
sortBy
groupBy
shuffle
toArray
size
first(head,take)
initial
rest(tail,drop)
last
without
indexOf
lastIndexOf
isEmpty
chain
difference
sample
partition
countBy
indexBy

books.each(function(book){
book.publish();
});
vartitles=books.map("title");
varpublishedBooks=books.filter({published:true});
varalphabetical=books.sortBy(function(book){
returnbook.author.get("name").toLowerCase();
});
varrandomThree=books.sample(3);

add

collection.add(models,[options])

Addamodel(oranarrayofmodels)tothecollection,firingan "add" eventforeach


model,andan "update" eventafterwards.Ifamodelpropertyisdefined,youmay
alsopassrawattributesobjects,andhavethembevivifiedasinstancesofthemodel.
Returnstheadded(orpreexisting,ifduplicate)models.Pass {at:index} tosplicethe
modelintothecollectionatthespecified index .Ifyou'readdingmodelstothe
collectionthatarealreadyinthecollection,they'llbeignored,unlessyoupass {merge:
true} ,inwhichcasetheirattributeswillbemergedintothecorrespondingmodels,

http://backbonejs.org/#changelog

15/57

3/16/2016

Backbone.js
firinganyappropriate "change" events.
varships=newBackbone.Collection;
ships.on("add",function(ship){
alert("Ahoy"+ship.get("name")+"!");
});
ships.add([
{name:"FlyingDutchman"},
{name:"BlackPearl"}
]);

Notethataddingthesamemodel(amodelwiththesame id )toacollectionmorethanonce
isanoop.

remove

collection.remove(models,[options])

Removeamodel(oranarrayofmodels)fromthecollection,andreturnthem.Each
modelcanbeaModelinstance,an id stringoraJSobject,anyvalueacceptableas
the id argumentof collection.get .Firesa "remove" eventforeachmodel,anda
single "update" eventafterwards,unless {silent:true} ispassed.Themodel's
indexbeforeremovalisavailabletolistenersas options.index .

reset

collection.reset([models],[options])

Addingandremovingmodelsoneatatimeisallwellandgood,butsometimesyou
havesomanymodelstochangethatyou'dratherjustupdatethecollectioninbulk.
Useresettoreplaceacollectionwithanewlistofmodels(orattributehashes),
triggeringasingle "reset" eventoncompletion,andwithouttriggeringanyaddor
removeeventsonanymodels.Returnsthenewlysetmodels.Forconvenience,within
a "reset" event,thelistofanypreviousmodelsisavailableas
options.previousModels .

Pass null for models toemptyyourCollectionwith options .


Here'sanexampleusingresettobootstrapacollectionduringinitialpageload,ina
Railsapplication:
<script>
varaccounts=newBackbone.Collection;
accounts.reset(<%=@accounts.to_json%>);
</script>

Calling collection.reset() withoutpassinganymodelsasargumentswillemptythe


entirecollection.

set

collection.set(models,[options])

Thesetmethodperformsa"smart"updateofthecollectionwiththepassedlistof
models.Ifamodelinthelistisn'tyetinthecollectionitwillbeaddedifthemodelis
alreadyinthecollectionitsattributeswillbemergedandifthecollectioncontainsany
modelsthataren'tpresentinthelist,they'llberemoved.Alloftheappropriate "add" ,
"remove" ,and "change" eventsarefiredasthishappens.Returnsthetouched

modelsinthecollection.Ifyou'dliketocustomizethebehavior,youcandisableitwith
options: {add:false} , {remove:false} ,or {merge:false} .
varvanHalen=newBackbone.Collection([eddie,alex,stone,roth]);
vanHalen.set([eddie,alex,stone,hagar]);
//Firesa"remove"eventforroth,andan"add"eventfor"hagar".
//Updatesanyofstone,alex,andeddie'sattributesthatmayhave
//changedovertheyears.

get

collection.get(id)

Getamodelfromacollection,specifiedbyanid,acid,orbypassinginamodel.
varbook=library.get(110);

http://backbonejs.org/#changelog

16/57

3/16/2016

Backbone.js

at

collection.at(index)

Getamodelfromacollection,specifiedbyindex.Usefulifyourcollectionissorted,
andifyourcollectionisn'tsorted,atwillstillretrievemodelsininsertionorder.When
passedanegativeindex,itwillretrievethemodelfromthebackofthecollection.

push

collection.push(model,[options])

Addamodelattheendofacollection.Takesthesameoptionsasadd.

pop

collection.pop([options])

Removeandreturnthelastmodelfromacollection.Takesthesameoptionsas
remove.

unshift

collection.unshift(model,[options])

Addamodelatthebeginningofacollection.Takesthesameoptionsasadd.

shift

collection.shift([options])

Removeandreturnthefirstmodelfromacollection.Takesthesameoptionsas
remove.

slice

collection.slice(begin,end)

Returnashallowcopyofthiscollection'smodels,usingthesameoptionsasnative
Array#slice.

length

collection.length

Likeanarray,aCollectionmaintainsa length property,countingthenumberof


modelsitcontains.

comparator

collection.comparator

Bydefaultthereisnocomparatorforacollection.Ifyoudefineacomparator,itwillbe
usedtomaintainthecollectioninsortedorder.Thismeansthatasmodelsareadded,
theyareinsertedatthecorrectindexin collection.models .Acomparatorcanbe
definedasasortBy(passafunctionthattakesasingleargument),asasort(passa
comparatorfunctionthatexpectstwoarguments),orasastringindicatingtheattribute
tosortby.
"sortBy"comparatorfunctionstakeamodelandreturnanumericorstringvalueby
whichthemodelshouldbeorderedrelativetoothers."sort"comparatorfunctionstake
twomodels,andreturn 1 ifthefirstmodelshouldcomebeforethesecond, 0 ifthey
areofthesamerankand 1 ifthefirstmodelshouldcomeafter.NotethatBackbone
dependsonthearityofyourcomparatorfunctiontodeterminebetweenthetwostyles,
sobecarefulifyourcomparatorfunctionisbound.
Notehoweventhoughallofthechaptersinthisexampleareaddedbackwards,they
comeoutintheproperorder:
varChapter=Backbone.Model;
varchapters=newBackbone.Collection;
chapters.comparator='page';
chapters.add(newChapter({page:9,title:"TheEnd"}));
chapters.add(newChapter({page:5,title:"TheMiddle"}));
chapters.add(newChapter({page:1,title:"TheBeginning"}));
alert(chapters.pluck('title'));

Collectionswithacomparatorwillnotautomaticallyresortifyoulaterchangemodelattributes,soyou
maywishtocall sort afterchangingmodelattributesthatwouldaffecttheorder.

sort

collection.sort([options])

Forceacollectiontoresortitself.Youdon'tneedtocallthisundernormal

http://backbonejs.org/#changelog

17/57

3/16/2016

Backbone.js
circumstances,asacollectionwithacomparatorwillsortitselfwheneveramodelis
added.Todisablesortingwhenaddingamodel,pass {sort:false} to add .Calling
sorttriggersa "sort" eventonthecollection.

pluck

collection.pluck(attribute)

Pluckanattributefromeachmodelinthecollection.Equivalenttocalling map and


returningasingleattributefromtheiterator.
varstooges=newBackbone.Collection([
{name:"Curly"},
{name:"Larry"},
{name:"Moe"}
]);
varnames=stooges.pluck("name");
alert(JSON.stringify(names));

where

collection.where(attributes)

Returnanarrayofallthemodelsinacollectionthatmatchthepassedattributes.
Usefulforsimplecasesof filter .
varfriends=newBackbone.Collection([
{name:"Athos",job:"Musketeer"},
{name:"Porthos",job:"Musketeer"},
{name:"Aramis",job:"Musketeer"},
{name:"d'Artagnan",job:"Guard"},
]);
varmusketeers=friends.where({job:"Musketeer"});
alert(musketeers.length);

findWhere

collection.findWhere(attributes)

Justlikewhere,butdirectlyreturnsonlythefirstmodelinthecollectionthatmatches
thepassedattributes.

url

collection.urlorcollection.url()

Settheurlproperty(orfunction)onacollectiontoreferenceitslocationontheserver.
ModelswithinthecollectionwilluseurltoconstructURLsoftheirown.
varNotes=Backbone.Collection.extend({
url:'/notes'
});
//Or,somethingmoresophisticated:
varNotes=Backbone.Collection.extend({
url:function(){
returnthis.document.url()+'/notes';
}
});

parse

collection.parse(response,options)

parseiscalledbyBackbonewheneveracollection'smodelsarereturnedbythe
server,infetch.Thefunctionispassedtheraw response object,andshouldreturnthe
arrayofmodelattributestobeaddedtothecollection.Thedefaultimplementationisa
noop,simplypassingthroughtheJSONresponse.Overridethisifyouneedtowork
withapreexistingAPI,orbetternamespaceyourresponses.
varTweets=Backbone.Collection.extend({
//TheTwitterSearchAPIreturnstweetsunder"results".
parse:function(response){
returnresponse.results;
}
});

http://backbonejs.org/#changelog

18/57

3/16/2016

Backbone.js

clone

collection.clone()

Returnsanewinstanceofthecollectionwithanidenticallistofmodels.

fetch

collection.fetch([options])

Fetchthedefaultsetofmodelsforthiscollectionfromtheserver,settingthemonthe
collectionwhentheyarrive.Theoptionshashtakes success and error callbacks
whichwillbothbepassed (collection,response,options) asarguments.Whenthe
modeldatareturnsfromtheserver,itusessetto(intelligently)mergethefetched
models,unlessyoupass {reset:true} ,inwhichcasethecollectionwillbe(efficiently)
reset.DelegatestoBackbone.syncunderthecoversforcustompersistencestrategies
andreturnsajqXHR.TheserverhandlerforfetchrequestsshouldreturnaJSON
arrayofmodels.
Backbone.sync=function(method,model){
alert(method+":"+model.url);
};
varaccounts=newBackbone.Collection;
accounts.url='/accounts';
accounts.fetch();

Thebehavioroffetchcanbecustomizedbyusingtheavailablesetoptions.For
example,tofetchacollection,gettingan "add" eventforeverynewmodel,anda
"change" eventforeverychangedexistingmodel,withoutremovinganything:
collection.fetch({remove:false})

jQuery.ajaxoptionscanalsobepasseddirectlyasfetchoptions,sotofetchaspecific
pageofapaginatedcollection: Documents.fetch({data:{page:3}})
Notethatfetchshouldnotbeusedtopopulatecollectionsonpageloadallmodels
neededatloadtimeshouldalreadybebootstrappedintoplace.fetchisintendedfor
lazilyloadingmodelsforinterfacesthatarenotneededimmediately:forexample,
documentswithcollectionsofnotesthatmaybetoggledopenandclosed.

create

collection.create(attributes,[options])

Conveniencetocreateanewinstanceofamodelwithinacollection.Equivalentto
instantiatingamodelwithahashofattributes,savingthemodeltotheserver,and
addingthemodeltothesetafterbeingsuccessfullycreated.Returnsthenewmodel.If
clientsidevalidationfailed,themodelwillbeunsaved,withvalidationerrors.Inorder
forthistowork,youshouldsetthemodelpropertyofthecollection.Thecreate
methodcanaccepteitheranattributeshashoranexisting,unsavedmodelobject.
Creatingamodelwillcauseanimmediate "add" eventtobetriggeredonthe
collection,a "request" eventasthenewmodelissenttotheserver,aswellasa
"sync" event,oncetheserverhasrespondedwiththesuccessfulcreationofthe

model.Pass {wait:true} ifyou'dliketowaitfortheserverbeforeaddingthenew


modeltothecollection.
varLibrary=Backbone.Collection.extend({
model:Book
});
varnypl=newLibrary;
varothello=nypl.create({
title:"Othello",
author:"WilliamShakespeare"
});

Backbone.Router
Webapplicationsoftenprovidelinkable,bookmarkable,shareableURLsforimportant
locationsintheapp.Untilrecently,hashfragments( #page )wereusedtoprovidethese
permalinks,butwiththearrivaloftheHistoryAPI,it'snowpossibletousestandard

http://backbonejs.org/#changelog

19/57

3/16/2016

Backbone.js
URLs( /page ).Backbone.Routerprovidesmethodsforroutingclientsidepages,and
connectingthemtoactionsandevents.Forbrowserswhichdon'tyetsupportthe
HistoryAPI,theRouterhandlesgracefulfallbackandtransparenttranslationtothe
fragmentversionoftheURL.
Duringpageload,afteryourapplicationhasfinishedcreatingallofitsrouters,besure
tocall Backbone.history.start() or Backbone.history.start({pushState:true}) to
routetheinitialURL.

extend

Backbone.Router.extend(properties,[classProperties])

Getstartedbycreatingacustomrouterclass.Defineactionsthataretriggeredwhen
certainURLfragmentsarematched,andprovidearouteshashthatpairsroutesto
actions.Notethatyou'llwanttoavoidusingaleadingslashinyourroutedefinitions:
varWorkspace=Backbone.Router.extend({
routes:{
"help":"help",//#help
"search/:query":"search",//#search/kiwis
"search/:query/p:page":"search"//#search/kiwis/p7
},
help:function(){
...
},
search:function(query,page){
...
}
});

routes

router.routes

TherouteshashmapsURLswithparameterstofunctionsonyourrouter(orjustdirect
functiondefinitions,ifyouprefer),similartotheView'seventshash.Routescan
containparameterparts, :param ,whichmatchasingleURLcomponentbetween
slashesandsplatparts *splat ,whichcanmatchanynumberofURLcomponents.
Partofaroutecanbemadeoptionalbysurroundingitinparentheses (/:optional) .
Forexample,arouteof "search/:query/p:page" willmatchafragmentof
#search/obama/p2 ,passing "obama" and "2" totheaction.

Arouteof "file/*path" willmatch #file/folder/file.txt ,passing


"folder/file.txt" totheaction.

Arouteof "docs/:section(/:subsection)" willmatch #docs/faq and


#docs/faq/installing ,passing "faq" totheactioninthefirstcase,andpassing
"faq" and "installing" totheactioninthesecond.

Anestedoptionalrouteof "docs(/:section)(/:subsection)" willmatch #docs ,


#docs/faq ,and #docs/faq/installing ,passing "faq" totheactioninthesecond

case,andpassing "faq" and "installing" totheactioninthethird.


TrailingslashesaretreatedaspartoftheURL,and(correctly)treatedasaunique
routewhenaccessed. docs and docs/ willfiredifferentcallbacks.Ifyoucan'tavoid
generatingbothtypesofURLs,youcandefinea "docs(/)" matchertocaptureboth
cases.
Whenthevisitorpressesthebackbutton,orentersaURL,andaparticularrouteis
matched,thenameoftheactionwillbefiredasanevent,sothatotherobjectscan
listentotherouter,andbenotified.Inthefollowingexample,visiting #help/uploading
willfirea route:help eventfromtherouter.
routes:{
"help/:page":"help",
"download/*path":"download",
"folder/:name":"openFolder",

http://backbonejs.org/#changelog

20/57

3/16/2016

Backbone.js
"folder/:name:mode":"openFolder"
}

router.on("route:help",function(page){
...
});

constructor/initialize

newRouter([options])

Whencreatinganewrouter,youmaypassitsrouteshashdirectlyasanoption,ifyou
choose.All options willalsobepassedtoyour initialize function,ifdefined.

route

router.route(route,name,[callback])

Manuallycreatearoutefortherouter,The route argumentmaybearoutingstringor


regularexpression.Eachmatchingcapturefromtherouteorregularexpressionwillbe
passedasanargumenttothecallback.The name argumentwillbetriggeredasa
"route:name" eventwhenevertherouteismatched.Ifthe callback argumentis

omitted router[name] willbeusedinstead.Routesaddedlatermayoverride


previouslydeclaredroutes.
initialize:function(options){
//Matches#page/10,passing"10"
this.route("page/:number","page",function(number){...});
//Matches/117a/b/c/open,passing"117a/b/c"tothis.open
this.route(/^(.*?)\/open$/,"open");
},
open:function(id){...}

navigate

router.navigate(fragment,[options])

Wheneveryoureachapointinyourapplicationthatyou'dliketosaveasaURL,call
navigateinordertoupdatetheURL.Ifyoualsowishtocalltheroutefunction,setthe
triggeroptionto true .ToupdatetheURLwithoutcreatinganentryinthebrowser's
history,setthereplaceoptionto true .
openPage:function(pageNumber){
this.document.pages.at(pageNumber).open();
this.navigate("page/"+pageNumber);
}
#Or...
app.navigate("help/troubleshooting",{trigger:true});
#Or...
app.navigate("help/troubleshooting",{trigger:true,replace:true});

execute

router.execute(callback,args,name)

Thismethodiscalledinternallywithintherouter,wheneveraroutematchesandits
correspondingcallbackisabouttobeexecuted.Returnfalsefromexecutetocancel
thecurrenttransition.Overrideittoperformcustomparsingorwrappingofyour
routes,forexample,toparsequerystringsbeforehandingthemtoyourroutecallback,
likeso:
varRouter=Backbone.Router.extend({
execute:function(callback,args,name){
if(!loggedIn){
goToLogin();
returnfalse;
}
args.push(parseQueryString(args.pop()));
if(callback)callback.apply(this,args);
}
});

http://backbonejs.org/#changelog

21/57

3/16/2016

Backbone.js

Backbone.history
Historyservesasaglobalrouter(perframe)tohandle hashchange eventsor
pushState ,matchtheappropriateroute,andtriggercallbacks.Youshouldn'tever

havetocreateoneoftheseyourselfsince Backbone.history alreadycontainsone.


pushStatesupportexistsonapurelyoptinbasisinBackbone.Olderbrowsersthat
don'tsupport pushState willcontinuetousehashbasedURLfragments,andifahash
URLisvisitedbya pushState capablebrowser,itwillbetransparentlyupgradedtothe
trueURL.NotethatusingrealURLsrequiresyourwebservertobeabletocorrectly
renderthosepages,sobackendchangesarerequiredaswell.Forexample,ifyou
havearouteof /documents/100 ,yourwebservermustbeabletoservethatpage,if
thebrowservisitsthatURLdirectly.Forfullsearchenginecrawlability,it'sbesttohave
theservergeneratethecompleteHTMLforthepage...butifit'sawebapplication,
justrenderingthesamecontentyouwouldhavefortherootURL,andfillingintherest
withBackboneViewsandJavaScriptworksfine.

start

Backbone.history.start([options])

WhenallofyourRoutershavebeencreated,andalloftheroutesaresetupproperly,
call Backbone.history.start() tobeginmonitoring hashchange events,anddispatching
routes.Subsequentcallsto Backbone.history.start() willthrowanerror,and
Backbone.History.started isabooleanvalueindicatingwhetherithasalreadybeen

called.
Toindicatethatyou'dliketouseHTML5 pushState supportinyourapplication,use
Backbone.history.start({pushState:true}) .Ifyou'dliketouse pushState ,buthave

browsersthatdon'tsupportitnativelyusefullpagerefreshesinstead,youcanadd
{hashChange:false} totheoptions.

Ifyourapplicationisnotbeingservedfromtherooturl / ofyourdomain,besureto
tellHistorywheretherootreallyis,asanoption: Backbone.history.start({pushState:
true,root:"/public/search/"})

Whencalled,ifaroutesucceedswithamatchforthecurrentURL,
Backbone.history.start() returns true .IfnodefinedroutematchesthecurrentURL,

itreturns false .
Iftheserverhasalreadyrenderedtheentirepage,andyoudon'twanttheinitialroute
totriggerwhenstartingHistory,pass silent:true .
BecausehashbasedhistoryinInternetExplorerreliesonan <iframe> ,besuretocall
start() onlyaftertheDOMisready.

$(function(){
newWorkspaceRouter();
newHelpPaneRouter();
Backbone.history.start({pushState:true});
});

Backbone.sync
Backbone.syncisthefunctionthatBackbonecallseverytimeitattemptstoreador
saveamodeltotheserver.Bydefault,ituses jQuery.ajax tomakeaRESTfulJSON
requestandreturnsajqXHR.Youcanoverrideitinordertouseadifferentpersistence
strategy,suchasWebSockets,XMLtransport,orLocalStorage.
ThemethodsignatureofBackbone.syncis sync(method,model,[options])
methodtheCRUDmethod( "create" , "read" , "update" ,or "delete" )
modelthemodeltobesaved(orcollectiontoberead)
optionssuccessanderrorcallbacks,andallotherjQueryrequestoptions

http://backbonejs.org/#changelog

22/57

3/16/2016

Backbone.js
Withthedefaultimplementation,whenBackbone.syncsendsuparequesttosavea
model,itsattributeswillbepassed,serializedasJSON,andsentintheHTTPbody
withcontenttype application/json .WhenreturningaJSONresponse,senddownthe
attributesofthemodelthathavebeenchangedbytheserver,andneedtobeupdated
ontheclient.Whenrespondingtoa "read" requestfromacollection
(Collection#fetch),senddownanarrayofmodelattributeobjects.
Wheneveramodelorcollectionbeginsasyncwiththeserver,a "request" eventis
emitted.Iftherequestcompletessuccessfullyyou'llgeta "sync" event,andan
"error" eventifnot.

Thesyncfunctionmaybeoverriddengloballyas Backbone.sync ,oratafinergrained


level,byaddinga sync functiontoaBackbonecollectionortoanindividualmodel.
ThedefaultsynchandlermapsCRUDtoRESTlikeso:
createPOST /collection
readGET /collection[/id]
updatePUT /collection/id
patchPATCH /collection/id
deleteDELETE /collection/id

Asanexample,aRails4handlerrespondingtoan "update" callfrom Backbone might


looklikethis:
defupdate
account=Account.findparams[:id]
permitted=params.require(:account).permit(:name,:otherparam)
account.update_attributespermitted
render:json=>account
end

OnemoretipforintegratingRailsversionspriorto3.1istodisablethedefault
namespacingfor to_json callsonmodelsbysetting
ActiveRecord::Base.include_root_in_json=false

ajax

Backbone.ajax=function(request){...};

IfyouwanttouseacustomAJAXfunction,oryourendpointdoesn'tsupportthe
jQuery.ajaxAPIandyouneedtotweakthings,youcandosobysetting
Backbone.ajax .

emulateHTTP

Backbone.emulateHTTP=true

Ifyouwanttoworkwithalegacywebserverthatdoesn'tsupportBackbone'sdefault
REST/HTTPapproach,youmaychoosetoturnon Backbone.emulateHTTP .Settingthis
optionwillfake PUT , PATCH and DELETE requestswithaHTTP POST ,settingthe X
HTTPMethodOverride headerwiththetruemethod.If emulateJSON isalsoon,thetrue

methodwillbepassedasanadditional _method parameter.


Backbone.emulateHTTP=true;
model.save();//POSTto"/collection/id",with"_method=PUT"+header.

emulateJSON

Backbone.emulateJSON=true

Ifyou'reworkingwithalegacywebserverthatcan'thandlerequestsencodedas
application/json ,setting Backbone.emulateJSON=true; willcausetheJSONtobe

serializedundera model parameter,andtherequesttobemadewitha


application/xwwwformurlencoded MIMEtype,asiffromanHTMLform.

Backbone.View
Backboneviewsarealmostmoreconventionthantheyarecodetheydon't
determineanythingaboutyourHTMLorCSSforyou,andcanbeusedwithany

http://backbonejs.org/#changelog

23/57

3/16/2016

Backbone.js
JavaScripttemplatinglibrary.Thegeneralideaistoorganizeyourinterfaceintological
views,backedbymodels,eachofwhichcanbeupdatedindependentlywhenthe
modelchanges,withouthavingtoredrawthepage.InsteadofdiggingintoaJSON
object,lookingupanelementintheDOM,andupdatingtheHTMLbyhand,youcan
bindyourview's render functiontothemodel's "change" eventandnow
everywherethatmodeldataisdisplayedintheUI,itisalwaysimmediatelyuptodate.

extend

Backbone.View.extend(properties,[classProperties])

Getstartedwithviewsbycreatingacustomviewclass.You'llwanttooverridethe
renderfunction,specifyyourdeclarativeevents,andperhapsthe tagName , className ,
or id oftheView'srootelement.
varDocumentRow=Backbone.View.extend({
tagName:"li",
className:"documentrow",
events:{
"click.icon":"open",
"click.button.edit":"openEditDialog",
"click.button.delete":"destroy"
},
initialize:function(){
this.listenTo(this.model,"change",this.render);
},
render:function(){
...
}
});

Propertieslike tagName , id , className , el ,and events mayalsobedefinedasa


function,ifyouwanttowaittodefinethemuntilruntime.

constructor/initialize

newView([options])

Thereareseveralspecialoptionsthat,ifpassed,willbeattacheddirectlytotheview:
model , collection , el , id , className , tagName , attributes and events .Ifthe

viewdefinesaninitializefunction,itwillbecalledwhentheviewisfirstcreated.If
you'dliketocreateaviewthatreferencesanelementalreadyintheDOM,passinthe
elementasanoption: newView({el:existingElement})
vardoc=documents.first();
newDocumentRow({
model:doc,
id:"documentrow"+doc.id
});

el

view.el

AllviewshaveaDOMelementatalltimes(theelproperty),whetherthey'vealready
beeninsertedintothepageornot.Inthisfashion,viewscanberenderedatanytime,
andinsertedintotheDOMallatonce,inordertogethighperformanceUIrendering
withasfewreflowsandrepaintsaspossible.
this.el canberesolvedfromaDOMselectorstringoranElementotherwiseitwill

becreatedfromtheview's tagName , className , id and attributes properties.If


noneareset, this.el isanempty div ,whichisoftenjustfine.Anelreferencemay
alsobepassedintotheview'sconstructor.
varItemView=Backbone.View.extend({
tagName:'li'
});
varBodyView=Backbone.View.extend({
el:'body'
});

http://backbonejs.org/#changelog

24/57

3/16/2016

Backbone.js
varitem=newItemView();
varbody=newBodyView();
alert(item.el+''+body.el);

$el

view.$el

AcachedjQueryobjectfortheview'selement.Ahandyreferenceinsteadofre
wrappingtheDOMelementallthetime.
view.$el.show();
listView.$el.append(itemView.el);

setElement

view.setElement(element)

Ifyou'dliketoapplyaBackboneviewtoadifferentDOMelement,usesetElement,
whichwillalsocreatethecached $el referenceandmovetheview'sdelegatedevents
fromtheoldelementtothenewone.

attributes

view.attributes

AhashofattributesthatwillbesetasHTMLDOMelementattributesontheview's el
(id,class,dataproperties,etc.),orafunctionthatreturnssuchahash.

$(jQuery)

view.$(selector)

IfjQueryisincludedonthepage,eachviewhasa$functionthatrunsqueriesscoped
withintheview'selement.IfyouusethisscopedjQueryfunction,youdon'thavetouse
modelidsaspartofyourquerytopulloutspecificelementsinalist,andcanrelymuch
moreonHTMLclassattributes.It'sequivalenttorunning: view.$el.find(selector)
ui.Chapter=Backbone.View.extend({
serialize:function(){
return{
title:this.$(".title").text(),
start:this.$(".startpage").text(),
end:this.$(".endpage").text()
};
}
});

template

view.template([data])

Whiletemplatingforaviewisn'tafunctionprovideddirectlybyBackbone,it'softena
niceconventiontodefineatemplatefunctiononyourviews.Inthisway,when
renderingyourview,youhaveconvenientaccesstoinstancedata.Forexample,using
Underscoretemplates:
varLibraryView=Backbone.View.extend({
template:_.template(...)
});

render

view.render()

Thedefaultimplementationofrenderisanoop.Overridethisfunctionwithyourcode
thatrenderstheviewtemplatefrommodeldata,andupdates this.el withthenew
HTML.Agoodconventionisto returnthis attheendofrendertoenablechained
calls.
varBookmark=Backbone.View.extend({
template:_.template(...),
render:function(){
this.$el.html(this.template(this.model.attributes));
returnthis;
}
});

BackboneisagnosticwithrespecttoyourpreferredmethodofHTMLtemplating.Your
renderfunctioncouldevenmungetogetheranHTMLstring,oruse

http://backbonejs.org/#changelog

25/57

3/16/2016

Backbone.js
document.createElement togenerateaDOMtree.However,wesuggestchoosinga

niceJavaScripttemplatinglibrary.Mustache.js,Hamljs,andEcoareallfine
alternatives.BecauseUnderscore.jsisalreadyonthepage,_.templateisavailable,
andisanexcellentchoiceifyouprefersimpleinterpolatedJavaScriptstyletemplates.
Whatevertemplatingstrategyyouendupwith,it'sniceifyouneverhavetoputstrings
ofHTMLinyourJavaScript.AtDocumentCloud,weuseJammitinordertopackageup
JavaScripttemplatesstoredin /app/views aspartofourmain core.js asset
package.

remove

view.remove()

Removesaviewandits el fromtheDOM,andcallsstopListeningtoremoveany
boundeventsthattheviewhaslistenTo'd.

events

view.eventsorview.events()

Theeventshash(ormethod)canbeusedtospecifyasetofDOMeventsthatwillbe
boundtomethodsonyourViewthroughdelegateEvents.
Backbonewillautomaticallyattachtheeventlistenersatinstantiationtime,rightbefore
invokinginitialize.
varENTER_KEY=13;
varInputView=Backbone.View.extend({
tagName:'input',
events:{
"keydown":"keyAction",
},
render:function(){...},
keyAction:function(e){
if(e.which===ENTER_KEY){
this.collection.add({text:this.$el.val()});
}
}
});

delegateEvents

delegateEvents([events])

UsesjQuery's on functiontoprovidedeclarativecallbacksforDOMeventswithina
view.Ifaneventshashisnotpasseddirectly,uses this.events asthesource.Events
arewrittenintheformat {"eventselector":"callback"} .Thecallbackmaybeeither
thenameofamethodontheview,oradirectfunctionbody.Omittingthe selector
causestheeventtobeboundtotheview'srootelement( this.el ).Bydefault,
delegateEvents iscalledwithintheView'sconstructorforyou,soifyouhaveasimple
events hash,allofyourDOMeventswillalwaysalreadybeconnected,andyouwill

neverhavetocallthisfunctionyourself.
The events propertymayalsobedefinedasafunctionthatreturnsaneventshash,
tomakeiteasiertoprogrammaticallydefineyourevents,aswellasinheritthemfrom
parentviews.
UsingdelegateEventsprovidesanumberofadvantagesovermanuallyusingjQuery
tobindeventstochildelementsduringrender.Allattachedcallbacksareboundtothe
viewbeforebeinghandedofftojQuery,sowhenthecallbacksareinvoked, this
continuestorefertotheviewobject.WhendelegateEventsisrunagain,perhapswith
adifferent events hash,allcallbacksareremovedanddelegatedafreshusefulfor
viewswhichneedtobehavedifferentlywhenindifferentmodes.
AsingleeventversionofdelegateEventsisavailableas delegate .Infact,
delegateEventsissimplyamultieventwrapperaround delegate .Acounterpartto
undelegateEvents isavailableas undelegate .

Aviewthatdisplaysadocumentinasearchresultmightlooksomethinglikethis:

http://backbonejs.org/#changelog

26/57

3/16/2016

Backbone.js
varDocumentView=Backbone.View.extend({
events:{
"dblclick":"open",
"click.icon.doc":"select",
"contextmenu.icon.doc":"showMenu",
"click.show_notes":"toggleNotes",
"click.title.lock":"editAccessLevel",
"mouseover.title.date":"showTooltip"
},
render:function(){
this.$el.html(this.template(this.model.attributes));
returnthis;
},
open:function(){
window.open(this.model.get("viewer_url"));
},
select:function(){
this.model.set({selected:true});
},
...
});

undelegateEvents

undelegateEvents()

Removesalloftheview'sdelegatedevents.Usefulifyouwanttodisableorremovea
viewfromtheDOMtemporarily.

Utility
Backbone.noConflict

varbackbone=Backbone.noConflict();

Returnsthe Backbone objectbacktoitsoriginalvalue.Youcanusethereturnvalueof


Backbone.noConflict() tokeepalocalreferencetoBackbone.Usefulforembedding

Backboneonthirdpartywebsites,whereyoudon'twanttoclobbertheexisting
Backbone.
varlocalBackbone=Backbone.noConflict();
varmodel=localBackbone.Model.extend(...);

Backbone.$

Backbone.$=$;

Ifyouhavemultiplecopiesof jQuery onthepage,orsimplywanttotellBackboneto


useaparticularobjectasitsDOM/Ajaxlibrary,thisisthepropertyforyou.
Backbone.$=require('jquery');

F.A.Q.
WhyuseBackbone,not[otherframeworkX]?
Ifyoureyehasn'talreadybeencaughtbytheadaptabilityandelanondisplayinthe
abovelistofexamples,wecangetmorespecific:Backbone.jsaimstoprovidethe
commonfoundationthatdatarichwebapplicationswithambitiousinterfacesrequire
whileverydeliberatelyavoidingpaintingyouintoacornerbymakinganydecisionsthat
you'rebetterequippedtomakeyourself.
Thefocusisonsupplyingyouwithhelpfulmethodstomanipulateandqueryyourdata,noton
HTMLwidgetsorreinventingtheJavaScriptobjectmodel.
Backbonedoesnotforceyoutouseasingletemplateengine.ViewscanbindtoHTML
constructedinyourfavoriteway.
It'ssmaller.Therearefewerkilobytesforyourbrowserorphonetodownload,andless
conceptualsurfacearea.Youcanreadandunderstandthesourceinanafternoon.
Itdoesn'tdependonstuffingapplicationlogicintoyourHTML.There'snoembedded
JavaScript,templatelogic,orbindinghookupcodein data or ng attributes,andnoneed

http://backbonejs.org/#changelog

27/57

3/16/2016

Backbone.js
toinventyourownHTMLtags.
Synchronouseventsareusedasthefundamentalbuildingblock,notadifficulttoreasonabout
runloop,orbyconstantlypollingandtraversingyourdatastructurestohuntforchanges.And
ifyouwantaspecificeventtobeasynchronousandaggregated,noproblem.
Backbonescaleswell,fromembeddedwidgetstomassiveapps.
Backboneisalibrary,notaframework,andplayswellwithothers.YoucanembedBackbone
widgetsinDojoappswithouttrouble,oruseBackbonemodelsasthedatabackingforD3
visualizations(topicktwoentirelyrandomexamples).
"Twowaydatabinding"isavoided.Whileitcertainlymakesforaniftydemo,andworksforthe
mostbasicCRUD,itdoesn'ttendtobeterriblyusefulinyourrealworldapp.Sometimesyou
wanttoupdateoneverykeypress,sometimesonblur,sometimeswhenthepanelisclosed,
andsometimeswhenthe"save"buttonisclicked.Inalmostallcases,simplyserializingthe
formtoJSONisfasterandeasier.Allthataside,ifyourheartisset,goforit.
There'snobuiltinperformancepenaltyforchoosingtostructureyourcodewithBackbone.And
ifyoudowanttooptimizefurther,thinmodelsandtemplateswithflexiblegranularitymakeit
easytosqueezeeverylastdropofpotentialperformanceoutof,say,IE8.

There'sMoreThanOneWayToDoIt
It'scommonforfolksjustgettingstartedtotreattheexampleslistedonthispageas
somesortofgospeltruth.Infact,Backbone.jsisintendedtobefairlyagnosticabout
manycommonpatternsinclientsidecode.Forexample...
ReferencesbetweenModelsandViewscanbehandledseveralways.Somepeople
liketohavedirectpointers,whereviewscorrespond1:1withmodels( model.view and
view.model ).Othersprefertohaveintermediate"controller"objectsthatorchestrate

thecreationandorganizationofviewsintoahierarchy.Othersstillprefertheevented
approach,andalwaysfireeventsinsteadofcallingmethodsdirectly.Allofthesestyles
workwell.
BatchoperationsonModelsarecommon,butoftenbesthandleddifferently
dependingonyourserversidesetup.Somefolksdon'tmindmakingindividualAjax
requests.OtherscreateexplicitresourcesforRESTfulbatchoperations:
/notes/batch/destroy?ids=1,2,3,4 .OtherstunnelRESToverJSON,withthecreation

of"changeset"requests:
{
"create":[arrayofmodelstocreate]
"update":[arrayofmodelstoupdate]
"destroy":[arrayofmodelidstodestroy]
}

Feelfreetodefineyourownevents.Backbone.Eventsisdesignedsothatyoucan
mixitintoanyJavaScriptobjectorprototype.Sinceyoucanuseanystringasan
event,it'softenhandytobindandtriggeryourowncustomevents:
model.on("selected:true") or model.on("editing")

RendertheUIasyouseefit.BackboneisagnosticastowhetheryouuseUnderscore
templates,Mustache.js,directDOMmanipulation,serversiderenderedsnippetsof
HTML,orjQueryUIinyour render function.Sometimesyou'llcreateaviewforeach
model...sometimesyou'llhaveaviewthatrendersthousandsofmodelsatonce,ina
tightloop.Bothcanbeappropriateinthesameapp,dependingonthequantityofdata
involved,andthecomplexityoftheUI.

NestedModels&Collections
It'scommontonestcollectionsinsideofmodelswithBackbone.Forexample,consider
a Mailbox modelthatcontainsmany Message models.Onenicepatternforhandling
thisishavea this.messages collectionforeachmailbox,enablingthelazyloadingof
messages,whenthemailboxisfirstopened...perhapswith MessageList views
listeningfor "add" and "remove" events.
varMailbox=Backbone.Model.extend({
initialize:function(){
this.messages=newMessages;
this.messages.url='/mailbox/'+this.id+'/messages';
this.messages.on("reset",this.updateCounts);

http://backbonejs.org/#changelog

28/57

3/16/2016

Backbone.js
},
...
});
varinbox=newMailbox;
//Andthen,whentheInboxisopened:
inbox.messages.fetch({reset:true});

Ifyou'relookingforsomethingmoreopinionated,thereareanumberofBackbone
pluginsthataddsophisticatedassociationsamongmodels,availableonthewiki.
Backbonedoesn'tincludedirectsupportfornestedmodelsandcollectionsor"has
many"associationsbecausethereareanumberofgoodpatternsformodeling
structureddataontheclientside,andBackboneshouldprovidethefoundationfor
implementinganyofthem.Youmaywantto
MirroranSQLdatabase'sstructure,orthestructureofaNoSQLdatabase.
Usemodelswitharraysof"foreignkey"ids,andjointotoplevelcollections(alatables).
Forassociationsthatarenumerous,usearangeofidsinsteadofanexplicitlist.
Avoidids,andusedirectreferences,creatingapartialobjectgraphrepresentingyourdataset.
Lazilyloadjoinedmodelsfromtheserver,orlazilydeserializenestedmodelsfromJSON
documents.

LoadingBootstrappedModels
Whenyourappfirstloads,it'scommontohaveasetofinitialmodelsthatyouknow
you'regoingtoneed,inordertorenderthepage.InsteadoffiringanextraAJAX
requesttofetchthem,anicerpatternistohavetheirdataalreadybootstrappedinto
thepage.Youcanthenuseresettopopulateyourcollectionswiththeinitialdata.At
DocumentCloud,intheERBtemplatefortheworkspace,wedosomethingalongthese
lines:
<script>
varaccounts=newBackbone.Collection;
accounts.reset(<%=@accounts.to_json%>);
varprojects=newBackbone.Collection;
projects.reset(<%=@projects.to_json(:collaborators=>true)%>);
</script>

Youhavetoescape </ withintheJSONstring,topreventjavascriptinjectionattacks.

ExtendingBackbone
ManyJavaScriptlibrariesaremeanttobeinsularandselfenclosed,whereyou
interactwiththembycallingtheirpublicAPI,butneverpeekinsideattheguts.
Backbone.jsisnotthatkindoflibrary.
Becauseitservesasafoundationforyourapplication,you'remeanttoextendand
enhanceitinthewaysyouseefittheentiresourcecodeisannotatedtomakethis
easierforyou.You'llfindthatthere'sverylittlethereapartfromcorefunctions,and
mostofthosecanbeoverriddenoraugmentedshouldyoufindtheneed.Ifyoucatch
yourselfaddingmethodsto Backbone.Model.prototype ,orcreatingyourownbase
subclass,don'tworrythat'showthingsaresupposedtowork.

HowdoesBackbonerelateto"traditional"MVC?
DifferentimplementationsoftheModelViewControllerpatterntendtodisagreeabout
thedefinitionofacontroller.Ifithelpsany,inBackbone,theViewclasscanalsobe
thoughtofasakindofcontroller,dispatchingeventsthatoriginatefromtheUI,withthe
HTMLtemplateservingasthetrueview.WecallitaViewbecauseitrepresentsa
logicalchunkofUI,responsibleforthecontentsofasingleDOMelement.
ComparingtheoverallstructureofBackbonetoaserversideMVCframeworklike
Rails,thepieceslineuplikeso:

http://backbonejs.org/#changelog

29/57

3/16/2016

Backbone.js
Backbone.ModelLikeaRailsmodelminustheclassmethods.Wrapsarowofdatain
businesslogic.
Backbone.CollectionAgroupofmodelsontheclientside,withsorting/filtering/aggregation
logic.
Backbone.RouterRails routes.rb +Railscontrolleractions.MapsURLstofunctions.
Backbone.ViewAlogical,reusablepieceofUI.Often,butnotalways,associatedwitha
model.
ClientsideTemplatesRails .html.erb views,renderingachunkofHTML.

Binding"this"
PerhapsthesinglemostcommonJavaScript"gotcha"isthefactthatwhenyoupassa
functionasacallback,itsvaluefor this islost.Whendealingwitheventsand
callbacksinBackbone,you'lloftenfinditusefultorelyonlistenToortheoptional
context argumentthatmanyofUnderscoreandBackbone'smethodsusetospecify

the this thatwillbeusedwhenthecallbackislaterinvoked.(See_.each,_.map,and


object.on,tonameafew).Vieweventsareautomaticallyboundtotheview'scontext
foryou.Youmayalsofindithelpfultouse_.bindand_.bindAllfromUnderscore.js.
varMessageList=Backbone.View.extend({
initialize:function(){
varmessages=this.collection;
messages.on("reset",this.render,this);
messages.on("add",this.addMessage,this);
messages.on("remove",this.removeMessage,this);
messsages.each(this.addMessage,this);
}
});
//Later,intheapp...
Inbox.messages.add(newMessage);

WorkingwithRails
Backbone.jswasoriginallyextractedfromaRailsapplicationgettingyourclientside
(Backbone)Modelstosynccorrectlywithyourserverside(Rails)Modelsispainless,
buttherearestillafewthingstobeawareof.
Bydefault,Railsversionspriorto3.1addanextralayerofwrappingaroundtheJSON
representationofmodels.Youcandisablethiswrappingbysetting:
ActiveRecord::Base.include_root_in_json=false

...inyourconfiguration.Otherwise,overrideparsetopullmodelattributesoutofthe
wrapper.Similarly,BackbonePUTsandPOSTsdirectJSONrepresentationsofmodels,
wherebydefaultRailsexpectsnamespacedattributes.Youcanhaveyourcontrollers
filterattributesdirectlyfrom params ,oryoucanoverridetoJSONinBackbonetoadd
theextrawrappingRailsexpects.

Examples
Thelistofexamplesthatfollows,whilelong,isnotexhaustive.Ifyou'veworkedonan
appthatusesBackbone,pleaseaddittothewikipageofBackboneapps.
JrmeGravelNiquethascontributedaTodoListapplicationthatisbundledinthe
repositoryasBackboneexample.Ifyou'rewonderingwheretogetstartedwith
Backboneingeneral,takeamomenttoreadthroughtheannotatedsource.Theapp
usesaLocalStorageadaptertotransparentlysaveallofyourtodoswithinyour
browser,insteadofsendingthemtoaserver.Jrmealsohasaversionhostedat
localtodos.com.

http://backbonejs.org/#changelog

30/57

Вам также может понравиться