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

12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub

Personal Opensource Business Explore Pricing Blog Support Thisrepository Search Signin Signup

jashkenas / backbone Watch 1,641 Star 25,880 Fork 5,651

Code Issues 42 Pullrequests 34 Projects 0 Wiki Pulse Graphs

Backbone,ThePrimer
RafiDudekulaeditedthispageonJan1426revisions

AcommonsentimentfromdeveloperscomingtoBackboneisthattheydon'tknowwheretostart Pages 9
withit.Unlikefullfeaturedframeworkswithprescribedworkflows,Backboneisalightweightlibrary
withfewopinions.Atitsworst,somewouldsaythatBackbonehasTOOfewopinions.Atitsbest Home

though,Backboneisaflexiblecomponentlibrarydesignedtoprovideabaselinesolutionfor Backbone,ThePrimer
commonapplicationdesignpatterns.
ContributingtoBackbone
ThecoreofBackboneprovidesacomprehensiveRESTfulservicepackage.Thisprimerassumes DevelopmentTools
thatyouhaveabasicunderstandingofRESTresources.Thisprimerwillsummarizethebasic
Extensions,Plugins,
interactionsofBackbonecomponentswithaRESTfulAPI,andwilldemonstratesomebasic
Resources
techniquesforrenderingdataintoviews.
ProjectsandCompaniesusing
Backbone
TableofContents
Startupsandapplicationsthat
usebackbone.js
What'sInTheBox?
RESTfulResources Tutorials,blogpostsand
examplesites
UsingModels
UsingCollections UsingBackbonewithout
jQuery
BackboneCRUD
UsingEvents
Clonethiswikilocally
UsingViews
ASimpleRESTApplication https://github.com/jashkenas/backbone.wik

What'sInTheBox?

ThefirstthingtofamiliarizewitharethebasiccomponentsprovidedbyBackbone.We'llfocuson
thefollowingfoundationcomponentsthatmakeupBackboneapplications:

Backbone.Model

Modelsstoreapplicationdata,andsyncwithRESTservices.Amodelmaypredefineits
defaultattributes,andwillemiteventswhenanyofitsmanageddataattributeschange.

Backbone.Collection

Collectionsmanageasetofmodels,andsyncwithRESTservices.Acollectionprovidesbasic
searchmethodsforqueryingitsmanagedmodels,andemitseventswhenanymodelsare
added,removed,sortedand/orchanged.

Backbone.View

AviewconnectsamodeltoitsvisualrepresentationintheHTMLDocumentObjectModel(or,
the"DOM").Viewsrendertheirassociatedmodel'sdataintotheDOM,andcaptureuserinput
fromtheDOMtosendbackintothemodel.

Bonus...Underscore!

BackbonehastwoJavaScriptlibrarydependencies:jQueryandUnderscoreJS.Chancesare
goodthatyou'refamiliarwithjQuery.Ifyoudon'tknowUnderscore,reviewitsdocumentation.
Underscoreprovidescommonfunctionalprogrammingforworkingwithdatastructures.When

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 1/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
settingupBackbone,yougetthefullcapabilitiesofUnderscoreaspartofthepackage.jQuery
isnotaharddependencyandcanbereplaced.

Backbonedoesincludeadditionalusefulfeatures(suchasBackbone.Router),howeverwe'lljust
befocusingonthesecomponentsforthisprimer.

RESTfulResources

Forthisprimer,let'sassumethefollowingRESTfulMuppetsdataserviceisavailable:

GET/muppets/......ReadsallMuppets.
POST/muppets/......CreatesanewMuppet.
GET/muppets/:id...ReadsaMuppet.
PUT/muppets/:id...UpdatesaMuppet.
DEL/muppets/:id...DestroysaMuppet.

DataStructures
GET/muppets/

GetsalistofallMuppetswithintheapplication.ReturnsanarrayofallMuppetmodels(withsome
additionalmetadata):

{
"total":2,
"page":1,
"perPage ":10,
"muppets ":[
{
"id":1,
"name":"Kermit ",
"occupation ":"beinggreen "
},
{
"id":2,
"name":"Gonzo",
"occupation ":"plumber "
}
]
}

POST/muppets/

CreatesanewMuppetmodelbasedontheposteddata.Returnsthenewlycreatedmodel:

{
"id":3,
"name":"Animal ",
"occupation ":"drummer "
}

GET/muppets/:id

PUT/muppets/:id

DEL/muppets/:id

Gets,modifies,and/ordeletesaspecificusermodel.Allactionsreturntherequested/modified
model:

{
"id":1,
"name":"Kermit ",
"occupation ":"beinggreen "
}

UsingModels

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 2/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
First,let'sbuildasinglemodelthatmanagesdataforKermit.WeknowthatKermit'sREST
endpointis"/muppets/1" (ie:/muppets/:id ,andKermit'sidis1).ConfiguredasaBackbone
model,Kermitlookslikethis:

varKermitModel =Backbone .Model.extend ({


url:'/muppets/1 ',
defaults :{
id :null,
name :null,
occupation :null
}
})

Kermit'smodeldoestwothings:

ItdefinesaRESTfulURLforhismodeltosyncwith,and...
Itdefinesdefaultattributesforhismodel.DefaultattributesareusefulforrepresentingAPI
datacompositionwithinyourfrontendcode.Also,thesedefaultsguaranteethatyourmodelis
alwaysfullyformed,evenbeforeloadingitsdatafromtheserver.

However,whatISthatKermitModel object?WhenyouextendaBackbonecomponent,you
alwaysgetbackaconstructorfunction.Thisisreallyimportant.Soimportant,infact,thatwe
shouldrepeatthatrule:

WhenyouextendaBackbonecomponent,youalwaysgetbackaconstructorfunction.

So,becauseextendingaBackbonecomponentgivesusaconstructorfunction,thatmeanswe
needtocreateaninstanceofthecomponentbeforeusingit.Let'sbuildaninstanceofthe
KermitModel :

varkermit =newKermitModel ()

kermit .fetch().then(function (){


kermit .get('name')//>>"Kermit"
kermit .get('occupation ')//>>"beinggreen"
kermit .set('occupation ','muppetringleader ')
kermit .save()
})

AftercreatinganewinstanceofourKermitmodel,wecallfetchtohaveitloaddatafromits
RESTendpoint.Callingfetchreturnsapromiseobject,ontowhichwecanchainsuccessand
errorcallbacks.Intheaboveexample,weperformsomebasicactionsonourmodelafterloading
it.CommonlyusedModelmethodsinclude:

fetch:fetchesthemodel'sdatafromitsRESTserviceusingaGETrequest.

get:getsanamedattributefromthemodel.

set:setsvaluesfornamedmodelattributes(withoutpersisting).

save:setsattributes,andthenpersiststhemodeldatausingaPUTrequest.

destroy :decommissionsthemodel,andpersiststhisusingaDELETE request.

UsingCollections
Collectionshandletheloadingandmanagementofasetofmodels.WefirstdefineaModelclass
tobeusedforthesetofmodels,andthenattachthatModelclasstoamanagingcollectionalong
withanendpointURL:

varMuppetModel =Backbone .Model.extend ({


defaults :{
id :null,
name :null,
occupation :null
}
})

varMuppetsCollection =Backbone .Collection .extend ({


url:'/muppets ',

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 3/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
model :MuppetModel
})

Intheaboveexample,MuppetsCollection willloaddatafromthe"/muppets" listendpoint.It


willthenconstructtheloadeddataintoasetofMuppetModel instances.

ToloadourcollectionofMuppetmodels,webuildacollectioninstanceandthencallfetch:

varmuppets =newMuppetsCollection ()

muppets .fetch().then(function (){


console .log(muppets .length )//>>length:1
})

Easy,right?However,there'saproblemhere:ourcollectiononlycreatedasinglemodel.Wewere
supposedtogetbackalistoftwoitems.Let'sreviewagainwhattheGET/muppets/ service
returned...

{
"total":2,
"page":1,
"perPage ":10,
"muppets ":[
{
"id":1,
"name":"Kermit ",
"occupation ":"beinggreen "
},
{
"id":2,
"name":"Gonzo",
"occupation ":"plumber "
}
]
}

Wecanseethatthislistdatadoesindeedcontaintworecords,howeverourcollectiononlyfetched
onemodelinstance.Why?ThereasonisbecauseCollectionsarederivedfromArrays,while
ModelsarederivedfromObjects.Inthiscase,ourrootdatastructureisanObject(notanarray),
soourcollectiontriedtoparsethereturneddatadirectlyintoamodel.

Whatwereallywantisforourcollectiontopopulatethesetfromthe"muppets" arraypropertyof
thereturneddataobject.Toaddressthis,wesimplyaddaparsemethodontoourcollection:

varMuppetCollection =Backbone .Collection .extend ({


url:'/muppets ',
model :MuppetModel,

parse:function (data){
return data.muppets
}
})

ACollection'sparsemethodreceivesrawdataloadedfromourAPI,andmayreturnasubsetof
thatdatatobeloadedintothecollection.InBackbone,bothModelsandCollectionssupportthe
definitionofaparsemethod.Usingparseisveryusefulforreconcilingdifferencesbetween
yourAPIdesignandyourfrontendapplicationarchitecture(whichoftentimeswon'tmaponeto
one,andthat'sokay).

Withtheparsemethodinplace,thefollowingnowhappensuponfetchingthecollection:

varmuppets =newMuppetCollection ()

muppets .fetch().then(function (){


console .log(muppets .length )//>>length:2
})

muppets .get(1)//>>Returnsthe"Kermit"model,byidreference

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 4/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
muppets .get(2)//>>Returnsthe"Gonzo"model,byidreference
muppets .at(0)//>>Returnsthe"Kermit"model,byindex
muppets .findWhere ({name :'Gonzo'})//>>returnsthe"Gonzo"model

Success!ThereturnedlistofMuppetswereparsedasexpectedintoacollectionofMuppetModel
instances,andtheCollectionprovidedsomebasicmethodsforqueryingthem.Commonlyused
Collectionmethodsinclude:

fetch:fetchesthecollection'sdatausingaGETrequest.

create :addsanewmodelintothecollection,andpersistsitviaPOST.

add:addsanewmodelintothecollectionwithoutpersisting.

remove :removesamodelfromthecollectionwithoutpersisting.

get:getsamodelfromthecollectionbyidreference.

at:getsamodelfromthecollectionbyindex.

find:findsallrecordsmatchingspecificsearchcriteria.

BackboneCRUD
Create,Read,Update,andDestroyarethefourmajordatainteractionsthatanapplicationmust
manage.BackboneModelsandCollectionsworkcloselytogethertodelegatetheseroles.Infact,
therelationshipofModelsandCollections(notsocoincidentally)mirrorsthedesignofaRESTful
API.Toreview:

varMuppetModel =Backbone .Model.extend ({


defaults :{
id :null,
name :null,
occupation :null
}
})

varMuppetCollection =Backbone .Collection .extend ({


url:'/muppets ',
model :MuppetModel
})

NoteabovethattheModelclassdoesNOTdefineaurlendpointtosyncwith.Thisisbecause
modelswithinacollectionwillautomaticallyconstructtheirurlreferenceas"
<collection.url>/<model.id>" .Thismeansthatafterfetchingthecollection,ourKermitmodel
(withanidof1)willautomaticallybeconfiguredtosyncwithaurlof"/muppets/1" .

Create
UseCollection.create toPOSTnewdatatoalistendpoint.TheAPIshouldreturncomplete
dataforthenewdatabaserecord,includingitsassignedid.Thenewmodeliscreated
immediatelywithinthefrontendcollection,unlessspecificallytoldtowaitforaresponsefromthe
server.

muppetsList .create ({name :'Piggy',occupation :'fashionista '})

Read
UseCollection.fetch orModel.fetch toloaddataviaGET.Yougenerallyshouldn'tneedto
callfetchonmodelswithinacollection,giventhattheirdatawillbefetchedwiththeset.

kermit .fetch()
muppetsList .fetch()

Update
UseModel.save toPUTupdateddataforamodel.Themodel'scompletesetofdataattributes
aresenttotheAPI.

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 5/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub

kermit .save('occupation ','beingawesome ')

SomeAPIconfigurationsmayalsosupportthePATCHmethodtoperformpartialmodelupdates
(whereonlymodifieddataattributesaresenttotheAPI).ThiscanbeachievedinBackboneby
callingModel.save andpassinga{patch:true} option.

kermit .save('occupation ','beingawesome ',{patch :true})

Destroy
UseModel.destroy toDELETE amodelinstance.Themodelwillremoveitselffromanyparent
collection,andissueaDELETE requesttotheAPI.

kermit .destroy ()

UsingEvents

BackbonealsoprovidesarobustEventsframework,basedupontheobserverpattern.Amajor
benefitofBackboneEventsistheirsupportforcontextpassing,or,specifyingwhatthisrefersto
whenaneventhandleristriggered:

target.on(event,handler,context)
target.off(event,handler,context)
target.trigger(event)

OtherkeyfeaturesoftheBackboneEventsframeworkincludetheinversionofcontrolevent
binders:

this.listenTo(target,event,handler)
this.stopListening()

Thesereversedeventbindersallowalisteningobjecttotrackitsowneventbindings,thusallowing
thelisteningobjecttoquicklyreleaseitselffromallconnections.Asageneralruleofmemory
management,objectswithashorterlifespanshouldlistentoobjectswithalongerlifespan,and
handlecleaninguptheirowneventreferenceswhendeprecated.

Model&CollectionEvents
YoumaybindeventhandlersontoanyModelorCollection(oranyotherBackbonecomponentfor
thatmatter).Rememberthatyoucanpassinahandlercontexttodefinewhatthisreferences
whenthehandleriscalled:

kermit .on('change ',function (){


//dostuff...
},this)

CommonlytrackedModeleventsinclude:

"change" :triggeredwhenthevalueofanymodelattributechanges.

"change:<attribute>" :triggeredwhenthevalueofthenamedattributechanges.

sync:calledwhenthemodelcompletesadataexchangewiththeAPI.

CommonlytrackedCollectioneventsinclude:

"add":triggeredwhenamodelisaddedtothecollection.

"remove" :triggeredwhenamodelisremovedfromthecollection.

"reset" :triggeredwhenthecollectionispurgedwithahardreset.

"sync" :triggeredwhenthecollectioncompletesadataexchangewiththeAPI.

<modelevent> :theeventsofallmodelsareproxiedbytheirparentcollection.

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 6/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
ReviewBackbone'scatalogofbuiltineventsforallavailableeventtriggers.

UsingViews

AViewmanagesthevisuallayerplacedinfrontofamodelorcollection.

Creatingaview'scontainerelement
AllBackboneviewsareattachedtoacontainerelement,oranHTMLdocumentelementintowhich
allnesteddisplayandbehaviorisallocated.Acommonapproachistobindmajorviewsonto
predefinedelementswithintheHTMLDocumentObjectModel(henceforthreferredtoasthe
"DOM").Forexample:

<ulid="muppetslist "></ul>

<script >
varMuppetsListView =Backbone .View.extend ({
el:'#muppetslist '
})
</script >

Intheaboveexample,aBackboneviewclassisconfiguredtoreference"#muppetslist" asits
targetel,orelement.ThiselementreferenceisaselectorstringthatgetsresolvedintoaDOM
elementreference.

AnothercommonworkflowistohaveBackboneviewscreatetheirowncontainerelements.Todo
this,simplyprovideatagName andanoptionalclassName forthecreatedelement:

varMuppetsListItemView =Backbone .View.extend ({


tagName :'li',
className :'muppet '
})

Thesetwocontainerelementpatterns(selectingandcreating)arecommonlyusedtogether.For
example,acollectionmayattachitselftoaselectedDOMelement,andthencreateelementsfor
eachiteminthecollection.

Onceaviewclassisdefined,we'llnextneedtoinstanceit:

varMuppetsListView =Backbone .View.extend ({


el:'#muppetslist '
})

//Createanewviewinstance:
varmuppetsList =newMuppetsListView ()

//Appendcontentintotheview'scontainerelement:
muppetsList .$el.append ('<li>HelloWorld</li> ')

Whenaviewisinstanced,Backbonewillconfigurean$elpropertyforusthisisajQueryobject
wrappingtheview'sattachedcontainerelement.Thisreferenceprovidesaconvenientwaytowork
withthecontainerelementusingthejQueryAPI.

BackbonealsoencouragesefficientDOMpracticesusingjQuery.Ratherthanperforminglarge
andexpensiveoperationsacrosstheentireHTMLdocument,Backboneviewsprovidea$
methodthatperformsjQueryoperationslocallywithintheview'scontainerelement:

//Findall"li"tagslocallywithintheview'scontainer:
muppetsList .$('li')

Underthehood,usingview.$('...') issynonymouswithcallingview.$el.find('...') .
TheselocalizedqueriesgreatlycutdownonsuperfluousDOMoperations.

Attachingaview'sdatasource

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 7/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
Aviewisresponsibleforbindingitsdocumentelementtoamodeloracollectioninstance,
providedtotheviewasaconstructoroption.Forexample:

varmyModel =newMyModel ()
varmyView =newMyView ({model :myModel})

//Theprovidedmodelisattacheddirectlyontotheview:
console .log(myView .model===myModel) //<<true

Attachamodeltoaviewbyprovidinga{model:...} constructoroption:

varKermitModel =Backbone .Model.extend ({


url:'/muppets/1 ',
defaults :{...}
})

varMuppetsListItemView =Backbone .View.extend ({


tagName :'li',
className :'muppet ',

initialize :function (){


console .log(this.model)//<<KermitModel!!
}
})

//CreateModelandViewinstances:
varkermitModel =newKermitModel ()
varkermitView =newMuppetsListItemView ({model :kermitModel})

Attachacollectiontoaviewbyprovidinga{collection:...} constructoroption:

varMuppetsModel =Backbone .Model.extend ({...})

varMuppetsCollection =Backbone .Collection .extend ({


model :MuppetsModel,
url:'/muppets '
})

varMuppetsListView =Backbone .View.extend ({


el:'#muppetslist ',

initialize :function (){


console .log(this.collection )//<<MuppetsCollection!!
}
})

//CreateCollectionandViewinstances:
varmuppetsList =newMuppetsCollection ()
varmuppetsView =newMuppetsListView ({collection :muppetsList})

Intheaboveexamples,theprovideddatasourcesareattacheddirectlytotheirviewinstances,
thusallowingtheviewstoreferencethosesourcesasthis.model orthis.collection .Itwill
betheview'sjobtorenderitsdatasourceintoitsDOMelement,andpassuserinputdatafromthe
DOMbackintoitsdatasource.

Alsonote,theaboveexamplesleverageBackbone'sinitialize method.initialize iscalled


onceperobjectinstanceatthetimetheobjectiscreated,andisthereforeusefulforconfiguring
newobjects.AnyBackbonecomponentmaydefineaninitialize method.

RenderingaView
Amongtheprimaryresponsibilityofaviewistorenderdatafromitsdatasourceintoitsbound
DOMelement.Backboneisnotoriouslyunopinionatedaboutthistask(forbetterorworse),and
providesnofixturesfortranslatingadatasourceintodisplayreadyHTML.That'sforustodefine.

However,Backbonedoesprescribeaworkflowforwhereandwhenrenderingoccurs:

1.Aviewdefinesarender method.ThismethodgeneratesHTMLfromitsdatasource,and
installsthatmarkupintotheview'scontainerelement.

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 8/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
2.Aviewbindseventlistenerstoitsmodel.Anychangestothemodelshouldtriggertheviewto
rerender.

Asimpleimplementation:

<divid="kermitview "></div>

<script >
varKermitModel =Backbone .Model.extend ({
url:'/muppets/1 ',
defaults :{
name :'',
occupation :''
}
})

varKermitView =Backbone .View.extend ({


el:'#kermitview ',

initialize :function (){


this.listenTo (this.model,'syncchange ',this.render )
this.model.fetch()
this.render ()
},

render :function (){


varhtml ='<b>Name:</b> '+this.model.get('name')
html +=',occupation: '+this.model.get('occupation ')
this.$el.html(html)
return this
}
})

varkermit =newKermitModel ()
varkermitView =newKermitView ({model :kermit})
</script >

Intheaboveexample,asimplerendercycleisformed:

1.Theview'srender methodtranslatesitsboundmodelintodisplayreadyHTML.The
renderedHTMLisinsertedintotheview'scontainerelement.Arender methodnormally
returnsareferencetotheviewformethodchainingpurposes.
2.Theview'sinitialize methodbindseventlistenerstothemodelforsyncandchange
events.Eitherofthosemodeleventswilltriggertheviewtorerender.Theviewthenfetches
(loads)itsmodel,andrendersitsinitialappearance.

Atthecoreofthisworkflowiseventdrivenbehavior.ViewrenderingshouldNOTbeadirectresult
ofuserinteractionsorapplicationbehaviors.Manuallytimingrender callsispronetoerrorsand
inconsistencies.Instead,renderingshouldbeasimpleunionofdataanddisplay:whenthedata
changes,thedisplayupdates.

Renderingwithtemplates
Tosimplifytheprocessofrenderingmodeldataintodisplayreadymarkup,parsedHTML
templatesarecommonlyused.AnHTMLtemplatelooksgenerallylikethis:

<p><ahref="/muppets/<%=id%> "><%=name%></ a></p>


<p>Job:< i><%=occupation%></ i></p>

Lookfamiliar?TemplaterenderingonthefrontendisverysimilartoserversideHTMLrendering.
WejustneedaJavaScripttemplateutilitytoparsethesetemplatestrings.

TherearenumerousJavaScripttemplatelibrariesavailable.Infact,Underscorehasabuiltin
templaterenderer,thusmakingitomnipresentinallBackboneapps.Forthisprimer,we'llbeusing
theUnderscoretemplaterenderer.

Toimplementafrontendtemplate,wefirstneedtodefinetherawtextmarkup.Here'saquickand
easytrickforhidingrawtemplatetextwithinHTMLdocuments:includetherawtextina
<script> tagwithabogusscripttype.Forexample:

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 9/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub

<script type="text/template "id="muppetitemtmpl ">


<p><ahref="/muppets/<%=id%> "><%=name%></ a></p>
<p>Job:< i><%=occupation%></ i></p>
</script >

Theabove<script> tagdefinesabogustype="text/template" attribute.Thisisn'tavalid


scripttype,sothescripttag'scontentsareignoredbyHTMLparsers.Howeverwecanstill
accessthatignoredscripttagwithintheDOM,extractitsrawtextcontent,andparsethattextinto
atemplate.TocreateaJavaScripttemplate,wedothis:

vartmplText =$('#muppetitemtmpl ').html()


varmuppetTmpl =_.template (tmplText)

TheUnderscoretemplate methodparsesourrawtextintoareusabletemplatefunction.This
templatefunctionmaybecalledrepeatedlywithdifferentdatasources,andwillgenerateaparsed
HTMLstringforeachsource.Forexample,let'squicklyloadandrenderKermit:

varmuppetTmpl =_.template ($('#muppetitemtmpl ').html())


varkermit =newKermitModel ()

kermit .fetch().then(function (){


varhtml =muppetTmpl (kermit .toJSON ())
})

ResultingHTMLstring:

<p><ahref="/muppets/1 ">Kermit</ a></p>


<p>Job:< i>beinggreen</ i></p>

Intheaboveexample,aKermitModel iscreatedandfetched,andthenrenderedtoHTMLafter
itsdataisloaded.TogenerateHTMLmarkup,wesimplyinvokethetemplatefunctionandpassin
adatasource.TheprocessisprettystraightforwarduntilwegettothatmysterioustoJSON call.
What'sthat?

InordertorenderaBackboneModelusingagenerictemplate,wemustfirstserializethemodel
intoprimitivedata.BackboneprovidesatoJSON methodonModelsandCollectionsforprecisely
thisreasontoJSON willserializeaplainobjectrepresentationoftheseproprietarydata
structures.

Let'srevisetheearlierrenderingexampletoincludeaparsedtemplate:

<divid="kermitview "></div>

<script type="text/template "id="muppettmpl ">


<p><ahref="/muppets/<%=id%> "><%=name%></ a></p>
<p>Job:< i><%=occupation%></ i></p>
</script >

<script >
varKermitModel =Backbone .Model.extend ({
url:'/muppets/1 ',
defaults :{
name :'',
occupation :''
}
})

varKermitView =Backbone .View.extend ({


el:'#kermitview ',
template :_.template ($('#muppettmpl ').html()),

initialize :function (){


this.listenTo (this.model,'syncchange ',this.render )
this.model.fetch()
this.render ()
},

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 10/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
render :function (){
varhtml =this.template (this.model.toJSON ())
this.$el.html(html)
return this
}
})

varkermit =newKermitModel ()
varkermitView =newKermitView ({model :kermit})
</script >

Usingaparsedtemplategreatlysimplifiestherender method,especiallyasthesizeand
complexityoftherenderingincreases.Alsonotethatourtemplatefunctionisgeneratedonceand
cachedasamemberoftheviewclass.Generatingtemplatefunctionsisslow,thereforeit'sbestto
retainatemplatefunctionthatwillbeusedrepeatedly.

BindingDOMevents
Nextup,aviewmustcaptureuserinputeventswhetherthat'sanelementclick,textinput,or
changesinkeyboardfocus.BackboneViewsprovideaconvenientwayofdeclaringuserinterface
eventsusinganevents object.Theevents objectdefinesamappingofDOMeventtriggersto
handlermethodsontheview.

<divid="kermitview ">
<label>Name:< inputtype="text"name="name"class="name"></label>
<button class="save">Save</ button >
</div>

<script >
varKermitView =Backbone .View.extend ({
el:'#kermitview ',

events :{
'change.name ':'onChangeName ',
'click.save ':'onSave '
},

onChangeName :function (evt){


this.model.set('name',evt.currentTarget .value)
},

onSave :function (evt){


this.model.save()
}
})

varkermitView =newKermitView ({model :newKermitModel ()})


</script >

Tosummarizethestructureoftheaboveevents object:

Eventstriggersaredeclaredaskeysontheevents object,formattedas"[event_type]
[selector]" .

Eventhandlersaredeclaredasstringvaluesontheevents objecteachhandlernamecites
amethodavailableintheview.

Bemindfulthateventhandlermethodsshouldbekeptfairlysimple,andremainfocusedonhow
eachDOMeventtriggerrelatestoabehavioroftheunderlyingmodel.

ASimpleRESTApplication
Nowitstimetoputitalltogether.Let'sbreakdownacompleteRESTfulapplicationthatperformsall
CRUDmethodswithourAPI.

1.TheDOM

Thefirststepinsettingupanysmallapplicationistoestablishasimpleinterfaceformanagingthe
tasksyouintendtoperform.Here,we'veestablisha"muppetsapp" containerelementwithalist
(<ul>)fordisplayingallMuppetitems,andasimpleinputformfordefiningnewmuppets.

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 11/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
Downbelow,atemplateisdefinedforrenderingindividuallistitems.Notethatourlistitem
templateincludesa"remove"buttonforclearingtheitemfromthelist.

Finally,we'llincludeourapplication'sJavaScriptasanexternalscript.Wecanassumethatall
furtherexamplecodewillbeincludedinmuppetapp.js .

<divid="muppetsapp ">
<ulclass="muppetslist "></ul>

<divclass="muppetcreate ">
<b>AddaMuppet</ b>
<label>Name:< inputid="muppetname "type="text"></label>
<label>Job:< inputid="muppetjob "type="text"></label>
<button class="create ">CreateMuppet!</ button >
</div>
</div>

<script type="text/template "id="muppetitemtmpl ">


<p><ahref="/muppets/<%=id%> "><%=name%></ a></p>
<p>Job:< i><%=occupation%></ i></p>
<button class="remove ">x</button >
</script >

<script src="muppetapp.js "></script >

2.TheModelandCollection

Nowin"muppetapp.js" ,thefirststructureswe'lldefineistheModelclassforindividuallist
items,andtheCollectionclassformanagingalistofmodels.TheCollectionclassisconfigured
withtheURLofourAPIendpoint.

//ModelclassforeachMuppetitem
varMuppetModel =Backbone .Model.extend ({
defaults :{
id :null,
name :null,
occupation :null
}
})

//CollectionclassfortheMuppetslistendpoint
varMuppetCollection =Backbone .Collection .extend ({
model :MuppetModel,
url:'/muppets ',

parse:function (data){
return data.muppets
}
})

3.AListItemView

ThefirstViewclassthatwe'llwanttodefineisforindividuallistitems.Thisclasswillgenerateits
own<li>containerelement,andwillrenderitselfwithourlistitemtemplate.Thattemplate
functionisbeinggeneratedonce,andthenstoredasamemberoftheclass.Allinstancesofthis
classwillutilizethatoneparsedtemplatefunction.

Thisviewalsoconfiguresaneventformappingclicksonthe"remove"buttontoitsmodel's
destroy method(whichwillremovethemodelfromitsparentcollection,andthendispatcha
DELETE requestfromthemodeltotheAPI).

//Viewclassfordisplayingeachmuppetlistitem
varMuppetsListItemView =Backbone .View.extend ({
tagName :'li',
className :'muppet ',
template :_.template ($('#muppetitemtmpl ').html()),

initialize :function (){


this.listenTo (this.model,'destroy ',this.remove )
},

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 12/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub

render :function (){


varhtml =this.template (this.model.toJSON ())
this.$el.html(html)
return this
},

events :{
'click.remove ':'onRemove '
},

onRemove :function (){


this.model.destroy ()
}
})

4.AListView

Nowweneedaviewclassforrenderingoutlistsofitems,andcapturinginputfromthe"create"
form.

Thisviewbindsalistenertoitscollectionthatwilltriggertheviewtorenderwheneverthecollection
finishessyncingwiththeAPI.Thatwillforceourviewtorerenderwheninitialdataisloaded,or
whenitemsarecreatedordestroyed.

Thisviewrendersalistitemforeachmodelinitscollection.Itfirstfindsandemptiesitslist
container("ul.muppetslist" ),andthenloopsthroughitscollection,buildinganewlistitem
viewforeachmodelinthecollection.

Lastly,thisviewconfiguresaneventthatmapsclicksonthe"create"buttontocollectingform
input,andcreatinganewcollectionitembasedontheinputdata.

//Viewclassforrenderingthelistofallmuppets
varMuppetsListView =Backbone .View.extend ({
el:'#muppetsapp ',

initialize :function (){


this.listenTo (this.collection ,'sync',this.render )
},

render :function (){


var$list =this.$('ul.muppetslist ').empty()

this.collection .each(function (model){


varitem =newMuppetsListItemView ({model :model})
$list.append (item.render ().$el)
}, this)

return this
},

events :{
'click.create ':'onCreate '
},

onCreate :function (){


var$name =this.$('#muppetname ')
var$job =this.$('#muppetjob ')

if($name.val()){
this.collection .create ({
name :$name.val(),
occupation :$job.val()
})

$name.val('')
$job.val('')
}
}
})

5.Instantiation

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 13/14
12/27/2016 Backbone, The Primer jashkenas/backbone Wiki GitHub
Finally,weneedtobuildinstancesofourcomponents.We'llconstructacollectioninstancetoload
data,andthenconstructalistviewinstancetodisplayit.Whenourapplicationcomponentsareall
configured,allthat'slefttodoistellthecollectiontofetchfordata.

//Createanewlistcollection,alistview,andthenfetchlistdata:
varmuppetsList =newMuppetCollection ()
varmuppetsView =newMuppetsListView ({collection :muppetsList})
muppetsList .fetch()

GettingViewSupport
ViewmanagementisbyfartheleastregulatedcomponentofBackbone,andyetisironically
amongthemostdisciplinedrolesinfrontendengineering.WhileBackbone.View providessome
veryusefullowlevelutilityfeatures,itprovidesfewhighlevelworkflowfeatures.Asaresult,major
BackboneextensionsincludingMarionetteandLayoutManagerhavebecomepopular.Alsosee
ContainerViewforaminimalistextensionofcoreBackbone.Viewfeatures.

Thanksforreading.That'sBackboneinanutshell.

2016GitHub,Inc. Terms Privacy Security Status Help ContactGitHub API Training Shop Blog About

https://github.com/jashkenas/backbone/wiki/Backbone%2C-The-Primer#a-simple-rest-application 14/14

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