Table of Contents - itjumpstart.files.wordpress.com · "rollup-plugin-node-resolve"...

40

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

PromisesinSvelteTemplates

36

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