Building Single Page Web Apps With Sinatra

Embed Size (px)

Citation preview

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    1/20

    Building Single Page Web Apps with

    Sinatra: Part 1

    Jonathan Cutrellon Nov 8th 2012 with 14 Comments and 157 Reactions

    Have you ever wanted to learn how to build a sinle !ae a!! with "inatra and #noc$out%&s'

    (ell) today is the day you learn* +n this ,irst section o, a two-!art series) we.ll review the

    !rocess ,o buildin a sinle !ae to-do a!!lication where users can view their tas$s) sort

    them) mar$ them as com!lete) delete them) search throuh them) and add new tas$s%

    What is Sinatra?

    /ccordin to their website

    "inatra is a " ,or 3uic$ly creatin web a!!lications in Ruby with minimal e,,ort%

    "inatra allows you to do thins) li$e

    get "/task/new"do erb :formend

    his is a route that handles 6 re3uests ,or tas$new9 and renders an erb,orm named

    form.erb% (e won.t be usin "inatra to render Ruby tem!lates: instead) we.ll use it only to

    send J";N res!onses to our #noc$out%&s manaed ,ront end % (e will be usin erb only to render the main H? ,ile%

    What is Knockout?

    #noc$out is a ?odel-@iew-@iew?odel Java"cri!t ,ramewor$ that allows you to

    $ee! your models in s!ecial observable9 ob&ects% +t also $ee!s your A+ u! to date) based onthose observed ob&ects%

    1

    http://net.tutsplus.com/author/jonathan-cutrell/http://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-1/#disqus_threadhttp://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-1/http://net.tutsplus.com/author/jonathan-cutrell/http://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-1/#disqus_thread
  • 8/13/2019 Building Single Page Web Apps With Sinatra

    2/20

    Here is what you.ll be buildin

    -ToDo/-app.rb-models.rb--views/ -index.erb-- public /--- scripts/ - knockout.js - juer!.js - app.js

    --- st!les/ - st!les.css

    (e.ll et started by de,inin our model and then our CRA actions in "inatra% (e.ll rely on

    ata?a!!erand "=ite,or !ersistent storae) but you can use any ;R? that you !re,er%

    et.s add a tas$ model to the models.rb,ile

    Dataapper.setup#:default %slite:///pat&/to/project.db%'classTask include Dataapper::(esource propert! :id )erial

    propert! :complete *oolean propert! :description Text

    2

    http://datamapper.org/http://www.sqlite.org/http://sqlite//path/to/project.dbhttp://datamapper.org/http://www.sqlite.org/http://sqlite//path/to/project.db
  • 8/13/2019 Building Single Page Web Apps With Sinatra

    3/20

    propert! :created+at DateTime propert! :updated+at DateTimeendDataapper.auto+upgrade,

    his tas$ model essentially consists o, a ,ew di,,erent !ro!erties that we want to mani!ulatein our to-do a!!lication%

    NeBt) let.s write our "inatra J";N server% +n the app.rb,ile) we.ll start by re3uirin a ,ew

    di,,erent modules

    reuire %rub!gems%reuire %sinatra%reuire %data+mapper%reuire ile.dirname#++0++' 1 %/models.rb%reuire %json%reuire %Date%

    he neBt ste! is to de,ine some lobal de,aults: in !articular) we need a ?+?6 ty!e sent with

    each o, our res!onse headers to s!eci,y that every res!onse is J";N%

    before do content+t!pe %application/json%end

    he beforehel!er ,unction runs be,ore every route match% ou can also s!eci,y matchin

    routes a,ter before: i, you) ,or instance) wanted to only run J";N res!onses i, the AR

    ended in %&son9) you would use this

    before 2r3.14.json$5 do content+t!pe %application/json%end

    NeBt) we de,ine our CRA routes) as well as one route to serve our index.erb,ile

    get "/"do content+t!pe %&tml% erb :indexendget "/tasks"do

    6tasks7 Task.all 6tasks.to+jsonendpost "/tasks/new"do 6task7 Task.new 6task.complete 7 false 6task.description 7 params8:description9 6task.created+at 7 DateTime.now 6task.updated+at 7 nullendput "/tasks/:id"do 6task7 Task.find#params8:id9' 6task.complete 7 params8:complete9

    6task.description 7 params8:description9 6task.updated+at 7 DateTime.now

    D

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    4/20

    if6task.save 3:task7 6task :status7 "success"5.to+json else 3:task7 6task :status7 "failure"5.to+json endend

    delete "/tasks/:id"do 6task7 Task.find#params8:id9' if6task.destro! 3:task7 6task :status7 "success"5.to+json else 3:task7 6task :status7 "failure"5.to+json endend

    "o the app.rb,ile now loo$s li$e this

    reuire %rub!gems%reuire %sinatra%reuire %data+mapper%reuire ile.dirname#++0++' 1 %/models.rb%reuire %json%reuire %Date%before do content+t!pe %application/json%endget "/"do content+t!pe %&tml% erb :indexendget "/tasks"do 6tasks7 Task.all 6tasks.to+jsonendpost "/tasks/new"do 6task7 Task.new 6task.complete 7 false 6task.description 7 params8:description9 6task.created+at 7 DateTime.now 6task.updated+at 7 null if6task.save 3:task7 6task :status7 "success"5.to+json else 3:task7 6task :status7 "failure"5.to+json end

    endput "/tasks/:id"do 6task7 Task.find#params8:id9' 6task.complete 7 params8:complete9 6task.description 7 params8:description9 6task.updated+at 7 DateTime.now if6task.save 3:task7 6task :status7 "success"5.to+json else 3:task7 6task :status7 "failure"5.to+json endenddelete "/tasks/:id"do

    6task7 Task.find#params8:id9' if6task.destro!

    4

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    5/20

    3:task7 6task :status7 "success"5.to+json else 3:task7 6task :status7 "failure"5.to+json endend

    6ach o, these routes ma!s to an action% here is only one view thathouses every action% Remember in Ruby) the ,inal value returns im!licitly% ou can

    eB!licitly return early) but whatever content these routes return will be the res!onse sent ,rom

    the server%

    Knockout: Models

    NeBt) we start by de,inin our models in #noc$out% +n app.js) !lace the ,ollowin code

    functionTask#data' 3

    t&is.description 7 ko.observable#data.description'; t&is.complete 7 ko.observable#data.complete'; t&is.created+at 7 ko.observable#data.created+at'; t&is.updated+at 7 ko.observable#data.updated+at'; t&is.id 7 ko.observable#data.id';5

    /s you can see) these !ro!erties are directly ma!!ed to our model in models.rb% /

    ko.observable$ee!s the value u!dated across the A+ when it chanes without havin to

    rely on the server or on the ;? to $ee! trac$ o, its state%

    NeBt) we will add a Task

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    6/20

    varnewtask 7 newTask#3 description: t&is.newTaskDesc#' 5'; $.get>)?@#"/getdate" function#data'3 newtask.created+at#data.date'; newtask.updated+at#data.date'; t.tasks.pusnewtask'; t.saveTask#newtask';

    t.newTaskDesc#""'; 5'5;t.saveTask 7 function#task' 3 vart 7 ko.to>)#task'; $.ajax#3 url: "&ttp://local&ost:ABAB/tasks" t!pe: "C?)T" data: t 5'.done#function#data'3 task.id#data.task.id'; 5';5

    Eirst) we set newTaskDescas an observable% his allows us to use an in!ut ,ield easily to ty!e

    a tas$ descri!tion% NeBt) we de,ine our addTask#',unction) which adds a tas$ to the

    observable=rra!: it calls the saveTask#',unction) !assin in the new tas$ ob&ect%

    he saveTask#',unction is anostic o, what $ind o, save it !er,orms%

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    7/20

    ,-- Clace favicon.ico and apple-touc&-icon.png in t&e rootdirector! -- linkrel7"st!les&eet" &ref7"st!les/st!les.css" scriptsrc7"scripts/moderniLr-M.N.M.min.js"/script ,--8if lt 0 G9 p class7"c&romeframe"Fou are using an outdated browser. a

    &ref7"&ttp://browse&app!.com/"Jpgrade !our browser toda!/a or a&ref7"&ttp://www.google.com/c&romeframe/Oredirect7true "install PoogleE&rome rame/a to better experience t&is site./p ,8endif9-- ,-- =dd !our site or application content &ere -- divid7"container" sectionid7"taskforms"class7"clearfix" divid7"newtaskform"class7"floatleft fift!" &MEreate a @ew Task/&M formid7"addtask" input inputt!pe7"submit" /form

    /div divid7"tasksearc&form"class7"floatrig&t fift!" &M)earc& Tasks/&M formid7"searc&task" input /form /div /section sectionid7"tasktable" &Mncomplete Tasks remaining: span/span/&M aDelete =ll Eomplete Tasks/a table tbod!tr

    t&D* D/t& t&Description/t& t&Date =dded/t& t&Date odified/t& t&EompleteO/t& t&Delete/t& /tr tr td/td td/td td/td td/td tdinputt!pe7"c&eckbox" /td tdclass7"destro!task"aI/a/td /tr /tbod!/table /section /div scriptsrc7"&ttp://ajax.googleapis.com/ajax/libs/juer!/K.H.K/juer!.min.js "/script scriptwindow.jQuer! RR document.write#%scriptsrc7"scripts/juer!.js"4/script%'/script scriptsrc7"scripts/knockout.js"/script scriptsrc7"scripts/app.js"/script ,-- Poogle =nal!tics: c&ange J=-IIIII-I to be !our site%s D. -- script var +ga788%+set=ccount%%J=-IIIII-I%98%+trackCageview%99;

    7

    http://browsehappy.com/http://www.google.com/chromeframe/?redirect=truehttp://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.jshttp://browsehappy.com/http://www.google.com/chromeframe/?redirect=truehttp://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js
  • 8/13/2019 Building Single Page Web Apps With Sinatra

    8/20

    #function#dt'3varg7d.create0lement#t's7d.get0lements*!Tag@ame#t'8S9; g.src7#%&ttps:%77location.protocolO%//ssl%:%//www%'1%.google-anal!tics.com/ga.js%; [email protected]*efore#gs'5#document%script%''; /script

    /bod!/&tml

    et.s ta$e this tem!late and ,ill in the bindins that #noc$out uses to $ee! the A+ in sync% Eor

    this !art) we cover the creation o, o-o items% +n the !art two) we will cover more advanced

    ,unctionality %

    Ge,ore we move on) let.s ive our !ae a little bit o, style% "ince this tutorial isn.t about C"")

    we.ll &ust dro! this in and move riht alon% he ,ollowin code is inside the H?5

    Goiler!late C"" ,ile) which includes a reset and a ,ew other thins%

    section 3 widt&: HSSpx; margin: MSpxauto;5table 3 widt&: KSS2;5t& 3 cursor: pointer;5tr 3 border-bottom: Kpxsolidddd;

    5tr.complete tr.complete:nt&-c&ild#odd' 3 background: efffdG; color: ddd;5tr:nt&-c&ild#odd' 3 background-color: dedede;5td 3 padding: KSpxMSpx;5td.destro!task 3 background: ffeaea;

    color: AUBcBc; font-weig&t: bold; opacit!: S.U;5td.destro!task:&over 3 cursor: pointer; background: ffacac; color: GAMGMG; opacit!: K;5.fift! 3 widt&: VS2; 5input 3 background: fefefe;

    box-s&adow: insetSSNpxaaa; padding: Npx; border: none;

    8

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    9/20

    widt&: AS2; margin: Upx;5input:focus 3 outline: none; box-s&adow: insetSSNpxrgb#KG KUH MKK';

    -webkit-transition: S.Ms all; background: rgba#KG KUH MKK S.SV';5input8t!pe7submit9 3 background-color: KKAUdB; background-image: -webkit-gradient#linear lefttop leftbottomfrom#rgb#KG KUH MKK'' to#rgb#VA AV KUM'''; background-image: -webkit-linear-gradient#top rgb#KG KUH MKK'rgb#VA AV KUM''; background-image: -moL-linear-gradient#top rgb#KG KUH MKK' rgb#VAAV KUM''; background-image: -o-linear-gradient#top rgb#KG KUH MKK' rgb#VAAV KUM'';

    background-image: -ms-linear-gradient#top rgb#KG KUH MKK' rgb#VAAV KUM''; background-image: linear-gradient#top rgb#KG KUH MKK' rgb#VA AVKUM''; filter:progid:DImageTransform.icrosoft.gradient#PradientT!pe7S)tartEolor)tr7%KKAUdB% 0ndEolor)tr7%BbVfHe%'; padding: NpxApx; border-radius: Bpx; color: fff; text-s&adow: KpxKpxKpxSaBdVM; border: none; widt&: BS2;

    5input8t!pe7submit9:&over 3 background: SaBdVM;5.floatleft 3 float: left; 5.floatrig&t 3 float: rig&t; 5

    /dd this code to your st!les.css,ile%

    Now) let.s cover the new tas$9 ,orm% (e will add data-bindattributes to the ,orm to ma$e

    the #noc$out bindins wor$% he data-bindattribute is how #noc$out $ee!s the A+ in sync)

    and allows ,or event bindin and other im!ortant ,unctionality% Re!lace the new tas$9 ,ormwith the ,ollowin code%

    divid7"newtaskform"class7"floatleft fift!" &MEreate a @ew Task/&M formid7"addtask"data-bind7"submit: addTask" inputdata-bind7"value: newTaskDesc" inputt!pe7"submit" /form/div

    (e.ll ste! throuh these one by one% Eirst) the ,orm element has a bindin ,or the submit

    event% (hen the ,orm is submitted) the addTask#',unction de,ined on the Task

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    10/20

    the ko.observable newTaskDescthat we de,ined earlier% (hatever is in this ,ield when

    submittin the ,orm becomes the as$.s description!ro!erty%

    "o we have a way to add tas$s) but we need to dis!lay those tas$s% (e also need to add each

    o, the tas$.s !ro!erties% et.s iterate over the tas$s and add them into the table% #noc$out

    !rovides a convenient iteration ability to ,acilitate this: de,ine a comment bloc$ with the,ollowin syntaB

    ,-- ko foreac&: tasks -- tddata-bind7"text: id"/td tddata-bind7"text: description"/td tddata-bind7"text: created+at"/td tddata-bind7"text: updated+at"/td td inputt!pe7"c&eckbox"/td td aI/a/td,-- /ko --

    his uses #noc$out.s iteration ca!ability% 6ach tas$ is s!eci,ically de,ined on theTask

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    11/20

    Building Single Page Web Apps With

    Sinatra: Part 2

    +n the ,irst !arto, this mini-series) we created the basic structure o, a to-do a!!lication usin

    a "inatra J";N inter,ace to a "=ite database) and a #noc$out-!owered ,ront-end that

    allows us to add tas$s to our database% +n this ,inal !art) we.ll cover some slihtly more

    advanced ,unctionality in #noc$out) includin sortin) searchin) u!datin) and deletin%

    et.s start where we le,t o,,: here is the relevant !ortion o, our index.erb,ile%

    divid7"container" sectionid7"taskforms"class7"clearfix" divid7"newtaskform"class7"floatleft fift!"

    &MEreate a @ew Task/&M formid7"addtask"data-bind7"submit: addTask" inputdata-bind7"value: newTaskDesc" inputt!pe7"submit" /form /div divid7"tasksearc&form"class7"floatrig&t fift!" &M)earc& Tasks/&M formid7"searc&task" input /form /div /section sectionid7"tasktable" &Mncomplete Tasks remaining: span/span/&M aDelete =ll Eomplete Tasks/a table tbod!tr t&D* D/t& t&Description/t& t&Date =dded/t& t&Date odified/t& t&EompleteO/t& t&Delete/t& /tr ,-- ko foreac&: tasks -- tr tddata-bind7"text: id"/td tddata-bind7"text: description"/td tddata-bind7"text: created+at"/td tddata-bind7"text: updated+at"/td tdinputt!pe7"c&eckbox"data-bind7"c&ecked:complete click: $parent.mark=sEomplete" /td tddata-bind7"click: $parent.destro!Task"class7"destro!task"aI/a/td /tr ,-- /ko -- /tbod!/table /section /div

    11

    http://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-1/http://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-1/
  • 8/13/2019 Building Single Page Web Apps With Sinatra

    12/20

    Sort

    "ortin is a common tas$ used in many a!!lications% +n our case) we want to sort the tas$ list

    by any header ,ield in our tas$-list table% (e will start by addin the ,ollowin code to the

    Task

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    13/20

    hese bindins allow each o, the headers to trier a sort based on the !assed strin value:

    each o, these directly ma!s to the Taskmodel%

    Mark As Complete

    NeBt) we want to be able to mar$ a tas$ as com!lete) and we.ll accom!lish this by sim!ly

    clic$in the chec$boB associated with a !articular tas$% et.s start by de,inin a method in the

    Task

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    14/20

    his ,unction adds a !ro!erty similar to the !ut9 method ,or com!letin a tas$% he built-in

    destro!#'method removes the !assed-in tas$ ,rom the observable array% Einally) callin

    saveTask#'destroys the tas$: that is) as lon as the .+met&odis set to delete9%

    Now we need to modi,y our view: add the ,ollowin

    tddata-bind7"click: $parent.destro!Task"class7"destro!task"aI/a/td

    his is very similar in ,unctionality to the com!lete chec$boB% Note that the

    class7"destro!task"is !urely ,or stylin !ur!oses%

    Delete All Completed

    NeBt) we want to add the delete all com!lete tas$s9 ,unctionality% Eirst) add the ,ollowincode to the Task

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    15/20

    ncomplete Tasks !emaining

    ;ur inter,ace should also dis!lay the amount o, incom!lete tas$s% "imilar to our

    completeTasks#',unction above) we de,ine an incompleteTasks#',unction in

    Task

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    16/20

    tddata-bind7"text: $root.dateormat#created+at#''"/tdtddata-bind7"text: $root.dateormat#updated+at#''"/td

    his !asses the created+atand updated+at!ro!erties to the dateormat#',unction% ;nce

    aain) it.s im!ortant to remember that !ro!erties o, each tas$ are not normal !ro!erties: they

    are ,unctions% +n order to retrieve their value) you must call the ,unction % Note $rootis a $eyword) de,ined by #noc$out) that re,ers to the

    @iew?odel% he dateormat#'method) ,or instance) is de,ined as a method o, the root

    @iew?odel

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    17/20

    #inal Code

    index.erb

    ,D?ETFC0 &tml

    &tml,--8if lt 0 G9 &tml class7"no-js lt-ieA lt-ieH lt-ieG" ,8endif9--,--8if 0 G9 &tml class7"no-js lt-ieA lt-ieH" ,8endif9--,--8if 0 H9 &tml class7"no-js lt-ieA" ,8endif9--

    ,--8if gt 0 H9,-- ,--,8endif9-- bod! metac&arset7"utf-H" meta&ttp-euiv7"I-J=-Eompatible" content7"07edgec&rome7K" titleToDo/title metaname7"description" content7"" metaname7"viewport"content7"widt&7device-widt&" ,-- Clace favicon.ico and apple-touc&-icon.png in t&e root

    director! -- linkrel7"st!les&eet" &ref7"st!les/st!les.css" scriptsrc7"scripts/moderniLr-M.N.M.min.js"/script ,--8if lt 0 G9 p class7"c&romeframe"Fou are using an outdated browser. a&ref7"&ttp://browse&app!.com/"Jpgrade !our browser toda!/a or a&ref7"&ttp://www.google.com/c&romeframe/Oredirect7true "install PoogleE&rome rame/a to better experience t&is site./p ,8endif9-- ,-- =dd !our site or application content &ere -- divid7"container" sectionid7"taskforms"class7"clearfix" divid7"newtaskform"class7"floatleft fift!" &MEreate a @ew Task/&M formid7"addtask"data-bind7"submit: addTask" inputdata-bind7"value: newTaskDesc" inputt!pe7"submit" /form /div divid7"tasksearc&form"class7"floatrig&t fift!" &M)earc& Tasks/&M formid7"searc&task" inputdata-bind7"value: uer! valueJpdate:%ke!up% event : 3 ke!up : searc&5" /form /div

    /section sectionid7"tasktable" &Mncomplete Tasks remaining: spandata-bind7"text:incompleteTasks#'.lengt&"/span/&M adata-bind7"click: remove=llEomplete visible:completeTasks#'.lengt& S "Delete =ll Eomplete Tasks/a table tbod!tr t&data-bind7"click: function#'3 sort#%id%' 5"D*D/t& t&data-bind7"click: function#'3 sort#%description%' 5"Description/t& t&data-bind7"click: function#'

    3 sort#%created+at%' 5"Date =dded/t&

    17

    http://browsehappy.com/http://www.google.com/chromeframe/?redirect=truehttp://browsehappy.com/http://www.google.com/chromeframe/?redirect=true
  • 8/13/2019 Building Single Page Web Apps With Sinatra

    18/20

    t&data-bind7"click: function#'3 sort#%updated+at%' 5"Date odified/t& t&data-bind7"click: function#'3 sort#%complete%' 5"EompleteO/t& t&Delete/t& /tr

    ,-- ko foreac&: tasks -- trdata-bind7"css: 3 %complete%: complete 5 visible:isvisible" tddata-bind7"text: id"/td tddata-bind7"text: description"/td tddata-bind7"text:$root.dateormat#created+at#''"/td tddata-bind7"text:$root.dateormat#updated+at#''"/td tdinputt!pe7"c&eckbox"data-bind7"c&ecked:complete click: $parent.mark=sEomplete" /td tddata-bind7"click: $parent.destro!Task"class7"destro!task"aI/a/td

    /tr ,-- /ko -- /tbod!/table /section /div scriptsrc7"&ttp://ajax.googleapis.com/ajax/libs/juer!/K.H.K/juer!.min.js "/script scriptwindow.jQuer! RR document.write#%scriptsrc7"scripts/juer!.js"4/script%'/script scriptsrc7"scripts/knockout.js"/script scriptsrc7"scripts/app.js"/script ,-- Poogle =nal!tics: c&ange J=-IIIII-I to be !our site%s D. --

    script var +ga788%+set=ccount%%J=-IIIII-I%98%+trackCageview%99; #function#dt'3varg7d.create0lement#t's7d.get0lements*!Tag@ame#t'8S9; g.src7#%&ttps:%77location.protocolO%//ssl%:%//www%'1%.google-anal!tics.com/ga.js%; [email protected]*efore#gs'5#document%script%''; /script /bod!/&tml

    app.js

    functionTask#data' 3 t&is.description 7 ko.observable#data.description'; t&is.complete 7 ko.observable#data.complete'; t&is.created+at 7 ko.observable#data.created+at'; t&is.updated+at 7 ko.observable#data.updated+at'; t&is.id 7 ko.observable#data.id'; t&is.isvisible 7 ko.observable#true';5functionTask

  • 8/13/2019 Building Single Page Web Apps With Sinatra

    19/20

    t.?@TX) 7 8">an" "eb" "ar" "=pr" "a!" ">un" ">ul" "=ug"")ep" "?ct" "@ov" "Dec"9; $.get>)?@#"&ttp://local&ost:ABAB/tasks" function#raw' 3 vartasks 7 $.map#raw function#item' 3 returnnewTask#item' 5'; t.tasks#tasks'; 5';

    t.incompleteTasks 7 ko.computed#function#' 3 returnko.utils.arra!ilter#t.tasks#' function#task' 3 return#,task.complete#' WW task.+met&od ,7 "delete"' 5'; 5'; t.completeTasks 7 ko.computed#function#' 3 returnko.utils.arra!ilter#t.tasks#' function#task' 3 return#task.complete#' WW task.+met&od ,7 "delete"' 5'; 5'; // ?perations t.dateormat 7 function#date'3 if#,date' 3 return"refres& to see server date"; 5 vard 7 newDate#date'; returnd.getXours#' 1 ":"1 d.getinutes#' 1 " "1 d.getDate#' 1 "

    "1 t.?@TX)8d.getont'9 1 " "1 d.getullFear#'; 5 t.addTask 7 function#' 3 varnewtask 7 newTask#3 description: t&is.newTaskDesc#' 5'; $.get>)?@#"/getdate" function#data'3 newtask.created+at#data.date'; newtask.updated+at#data.date'; t.tasks.pusnewtask'; t.saveTask#newtask'; t.newTaskDesc#""'; 5' 5; t.searc& 7 function#task'3

    ko.utils.arra!or0act.tasks#' function#task'3 if#task.description#' WW t.uer!#' ,7 ""'3 task.isvisible#task.description#'.toowerEase#'.index?f#t.uer!#'.toowerEase#'' 7 S'; 5 elseif#t.uer!#' 77 ""' 3 task.isvisible#true'; 5 else3 task.isvisible#false'; 5 5' returntrue; 5 t.sort 7 function#field'3 if#t.sorted*!.lengt& WW t.sorted*!8S9 77 field WWt.sorted*!8K977K'3 t.sorted*!8K97S; t.tasks.sort#function#firstnext'3 if#,next8field9.call#''3 returnK; 5 return#next8field9.call#' first8field9.call#'' O K :#next8field9.call#' 77 first8field9.call#'' O S : -K; 5'; 5 else3 t.sorted*!8S9 7 field; t.sorted*!8K9 7 K; t.tasks.sort#function#firstnext'3 if#,first8field9.call#''3 returnK; 5 return#first8field9.call#' next8field9.call#'' O K :#first8field9.call#' 77 next8field9.call#'' O S : -K; 5';

    1I

    http://localhost:9393/taskshttp://localhost:9393/tasks
  • 8/13/2019 Building Single Page Web Apps With Sinatra

    20/20

    5 5 t.mark=sEomplete 7 function#task' 3 if#task.complete#' 77 true'3 task.complete#true'; 5 else3

    task.complete#false'; 5 task.+met&od 7 "put"; t.saveTask#task'; returntrue; 5 t.destro!Task 7 function#task' 3 task.+met&od 7 "delete"; t.tasks.destro!#task'; t.saveTask#task'; 5; t.remove=llEomplete 7 function#' 3 ko.utils.arra!or0act.tasks#' function#task'3

    if#task.complete#''3 t.destro!Task#task'; 5 5'; 5 t.saveTask 7 function#task' 3 vart 7 ko.to>)#task'; $.ajax#3 url: "&ttp://local&ost:ABAB/tasks" t!pe: "C?)T" data: t 5'.done#function#data'3 task.id#data.task.id';

    5'; 55ko.appl!*indings#new Task