Table of Contents - itjumpstart.files.wordpress.com · "rollup-plugin-node-resolve"...
Transcript of Table of Contents - itjumpstart.files.wordpress.com · "rollup-plugin-node-resolve"...
TableofContentsPreface
IntroductiontoSvelte
SvelteComponents
HandlingStateinSvelte
SvelteReactivity
SvelteProps
Cross-componentStateManagementinSvelte
Slots
SvelteLifecycleevents
SvelteBindings
ConditionalLogicinTemplates
LoopinginSvelteTemplates
PromisesinSvelteTemplates
WorkingwithEventsinSvelte
WhereDoWeGoFromHere
2
Preface
Welcome!IwrotethisbooktohelpyouquicklylearnSvelteandgetfamiliarwithhowitworks.
TheidealreaderofthebookhaszeroknowledgeofSvelte,hasmaybeusedVueorReact,butislookingforsomethingmore,oranewapproachtothings.
IfindSvelteisverywellworthlookinginto,becauseitprovidesarefreshingpointofviewandseveraluniquefeaturestotheWeb.
Thankyouforgettingthisebook.IhopeitwillhelpyoulearnmoreaboutSvelte!
Flavio
[email protected],onTwitter@flaviocopes.
Mywebsiteisflaviocopes.com.
Preface
3
IntroductiontoSvelteSvelteisanexcitingWebframeworkthatoffersafreshnewtakeonhowtobuildWebapplications.
IfyouarealreadyexperiencedinReact,Vue,AngularorotherfrontendframeworksyoumightbepleasantlysurprisedbySvelte.
MyfirstimpressionwithSveltewasthatitallfeelssomuchmorelikeplainJavaScriptthanworkingwithotherframeworks.Sure,youhavesomerulesandtherearetemplatesthatarenot100%JavaScript(theylookmorelikeHTML)butmostofthethingsthatarecomplicatedwithotherframeworksareverysimpleandlightweightwithSvelte.
Andmyfirstimpressionhasbeenconfirmedbyfurtherusageoftheframeworkanditsecosystemoftools.
ComparedtoReact,Vue,Angularandotherframeworks,anappbuiltusingSvelteiscompiledbeforehandsoyoudon'thavetoservethewholeframeworktoeveryoneofyoursitevisitors.Asaresult,thefruitionoftheexperienceissmoother,consumeslessbandwidth,andeverythingfeelsfasterandmorelightweight.
Atdeployment,Sveltedisappearsandallyougetisplain(andfast!)JavaScript.
HowtogetstartedwithSvelteTouseSvelte,youneedtohaveNode.jsinstalledbecauseallthetoolingwe'regoingtouseisbasedonNode.CheckoutmytutorialhowtoinstallNode.jspostifyoudon'thaveitalready!
Andmakesureit'sthelatestversion(howtoupdateNode.js).
Ifyoudon'twanttoinstallNode,theSveltewebsiteprovidesaverycoolREPL(Read-Eval-PrintLoop)athttps://svelte.dev/repl.It'shandytotestsmallSvelteappsandtoexperimentwiththings.
Nodeinstallsthe npxcommand,whichisahandywaytorunNodecommands.Inparticular,we'regoingtorunthis:
npxdegitsveltejs/templatefirstapp
Thiswilldownloadandrunthedegitcommand,whichinturndownloadsthelatestcodeoftheSvelteprojecttemplatelivingathttps://github.com/sveltejs/template,intoanewlycreatedfirstappfolder.MakesurethatgitisinstalledonyourmachineandaddedtothePATH
IntroductiontoSvelte
4
variable,otherwisethedegitcommandwon'twork.Incasethingsarestillnotworkingoutforyou,youcanalternatively'Cloneordownload'thetemplateprojectandthendeletethehidden.gitfolder,whichisbasicallythesamethingthatthe degitcommanddoes(onlydifferenceisthatthefolderiscalled templateinsteadof firstapp).
Nowgointothat firstappfolderandrun npminstalltodownloadtheadditionaldependenciesofthetemplate.Atthetimeofwriting,thesearethedependenciesofthatprojecttemplate:
"npm-run-all"
"rollup"
"rollup-plugin-commonjs"
"rollup-plugin-livereload"
"rollup-plugin-node-resolve"
"rollup-plugin-svelte"
"rollup-plugin-terser"
"svelte"
Asyoucansee,it'stheSveltecore,plusRollup(aWebpackalternative)andsomeofitsplugins.Plus npm-run-all,aCLItoolthatisusedtorunmultiplenpmscriptsinparallelorsequential.
We'renowreadytorunourSveltesiteindevelopmentmode,byrunning
npmrundev
Thiswillstarttheapponlocalhost,onport5000,bydefault:
IntroductiontoSvelte
5
Ifyoupointyourbrowserthere,you'llseethe"Helloworld!"example:
You'renowreadytoopenthecodeinyourfavoriteeditor.The srcfoldercontainsallyouneedtotweaktheapp:the main.jsfile:
IntroductiontoSvelte
6
ThisfileistheentrypointandinthiscaseinitializestheAppcomponent,whichisdefinedinApp.svelte,asinglefilecomponent:
<script>
exportletname;
</script>
<style>
h1{
color:purple;
}
</style>
<h1>Hello{name}!</h1>
IntroductiontoSvelte
7
SvelteComponentsModernWebdevelopmentisverymuchfocusedoncomponents,andSvelteisnodifferent.
Whatisacomponent?Acomponentisanatomicpartoftheapplicationthatisself-containedandoptionallyreferencesothercomponentstocomposeitsoutput.
Inotherwords,it'sacompartmentalizedpartoftheapplication.Aformcanbeacomponent.Aninputelementcanbeacomponent.Thewholeapplicationisacomponent.
Sveltecomponentscontainallthat'sneededtorenderapieceoftheUI.EverySveltecomponentisdeclaredina .sveltefile,andinthereyou'llfindthecontent(markup),thebehavior(JavaScript),andthepresentation(CSS)withouthavingtodefineseparatefiles.
WhichisasanewaytodefineapieceoftheUIbecauseyoudon'tneedtosearchfortheitemsthataffectthesameelementacrossvariousfiles.
Here'sasamplecomponent,whichwe'llstoreinafilecalled Dog.svelte:
<script>
exportletname;
</script>
<style>
h1{
color:purple;
}
</style>
<h1>Thedognameis{name}!</h1>
AnyJavaScriptmustbeputinthe scripttag.
TheCSSyouhaveinthe styletagisscopedtothecomponentanddoesnot"leak"outside.Ifanothercomponenthasan h1tag,thisstylewillnotaffectthat.Thisisveryhandywhenreusingcomponentsyoualreadywroteforotherapplications,forexample,orwhenyouincludeOpenSourcelibrariespublishedbyotherpeople.
Forexample,afewweeksagoIincludedadatepickercomponentbuiltwithSvelteinanapplicationandnoneofthestylingsofthecomponentleakedoutsideofit,andnoneoftheCSSIwroteintotheappmodifiedthelookofthedatepicker.
ImportingthecomponentinothercomponentsAcomponentcan,assaid,beusedbyothercomponents.
SvelteComponents
8
Othercomponentscannowimportthe Dogcomponentintheircode.
Forexamplehere'sa Housecomponent,definedina House.sveltefile,inthesamefolderofDog.svelte:
<script>
importDogfrom'./Dog.svelte'
</script>
YoucannowusetheDogcomponentlikeanHTMLtag:
<script>
importDogfrom'./Dog.svelte'
</script>
<Dog/>
ExportingspecificfunctionsfromacomponentAsyousawabove,toexportthecomponentwedidn'thavetodoanything,becausethecomponentitselfisthedefaultexport.
Whatifyouwanttoexportsomethingotherthanthecomponentmarkupanditsassociatedandbuilt-infunctionality?
Youmustwriteallthefunctionsyouwanttoexportfromaspecial scripttagwiththecontext="module"attribute.
Here'sanexample.SayyouhaveaButtoncomponentin Button.svelte:
<button>Abutton</button>
andyouwanttoprovideothercomponentstheabilitytochangethecolorofthebutton.
Abettersolutionforthisusecaseistouseprops,whichissomethingwe'lltalkaboutinthenextchapter.Butstickwithmeforthisexample
Youcanprovideafunction,called changeColor.
Youwriteandexportitinthisspecial scripttag:
<scriptcontext="module">
exportfunctionchangeColor(){
//...logictochangecolor..
}
</script>
SvelteComponents
9
<button>Abutton</button>
Notethatyoucanhaveanother"normal"scripttag,inthecomponent.
NowothercomponentscanimportButton,whichisthedefaultexport,andthe changeColorfunctiontoo:
<script>
importButton,{changeColor}from'./Button.svelte'
</script>
Nowthatisprobablyasillyexample,butknowingyouhavethisfunctionalityatyourdisposalcanbequitehelpful.
SvelteComponents
10
HandlingStateinSvelteEverycomponent,inadditiontodefiningthemarkup,theCSSandtheJavaScriptlogic,canhostitsownstate.
Whatisstate?Stateisanydatathat'sneededtomakethecomponentrenderwhatit'srendering.
Forexample,ifaforminputfieldhasthestring"test"writtenintoit,there'llbeavariablesomewhereholdingthisvalue.That'sthestateoftheinputfield.
Thefieldisselected?Avariablesomewherewillregisterthisfact.Andsoon.
Stateishostedinthe scriptpartofacomponent:
<script>
letcount=0
</script>
Now,ifyoucomefromotherframeworksinthefrontendspacelikeVueorReact,youmightthink"howdoIupdatethisvalue?"-andforagoodreason,asthoseframeworksmakethisoperationratherunintuitive,I'dsay.
OnegreatthingaboutSvelteisthatyoudon'tneedtodoanythingspecialtoupdatethestateofacomponent.
Allyouneedisanassignment.AsimpleJavaScriptassignment,usingthe =operatorforexample.
Sayyouhavea countvariable.Youcanincrementthatusing,simply, count=count+1,orcount++:
<script>
letcount=0
constincrementCount=()=>{
count++
}
</script>
{count}<buttonon:click={incrementCount}>+1</button>
ThisisnothinggroundbreakingifyouareunfamiliarwithhowmodernWebframeworkshandlestate,butinReactyou'dhavetoeithercall this.setState(),orusethe useState()hook.
Vuetakesamorestructuredapproachusingclassesandthe dataproperty.
HandlingStateinSvelte
11
Havingusedboth,IfindSveltetobeamuchmoreJavaScript-likesyntax.
Weneedtobeawareofonething,whichislearnedprettyquickly:wemustalsomakeanassignmentwhenchangingthevalue.
Sveltealwayswantsanassignment,otherwiseitmightnotrecognizethatthestatechanged.
Forsimplevalueslikestringsandnumbers,that'smostlyagiven,becauseallmethodsonStringreturnnewstrings,andsamefornumbers-theyareimmutable.
Butforarrays?Wecan'tusemethodsthatalterthearray.Like push(), pop(), shift(),splice()...becausethere'snoassignment.Theychangetheinnerdatastructure,butSveltecan'tdetectthat.
Well,youcanstillusethem,butafteryou'vedoneyouroperation,youreassignthevariabletoitself,likethis:
letlist=[1,2,3]
list.push(4)
list=list
Whichisabitcounter-intuitive,butyou'llquicklyrememberit.
Oryoucanuseusethespreadoperatortoperformoperations:
letlist=[1,2,3]
list=[...list,4]
HandlingStateinSvelte
12
SvelteReactivityInSvelteyoucanlistenforchangesinthecomponentstate,andupdateothervariables.
Forexampleifyouhavea countvariable:
<script>
letcount=0
</script>
andyouupdateitbyclickingabutton:
<script>
letcount=0
constincrementCount=()=>{
count=count+1
}
</script>
{count}<buttonon:click={incrementCount}>+1</button>
Youcanlistenforchangeson countusingthespecialsyntax $:whichdefinesanewblockthatSveltewillre-runwhenanyvariablereferencedintoitchanges.
Here'sanexample:
<script>
letcount=0
constincrementCount=()=>{
count=count+1
}
$:console.log(`${count}`)
</script>
{count}<buttonon:click={incrementCount}>+1</button>
Iusedtheblock:
$:console.log(`${count}`)
Youcanwritemorethanoneofthem:
<script>
SvelteReactivity
13
$:console.log(`thecountis${count}`)
$:console.log(`doublethecountis${count*2}`)
</script>
Andyoucanalsoaddablocktogroupmorethanonestatement:
<script>
$:{
console.log(`thecountis${count}`)
console.log(`doublethecountis${count*2}`)
}
</script>
Iusedaconsole.log()callinthere,butyoucanupdateothervariablestoo:
<script>
letcount=0
letdouble=0
$:{
console.log(`thecountis${count}`)
double=count*2
console.log(`doublethecountis${double}`)
}
</script>
SvelteReactivity
14
SveltePropsYoucanimportaSveltecomponentintoanyothercomponentusingthesyntax importComponentNamefrom'componentPath':
<script>
importSignupFormfrom'./SignupForm.svelte';
</script>
Thepathisrelativetothecurrentcomponentpath. ./means"thissamefolder".You'duse ../togobackonefolder,andsoon.
Onceyoudoso,youcanusethenewlyimportedcomponentinthemarkup,likeanHTMLtag:
<SignupForm/>
Inthisway,youareformingaparent/childrelationshipbetweenthetwocomponents:theonethatimports,andtheonethatisimported.
Oftenyouwanttohavetheparentcomponentpassdatatothechildcomponent.
Youcandosousingprops.PropsbehavesimilarlytoattributesinplainHTML,andtheyareaone-wayformofcommunication.
Inthisexamplewepassthe disabledprop,passingtheJavaScriptvalue truetoit:
<SignupFormdisabled={true}/>
IntheSignupFormcomponent,youneedtoexportthe disabledprop,inthisway:
<script>
exportletdisabled
</script>
Thisisthewayyouexpressthefactthatthepropisexposedtoparentcomponents.
Whenusingthecomponent,youcanpassavariableinsteadofavalue,tochangeitdynamically:
<script>
importSignupFormfrom'./SignupForm.svelte';
letdisabled=true
</script>
SvelteProps
15
<SignupFormdisabled={disabled}/>
Whenthe disabledvariablevaluechanges,thechildcomponentwillbeupdatedwiththenewpropvalue.Example:
<script>
importSignupFormfrom'./SignupForm.svelte';
letdisabled=true
setTimeout(()=>{disabled=false},2000)
</script>
<SignupFormdisabled={disabled}/>
SvelteProps
16
Cross-componentStateManagementinSvelteWe'vealreadyseenhowSveltemakeshandlingthestateofasinglecomponentveryeasy.
Buthowdowepassstatearoundacrosscomponents?
PassingstatearoundusingpropsThefirststrategyiscommontootherUIframeworksandit'spassingstatearoundusingprops,liftingthestateup.
Whenacomponentneedstosharedatawithanother,thestatecanbemovedupinthecomponentstreeuntilthere'sacommonparenttothosecomponents.
Thestateneedstobepasseddownuntilitreachesallthecomponentsthatneedthisstateinformation.
Thisisdoneusingprops,andit'satechniquethatIthinkisthebestasit'ssimple.
ThecontextAPIHowever,therearecaseswherepropsarenotpractical.Perhaps2componentsaresodistantinthecomponentstreethatwe'dhavetomovestateuptothetop-levelcomponent.
Inthiscase,anothertechniquecanbeusedandit'scalledcontextAPI,andit'sidealwhenyouwanttoletmultiplecomponentscommunicatewithdescendants,butyoudon'twanttopasspropsaround.
ThecontextAPIisprovidedby2functionswhichareprovidedbythe sveltepackage:getContextand setContext.
Yousetanobjectinthecontext,associatingittoakey:
<script>
import{setContext}from'svelte'
constsomeObject={}
setContext('someKey',someObject)
</script>
Cross-componentStateManagementinSvelte
17
Inanothercomponentyoucanuse getContexttoretrievetheobjectassignedtoakey:
<script>
import{getContext}from'svelte'
constsomeObject=getContext('someKey')
</script>
Youcanonlyuse getContexttoretrieveakeyeitherinthecomponentthatused setContextorinoneofitsdescendants.
Ifyouwanttolettwocomponentslivingin2differentcomponenttreescommunicatethere'sanothertoolforus:stores.
UsingSveltestoresSveltestoresareagreattooltohandleyourappstatewhencomponentsneedtotalktoeachotherwithoutpassingpropsaroundtoomuch.
Youmustfirstimport writablefrom svelte/store:
import{writable}from'svelte/store'
andcreateastorevariableusingthe writable()function,passingthedefaultvalueasthefirstargument:
constusername=writable('Guest')
Thiscanbeputintoaseparatefilewhichyoucanimportintomultiplecomponents,forexample,called store.js(it'snotacomponent,soitcanbeina .jsfileinsteadof.svelte):
import{writable}from'svelte/store'
exportconstusername=writable('Guest')
Anyothercomponentnowloadingthisfilecanaccessthestore:
<script>
import{username}from'./store.js'
</script>
Cross-componentStateManagementinSvelte
18
Nowthevalueofthisvariablecanbesettoanewvalueusing set(),passingthenewvalueasthefirstargument:
username.set('newusername')
Anditcanbeupdatedusingthe update()function,whichdiffersfrom set()becauseyoudon'tjustpassthenewvaluetoit-yourunacallbackfunctionthatispassedthecurrentvalueasitsargument:
constnewUsername='newusername!'
username.update(existing=>newUsername)
Youcanaddmorelogichere:
username.update(existing=>{
console.log(`Updatingusernamefrom${existing}to${newUsername}`)
returnnewUsername
})
Togetthevalueofthestorevariableonce,youcanusethe get()functionexportedbysvelte/store:
import{writable,get}from'svelte/store'
exportconstusername=writable('Guest')
get(username)//'Guest'
Tocreateareactivevariablethat'supdatedwheneverthestorevaluechangesinstead,youcanprependthestorevariableusing $(inthisexample $username).Usingthatwillmakethecomponentre-renderwheneverthestoredvaluechanges.
Svelteconsiders $tobeareservedvalueandwillpreventyoutouseitforthingsthatarenotrelatedtostoresvalues(whichmightleadtoconfusion),soifyouareusedtoprependingDOMreferencesusing $,don'tdoitinSvelte.
Anotheroption,bestsuitedifyouneedtoexecutesomelogicwhenthevariablechanges,istousethe subscribe()methodof username:
username.subscribe(newValue=>{
console.log(newValue)
})
Inadditiontowritablestores,Svelteprovides2specialkindsofstores:readablestoresandderivedstores.
Cross-componentStateManagementinSvelte
19
SvelteReadableStores
Readablestoresarespecialbecausetheycan'tbeupdatedfromtheoutside-there'snoset()or update()method.Instead,onceyousettheinitialstate,theycan'tbemodifiedfromtheoutside.
TheofficialSveltedocsshowaninterestingexampleusingatimertoupdateadate.Icanthinkofsettingupatimertofetcharesourcefromthenetwork,performanAPIcall,getdatafromthefilesystem(usingalocalNode.jsserver)oranythingelsethatcanbesetupautonomously.
Inthiscaseinsteadofusing writable()toinitializethestorevariable,weuse readable():
import{readable}from'svelte/store'
exportconstcount=readable(0)
Youcanprovideafunctionafterthedefaultvalue,thatwillberesponsibleforupdatingit.Thisfunctionreceivesthe setfunctiontomodifythevalue:
<script>
import{readable}from'svelte/store'
exportconstcount=readable(0,set=>{
setTimeout(()=>{
set(1)
},1000)
})
</script>
Inthiscase,weupdatethevaluefrom0to1after1second.
Youcansetupanintervalinthisfunction,too:
import{readable,get}from'svelte/store'
exportconstcount=readable(0,set=>{
setInterval(()=>{
set(get(count)+1)
},1000)
})
Youcanusethisinanothercomponentlikethis:
<script>
import{count}from'./store.js'
</script>
{$count}
Cross-componentStateManagementinSvelte
20
SvelteDerivedStores
Aderivedstoreallowsyoutocreateanewstorevaluethatdependsonthevalueofanexistingstore.
Youcandosousingthe derived()functionexportedby svelte/storewhichtakesasitsfirstparametertheexistingstorevalue,andasasecondparameterafunctionwhichreceivesthatstorevalueasitsfirstparameter:
import{writable,derived}from'svelte/store'
exportconstusername=writable('Guest')
exportconstwelcomeMessage=derived(username,$username=>{
return`Welcome${$username}`
})
<script>
import{username,welcomeMessage}from'./store.js'
</script>
{$username}
{$welcomeMessage}
Cross-componentStateManagementinSvelte
21
SlotsSlotsareahandywaytoletyoudefinecomponentsthatcanbecomposedtogether.
Andviceversa,dependingonyourpointofview,slotsareahandywaytoconfigureacomponentyouareimporting.
Here'showtheywork.
Inacomponentyoucandefineaslotusingthe <slot/>(or <slot></slot>)syntax.
Here'sa Button.sveltecomponentthatsimplyprintsa <button>HTMLtag:
<button><slot/></button>
ForReactdevelopers,thisisbasicallythesameas <button>{props.children}</button>
Anycomponentimportingitcandefinecontentthatisgoingtobeputintotheslotbyaddingitintothecomponent'sopeningandclosingtags:
<script>
importButtonfrom'./Button.svelte'
</script>
<Button>Insertthisintotheslot</Button>
Youcandefineadefault,whichisusediftheslotisnotfilled:
<button>
<slot>
Defaulttextforthebutton
</slot>
</button>
Youcanhavemorethanoneslotinacomponent,andyoucandistinguishonefromtheotherusingnamedslots.Thesingleunnamedslotwillbethedefaultone:
<slotname="before"/>
<button>
<slot/>
</button>
<slotname="after"/>
Here'showyouwoulduseit:
Slots
22
<script>
importButtonfrom'./Button.svelte'
</script>
<Button>
Insertthisintotheslot
<pslot="before">Addthisbefore</p>
<pslot="after">Addthisafter</p>
</Button>
AndthiswouldrenderthefollowingtotheDOM:
<pslot="before">Addthisbefore</p>
<button>
Insertthisintotheslot
</button>
<pslot="after">Addthisafter</p>
Slots
23
SvelteLifecycleeventsEverycomponentinSveltefiresseverallifecycleeventsthatwecanhookon,tohelpusimplementthefunctionalitywehaveinmind.
Inparticular,wehave
onMountfiredafterthecomponentisrenderedonDestroyfiredafterthecomponentisdestroyedbeforeUpdatefiredbeforetheDOMisupdatedafterUpdatefiredaftertheDOMisupdated
WecanschedulefunctionstohappenwhentheseeventsarefiredbySvelte.
Wedon'thaveaccesstoanyofthosemethodsbydefault,butweneedtoimportthemfromthe sveltepackage:
<script>
import{onMount,onDestroy,beforeUpdate,afterUpdate}from'svelte'
</script>
Acommonscenariofor onMountistofetchdatafromothersources.
Here'sasampleusageof onMount:
<script>
import{onMount}from'svelte'
onMount(async()=>{
//dosomethingonmount
})
</script>
onDestroyallowsustocleanupdataorstopanyoperationwemighthavestartedatthecomponentinitialization,liketimersorscheduledperiodicfunctionsusing setInterval.
Oneparticularthingtonoticeisthatifwereturnafunctionfrom onMount,thatservesthesamefunctionalityof onDestroy-it'srunwhenthecomponentisdestroyed:
<script>
import{onMount}from'svelte'
onMount(async()=>{
//dosomethingonmount
return()=>{
SvelteLifecycleevents
24
//dosomethingondestroy
}
})
</script>
Here'sapracticalexamplethatsetsaperiodicfunctiontorunonmount,andremovesitondestroy:
<script>
import{onMount}from'svelte'
onMount(async()=>{
constinterval=setInterval(()=>{
console.log('hey,justchecking!')
},1000)
return()=>{
clearInterval(interval)
}
})
</script>
SvelteLifecycleevents
25
SvelteBindingsUsingSvelteyoucancreateatwo-waybindingbetweendataandtheUI.
ManyotherWebframeworkscanprovidetwo-waybindings,it'saverycommonpattern.
Theyareespeciallyusefulwithforms.
bind:valueLet'sstartwiththemostcommonformofbindingyou'lloftenuse,whichyoucanapplyusingbind:value.Youtakeavariablefromthecomponentstate,andyoubindittoaformfield:
<script>
letname=''
</script>
<inputbind:value={name}>
Nowif namechangestheinputfieldwillupdateitsvalue.Andtheoppositeistrue,aswell:iftheformisupdatedbytheuser,the namevariablevaluechanges.
Justbeawarethatthevariablemustbedefinedusing let/varandnot const,otherwiseitcan'tbeupdatedbySvelte,as constdefinesavariablewithavaluethatcan'tbereassigned.
bind:valueworksonallflavorsofinputfields( type="number", type="email"andsoon),butitalsoworksforotherkindoffields,like textareaand select(moreon selectlater).
CheckboxesandradiobuttonsCheckboxesandradioinputs( inputelementswith type="checkbox"or type="radio")allowthose3bindings:
bind:checked
bind:group
bind:indeterminate
bind:checkedallowsustobindavaluetothecheckedstateoftheelement:
<script>
letisChecked
</script>
SvelteBindings
26
<inputtype=checkboxbind:checked={isChecked}>
bind:groupishandywithcheckboxesandradioinputs,becausethoseareveryoftenusedingroups.Using bind:groupyoucanassociateaJavaScriptarraytoalistofcheckboxes,andhaveitpopulatedbasedonthechoicesmadebytheuser.
Here'sanexample.The goodDogsarraypopulatesbasedonthecheckboxesItick:
<script>
letgoodDogs=[]
letdogs=['Roger','Syd']
</script>
<h2>
Who'sagooddog?
</h2>
<ul>
{#eachdogsasdog}
<li>{dog}<inputtype=checkboxbind:group={goodDogs}value={dog}></li>
{/each}
</ul>
<h2>
Gooddogsaccordingtome:
</h2>
<ul>
{#eachgoodDogsasdog}
<li>{dog}</li>
{/each}
</ul>
Seetheexampleonhttps://svelte.dev/repl/059c1b5edffc4b058ad36301dd7a1a58
bind:indeterminateallowsustobindtothe indeterminatestateofanelement(ifyouwanttolearnmoreheadtohttps://css-tricks.com/indeterminate-checkboxes/)
Selectfieldsbind:valuealsoworksforthe selectformfieldtogettheselectedvalueautomaticallyassignedtothevalueofavariable:
<script>
letselected
</script>
<selectbind:value={selected}>
SvelteBindings
27
<optionvalue="1">1</option>
<optionvalue="2">2</option>
<optionvalue="3">3</option>
</select>
{selected}
Thecoolthingisthatifyougenerateoptionsdynamicallyfromanarrayofobjects,theselectedoptionisnowanobject,notastring:
<script>
letselected
constgoodDogs=[
{name:'Roger'},
{name:'Syd'}
]
</script>
<h2>Listofpossiblegooddogs:</h2>
<selectbind:value={selected}>
{#eachgoodDogsasgoodDog}
<optionvalue={goodDog}>{goodDog.name}</option>
{/each}
</select>
{#ifselected}
<h2>
Gooddogselected:{selected.name}
</h2>
{/if}
Seeexample:https://svelte.dev/repl/7e06f9b7becd4c57880db5ed184ea0f3
selectalsoallowsthe multipleattribute:
<script>
letselected=[]
constgoodDogs=[
{name:'Roger'},
{name:'Syd'}
]
</script>
<h2>Listofpossiblegooddogs:</h2>
<selectmultiplebind:value={selected}>
{#eachgoodDogsasgoodDog}
<optionvalue={goodDog}>{goodDog.name}</option>
{/each}
</select>
{#ifselected.length}
SvelteBindings
28
<h2>Gooddogselected:</h2>
<ul>
{#eachselectedasdog}
<li>{dog.name}</li>
{/each}
</ul>
{/if}
Seeexample:https://svelte.dev/repl/b003248e87f04919a2f9fed63dbdab8c
OtherbindingsDependingontheHTMLtagyouareworkingon,youcanapplydifferentkindsofbindings.
bind:filesisabindingvalidon type="file"inputelements,tobindthelistofselectedfiles.
The detailsHTMLelementallowstheuseof bind:opentobinditsopen/closevalue.
The audioand videomediaHTMLtagsallowtobindseveraloftheirproperties:currentTime, duration, paused, buffered, seekable, played, volume, playbackRate.
textContentand innerHTMLcanbeboundon contenteditablefields.
AllthingsveryusefulforthosespecificHTMLelements.
Read-onlybindingsoffsetWidth, offsetHeight, clientWidth, clientHeightcanbebound,readonly,onanyblocklevelHTMLelement,excludingvoidtags(like br)andelementsthataresettobeinline( display:inline).
GetareferencetotheHTMLelementinJavaScriptbind:thisisaspecialkindofbindingthatallowsyoutogetareferencetoanHTMLelementandbindittoaJavaScriptvariable:
<script>
letmyInputField
</script>
<inputbind:this={myInputField}/>
SvelteBindings
29
Thisishandywhenyouneedtoapplylogictoelementsafteryoumountthem,forexample,usingthe onMount()lifecycleeventcallback.
BindingcomponentspropsUsing bind:youcanbindavaluetoanypropthatacomponentexposes.
Sayyouhavea Car.sveltecomponent:
<script>
exportletinMovement=false
</script>
<buttonon:click={()=>inMovement=true}>Startcar</button>
Youcanimportthecomponentandbindthe inMovementprop:
<script>
importCarfrom'./Car.svelte';
letcarInMovement;
</script>
<Carbind:inMovement={carInMovement}/>
{carInMovement}
Thiscanallowforinterestingscenarios.
SvelteBindings
30
ConditionalLogicinTemplatesInaSveltecomponent,whenitcomestorenderingHTMLyoucanworkwithsomespecificsyntaxtocrafttheUIyouneedateverystageoftheapplicationlifecycle.
Inparticular,we'llnowexploreconditionalstructures.
Theproblemisthis:youwanttobeabletolookatavalue/expression,andifthatpointstoatruevaluedosomethingifthatpointstoafalsevaluethendosomethingelse.
Svelteprovidesusaverypowerfulsetofcontrolstructures.
Thefirstisif:
{#ifisRed}
<p>Red</p>
{/if}
Thereisanopening {#if}andanending {/if}.Theopeningmarkupchecksforavalueorstatementtobetruthy.Inthiscase isRedcanbeabooleanwitha truevalue:
<script>
letisRed=true
</script>
Anemptystringisfalsy,butastringwithsomecontentistruthy.
0isfalsy,butanumber>0istruthy.
Thebooleanvalue trueistruthy,ofcourse,and falseisfalsy.
Iftheopeningmarkupisnotsatisfied(afalsyvalueisprovided),thennothinghappens.
Todosomethingelseifthat'snotsatisfied,weusetheappropriatelycalled elsestatement:
{#ifisRed}
<p>Red</p>
{:else}
<p>Notred</p>
{/if}
Eitherthefirstblockisrenderedinthetemplateorthesecondone.There'snootheroption.
YoucanuseanyJavaScriptexpressionintothe ifblockcondition,soyoucannegateanoptionusingthe !operator:
ConditionalLogicinTemplates
31
{#if!isRed}
<p>Notred</p>
{:else}
<p>Red</p>
{/if}
Now,insidethe elseyoumightwanttocheckforanadditionalcondition.That'swherethe{:elseifsomethingElse}syntaxcomesalong:
{#ifisRed}
<p>Red</p>
{:elseifisGreen}
<p>Green</p>
{:else}
<p>Notrednorgreen</p>
{/if}
Youcanhavemanyoftheseblocks,notjustone,andyoucannestthem.Here'samorecomplexexample:
{#ifisRed}
<p>Red</p>
{:elseifisGreen}
<p>Green</p>
{:elseifisBlue}
<p>Itisblue</p>
{:else}
{#ifisDog}
<p>Itisadog</p>
{/if}
{/if}
ConditionalLogicinTemplates
32
LoopinginSvelteTemplatesInSveltetemplatesyoucancreatealoopusingthe {#each}{/each}syntax:
<script>
letgoodDogs=['Roger','Syd']
</script>
{#eachgoodDogsasgoodDog}
<li>{goodDog}</li>
{/each}
Ifyouarefamiliarwithotherframeworksthatusetemplates,it'saverysimilarsyntax.
Youcangettheindexoftheiterationusing:
<script>
letgoodDogs=['Roger','Syd']
</script>
{#eachgoodDogsasgoodDog,index}
<li>{index}:{goodDog}</li>
{/each}
(indexesstartat0)
Whendynamicallyeditingthelistsremovingandaddingelements,youshouldalwayspassanidentifierinlists,topreventissues.
Youdosousingthissyntax:
<script>
letgoodDogs=['Roger','Syd']
</script>
{#eachgoodDogsasgoodDog(goodDog)}
<li>{goodDog}</li>
{/each}
<!--withtheindex-->
{#eachgoodDogsasgoodDog,index(goodDog)}
<li>{goodDog}</li>
{/each}
Youcanpassanobject,too,butifyourlisthasauniqueidentifierforeachelement,it'sbesttouseit:
LoopinginSvelteTemplates
33
<script>
letgoodDogs=[
{id:1,name:'Roger'},
{id:2,name:'Syd'}
]
</script>
{#eachgoodDogsasgoodDog(goodDog.id)}
<li>{goodDog.name}</li>
{/each}
<!--withtheindex-->
{#eachgoodDogsasgoodDog,index(goodDog.id)}
<li>{goodDog.name}</li>
{/each}
LoopinginSvelteTemplates
34
PromisesinSvelteTemplatesPromisesareanawesometoolwehaveatourdisposaltoworkwithasynchronouseventsinJavaScript.
Therelativelyrecentintroductionofthe awaitsyntaxinES2017madeusingpromisesevensimpler.
Svelteprovidesusthe {#await}syntaxintemplatestodirectlyworkwithpromisesatthetemplatelevel.
Wecanwaitforpromisestoresolve,anddefineadifferentUIforthevariousstatesofapromise:unresolved,resolvedandrejected.
Here'showitworks.Wedefineapromise,andusingthe {#await}blockwewaitforittoresolve.
Oncethepromiseresolves,theresultispassedtothe {:then}block:
<script>
constfetchImage=(async()=>{
constresponse=awaitfetch('https://dog.ceo/api/breeds/image/random')
returnawaitresponse.json()
})()
</script>
{#awaitfetchImage}
<p>...waiting</p>
{:thendata}
<imgsrc={data.message}alt="Dogimage"/>
{/await}
Youcandetectapromiserejectionbyaddinga {:catch}block:
{#awaitfetchImage}
<p>...waiting</p>
{:thendata}
<imgsrc={data.message}alt="Dogimage"/>
{:catcherror}
<p>Anerroroccurred!</p>
{/await}
Runtheexample:https://svelte.dev/repl/70e61d6cc91345cdaca2db9b7077a941
PromisesinSvelteTemplates
35
WorkingwithEventsinSvelte
ListeningtoDOMeventsInSvelteyoucandefinealistenerforaDOMeventdirectlyinthetemplate,usingthe on:<event>syntax.
Forexample,tolistentothe clickevent,youwillpassafunctiontothe on:clickattribute.
Tolistentothe onmousemoveevent,you'llpassafunctiontothe on:mousemoveattribute.
Here'sanexamplewiththehandlingfunctiondefinedinline:
<buttonon:click={()=>{
alert('clicked')
}}>Clickme</button>
andhere'sanotherexamplewiththehandlingfunctiondefinedinthe scriptsectionofthecomponent:
<script>
constdoSomething=()=>{
alert('clicked')
}
</script>
<buttonon:click={doSomething}>Clickme</button>
Ipreferinlinewhenthecodeisnottooverbose.Ifit'sjust2-3lines,forexample,otherwiseI'dmovethatupinthescriptsection.
Sveltepassestheeventhandlerastheargumentofthefunction,whichishandyifyouneedtostoppropagationortoreferencesomethingintheEventobject:
<script>
constdoSomething=event=>{
console.log(event)
alert('clicked')
}
</script>
<buttonon:click={doSomething}>Clickme</button>
WorkingwithEventsinSvelte
37
Now,Imentioned"stoppropagation".That'saverycommonthingtodo,tostopformsubmiteventsforexample.Svelteprovidesusmodifiers,awaytoapplyitdirectlywithoutmanuallydoingit. stopPropagationand preventDefaultarethe2modifiersyou'llusethemost,Ithink.
Youapplyamodifierlikethis: <buttonon:click|stopPropagation|preventDefault={doSomething}>Clickme</button>
Thereareothermodifiers,whicharemoreniche. captureenablescapturingeventsinsteadofbubbling, onceonlyfirestheeventonce, selfonlyfirestheeventifthetargetoftheeventisthisobject(removingitfromthebubbling/capturinghierarchy).
CreatingyoureventsincomponentsWhat'sinterestingisthatwecancreatecustomeventsincomponents,andusethesamesyntaxofbuilt-inDOMevents.
Todoso,wemustimportthe createEventDispatcherfunctionfromthe sveltepackageandcallittogetaneventdispatcher:
<script>
import{createEventDispatcher}from'svelte'
constdispatch=createEventDispatcher()
</script>
Oncewedoso,wecancallthe dispatch()function,passingastringthatidentifiestheevent(whichwe'lluseforthe on:syntaxinothercomponentsthatusethis):
<script>
import{createEventDispatcher}from'svelte'
constdispatch=createEventDispatcher()
//whenit'stimetotriggertheevent
dispatch('eventName')
</script>
Nowothercomponentscanuseoursusing
<ComponentNameon:eventName={event=>{
//dosomething
}}/>
Youcanalsopassanobjecttotheevent,passingasecondparameterto dispatch():
<script>
import{createEventDispatcher}from'svelte'
WorkingwithEventsinSvelte
38
constdispatch=createEventDispatcher()
constvalue='something'
//whenit'stimetotriggertheevent
dispatch('eventName',value)
//or
dispatch('eventName',{
someProperty:value
})
</script>
theobjectpassedby dispatch()isavailableonthe eventobject.
WorkingwithEventsinSvelte
39
WhereDoWeGoFromHereIhopethislittlehandbookwasusefultoshinealightonwhatSveltecandoforyou,andIhopeyouarenowinterestedtolearnmoreaboutit!
Icannowpointyoutotwoplacestolearnmore:
TheofficialSveltewebsiteSapper,anawesomeframeworkbuiltontopofSveltethatletsyoubuildSSRappswithNode.jsandSvelte
That'sit!
Icanpointyoutomywebsiteflaviocopes.comifyouareinterestedinlearningmore,IpublishonenewtutorialeverydayandI'llbepostingmoreSvelteguidessoon!
WhereDoWeGoFromHere
40