["<input\tclass=\\\"form-control\\\"\tname=\\\"coffee\\\"> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t<\/form> \t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t<\/div> ... The\tform-control\tclass\tis\tanother\tone\tdefined\tby\tBootstrap.\tIt\tprovides\tlayout\tand typography\tstyling\tfor\tyour\tform\telements. Save\tindex.html\tand\tcheck\tthe\tresults\tin\tthe\tbrowser\t(Figure\t9.4). Figure\t9.4\t\tInput\tfield\tfor\ta\tcoffee\torder Your\t<input>\telement\tdefaults\tto\ta\tsingle-line\ttext\tfield.\tOther\tthan\tits\tform-control class,\tit\thas\tone\tattribute:\tname.\tWhen\ta\tform\tis\tsubmitted,\tthe\tdata\twill\tbe\tsent\tto\ta\tserver, and\tthe\tname\tattribute\twill\tbe\tsent\twith\tthat\tdata.\tIf\tyou\tthink\tabout\tform\tdata\tas\ta key\/value\tpair,\tthen\tthe\tname\tattribute\tis\tthe\tkey\tand\tthe\tdata\tthat\tthe\tuser\ttypes\tin\tthe\tfield is\tthe\tvalue. Linking\ta\tlabel\tand\ta\tform\telement <label>\ttags\tare\timportant\tusability\tenhancements\tfor\tyour\tform\telements.\tYou\ttell\ta <label>\twhat\tform\telement\tit\tis\tlabeling\tby\tsetting\tits\tfor\tattribute\tto\tmatch\tthe\tid attribute\tof\tthe\tform\telement. In\tindex.html,\tadd\tfor\tand\tid\tattributes\tto\tyour\t<label>\tand\t<input>\tform\telements, respectively.\tGive\tboth\tattributes\tthe\tsame\tcoffeeOrder\tvalue. ... \t\t\t\t\t\t<div\tclass=\\\"panel\tpanel-default\\\"> \t\t\t\t\t\t\t\t<div\tclass=\\\"panel-body\\\"> \t\t\t\t\t\t\t\t\t\t<form\tdata-coffee-order=\\\"form\\\"> \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"coffeeOrder\\\">Coffee\tOrder<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\tclass=\\\"form-control\\\"\tname=\\\"coffee\\\"\tid=\\\"coffeeOrder\\\"> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t<\/form> \t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t<\/div> ...","When\ta\t<label>\tis\tlinked\tto\ta\tform\telement,\tyou\tcan\tclick\tthe\t<label>\u2019s\ttext\ton\tthe\tpage and\tit\twill\tmake\tthe\tlinked\tform\telement\tactive.\tYou\tshould\talways\tlink\tyour\t<label>s\tto their\tform\telements. To\tsee\tthis\tin\taction,\tsave\tindex.html,\tswitch\tto\tthe\tbrowser,\tand\tclick\tthe\tCoffee\tOrder label\ttext.\tThe\t<input>\tshould\tgain\tfocus,\tready\tfor\tyou\tto\tstart\ttyping\t(Figure\t9.5). Figure\t9.5\t\tClicking\tthe\tlinked\tlabel\tcauses\tthe\tinput\tto\tgain\tfocus Adding\tautofocus Because\tthis\tis\tthe\tfirst\tfield\ton\tthe\tscreen,\tyou\twant\tthe\tuser\tto\tbe\table\tto\tenter\ttext\tin\tit as\tsoon\tas\tthe\tpage\tloads,\tinstead\tof\thaving\tto\tclick. To\tachieve\tthis,\tadd\tan\tautofocus\tattribute\tto\tthe\t<input>\tin\tindex.html. ... \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"coffeeOrder\\\">Coffee\tOrder<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\tclass=\\\"form-control\\\"\tname=\\\"coffee\\\"\tid=\\\"coffeeOrder\\\"\tautofocus> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> ... Save\tyour\tchanges\tto\tindex.html\tand\treturn\tto\tthe\tbrowser.\tYou\twill\tsee\tthat\tthe\ttext input\tfield\thas\ta\tcursor\tand\ta\thighlight\tas\tsoon\tas\tthe\tpage\tloads\t(Figure\t9.6).","Figure\t9.6\t\tInput\tfield\twith\tautofocus\ton\tpage\tload Notice\tthat\tthe\tautofocus\tattribute\tdoes\tnot\thave\ta\tvalue.\tIt\tdoes\tnot\tneed\tone.\tThe\tmere presence\tof\tthe\tautofocus\tattribute\tin\tan\t<input>\ttag\ttells\tthe\tbrowser\tto\tactivate\tthat field.\tThe\tautofocus\tattribute\tis\ta\tBoolean\tattribute,\twhich\tmeans\tthat\tits\tonly\tpossible values\tare\ttrue\tand\tfalse.\tYou\tonly\tneed\tto\tadd\tthe\tattribute\tname\tto\tthe\ttag\tin\torder\tto set\tits\tvalue.\tWhen\tit\tis\tpresent,\tit\thas\tthe\tvalue\ttrue.\tWhen\tit\tis\tnot\tpresent,\tthe\tattribute is\tconsidered\tfalse. Adding\tan\temail\tinput\tfield When\tyou\tcreated\tyour\tTruck\tand\tDataStore\tmodules,\tyou\ttracked\torders\tby\tthe customer\u2019s\temail\taddress.\tNow\tyou\twill\tcapture\tthat\tinformation\tusing\tanother\t<input> element. Add\tanother\t.form-group\telement\tto\tindex.html\twith\ta\t<label>\tand\tan\t<input>.\tFor the\t<input>\telement,\tset\tthe\ttype\tas\temail,\tthe\tname\tto\temailAddress,\tand\tthe\tid\tto emailInput.\tAlso,\tadd\ta\tvalue\tattribute,\tset\tto\tan\tempty\tstring.\tThis\tensures\tthat\tthis\tfield is\tblank\twhen\tthe\tpage\tloads.\tFinally,\tlink\tthe\t<input>\tand\tthe\t<label>\tusing\tthe\tid. ... \t\t\t\t\t\t\t\t\t\t<form\tdata-coffee-order=\\\"form\\\"> \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"coffeeOrder\\\">Coffee\tOrder<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\tclass=\\\"form-control\\\"\tname=\\\"coffee\\\"\tid=\\\"coffeeOrder\\\"\tautofocus> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"emailInput\\\">Email<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\tclass=\\\"form-control\\\"\ttype=\\\"email\\\"\tname=\\\"emailAddress\\\" \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tid=\\\"emailInput\\\"\tvalue=\\\"\\\"> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t<\/form> ... Save\tindex.html\tand\tcheck\tthe\tbrowser\tto\tsee\tyour\tnew\tform\tfield\t(Figure\t9.7).","Figure\t9.7\t\tInput\tfield\tfor\tan\temail\taddress Showing\texample\tinput\twith\tplaceholder\ttext Sometimes\tusers\tappreciate\ta\tsuggestion\tabout\twhat\tthey\tshould\tenter\tinto\ta\ttext\tfield.\tTo create\texample\ttext,\tuse\tthe\tplaceholder\tattribute. Add\ta\tplaceholder\tattribute\tto\tyour\tnew\t<input>\telement\tin\tindex.html. ... \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"emailInput\\\">Email<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\tclass=\\\"form-control\\\"\ttype=\\\"email\\\"\tname=\\\"emailAddress\\\" \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tid=\\\"emailInput\\\"\tvalue=\\\"\\\"\tplaceholder=\\\"[email protected]\\\"> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> ... Save\tyour\tfile.\tThe\tresult\twill\tlook\tlike\tFigure\t9.8.","Figure\t9.8\t\tPlaceholder\ttext\tin\tthe\temail\tinput The\tvalue\tof\tthe\tplaceholder\tattribute\tappears\tin\tthe\ttext\tfield\tuntil\tthe\tuser\tenters\tsome text,\tat\twhich\tpoint\tit\tdisappears.\tIf\tthe\tuser\tdeletes\tall\tof\tthe\ttext\tin\tthe\tfield,\tthe placeholder\ttext\tappears\tagain. Offering\tchoices\twith\tradio\tbuttons Next,\tyou\twant\tthe\tuser\tto\tbe\table\tto\tspecify\tthe\tsize\tof\ttheir\tcoffee\tdrink.\tThey\tshould\tbe able\tto\tchoose\tbetween\tshort,\ttall,\tand\tgrande\t\u2013\tand\tthey\tshould\tnot\tbe\table\tto\tchoose more\tthan\tone\tsize.\tFor\tthis\tkind\tof\tdata\tinput,\tyou\tcan\tuse\t<input>\tfields\twhose\ttype attribute\tis\tset\tto\tradio. The\tmarkup\tfor\tyour\tradio\tbuttons\twill\tbe\tdifferent\tfrom\tyour\tother\t<input>\tfields.\tEach radio\tbutton\twill\thave\tan\t<input>\tfield,\twrapped\tby\ta\t<label>\telement.\tThe\t<label>\twill be\twrapped\tin\ta\t<div>\twhose\tclass\tis\talso\tradio. The\t<label>\telements\twill\tnot\tneed\tthe\tfor\tattribute\tthat\tyou\tadded\tto\tthe\t<label>s\tfor the\tcoffee\torder\tand\temail.\tBecause\tthe\t<input>\tis\twrapped\twith\tthe\t<label>,\tthey\tare automatically\tlinked. In\tcase\tyou\tare\twondering\twhy\tthe\tHTML\tis\tdifferent\tfor\tradio\tbuttons,\tit\tis\tbecause Bootstrap\tstyles\tthem\tdifferently\tfrom\tthe\tother\tform\telements. When\twriting\tyour\town\tcode,\tyou\tcan\tchoose\tto\twrap\tan\t<input>\telement\tin\ta\t<label>\tor to\tuse\tthe\tfor\tattribute\t\u2013\tboth\tare\tcorrect.\tBut,\twhen\tyou\tuse\tBootstrap,\tyou\tmust\tfollow\tits patterns\tand\tconventions\tfor\tthe\tstyles\tto\twork\tas\texpected.\tRefer\tto\tthe\tBootstrap documentation\tfor\texamples\tof\thow\tto\tstructure\tyour\tHTML\t(getbootstrap.com\/\u200b css\/\u200b#forms). In\tindex.html,\tadd\tthe\tmarkup\tfor\tyour\tradio\tbuttons\tjust\tafter\tthe\temail\t<input>. ... \t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"emailInput\\\">Email<\/label>","<input\tclass=\\\"form-control\\\"\ttype=\\\"email\\\"\tname=\\\"emailAddress\\\" \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tid=\\\"emailInput\\\"\tvalue=\\\"\\\"\tplaceholder=\\\"[email protected]\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"radio\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\ttype=\\\"radio\\\"\tname=\\\"size\\\"\tvalue=\\\"short\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tShort \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"radio\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\ttype=\\\"radio\\\"\tname=\\\"size\\\"\tvalue=\\\"tall\\\"\tchecked> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tTall \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"radio\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\ttype=\\\"radio\\\"\tname=\\\"size\\\"\tvalue=\\\"grande\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tGrande \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t\t\t<\/form> ... You\tgave\tall\tthree\tof\tyour\tradio\tinputs\tthe\tsame\tvalue\tfor\tthe\tname\tattribute\t(size).\tThis tells\tthe\tbrowser\tthat\tonly\tone\tof\tthem\tcan\tbe\tselected\t(or\t\u201cchecked\u201d)\tat\ta\ttime.\tYou\tgave the\tTall\tradio\tbutton\ta\tBoolean\tattribute\tnamed\tchecked.\tThis\tworks\tthe\tsame\tway\tthat autofocus\tdoes:\tWhen\tit\tis\tpresent,\tthe\tvalue\tof\tthe\tattribute\tis\ttrue\tand\twhen\tit\tis\tabsent it\tis\tfalse. Save\tindex.html\tand\ttake\ta\tlook\tat\tyour\tnew\tradio\tbuttons\t(Figure\t9.9). Figure\t9.9\t\tRadio\tbuttons\tfor\tcoffee\tsizes Try\tclicking\teither\ta\tradio\tbutton\tor\tthe\ttext\tnext\tto\tit.\tEither\tway,\tthat\tradio\tbutton\tshould indicate\tthat\tit\twas\tselected. Adding\ta\tdropdown\tmenu","Some\tfolks\tare\tcrazy\tfor\tflavored\tcoffee.\tYou\twant\tto\tgive\tthem\tthe\toption\tto\tchoose\tfrom a\tfew\tdifferent\tflavors.\tBy\tdefault,\tno\tflavor\tshot\twill\tbe\tadded. You\tcould\tuse\ta\tset\tof\tradio\tbuttons\tfor\tthis,\tbut\tyou\tmight\tadd\tmany\tmore\tflavors\tto\tthe list.\tTo\tmake\tsure\tthat\tthe\tflavor\tchoices\tdo\tnot\tclutter\tup\tthe\tUI,\tyou\twill\tuse\ta\tdropdown menu. To\tcreate\ta\tdropdown\tmenu\tstyled\twith\tBootstrap,\tadd\ta\t<div>\tto\tindex.html\twith\tthe class\tform-group.\tCreate\ta\t<select>\telement\twith\tthe\tclass\tform-control.\tBootstrap will\tstyle\tthis\telement\tas\ta\tdropdown.\tLink\tit\tto\tits\t<label>\twith\tthe\tid\tflavorShot. Inside\tof\tthe\t<select>,\tadd\tan\t<option>\telement\tfor\teach\tof\tthe\tmenu\titems\tyou\twant\tto display,\tgiving\teach\tof\tthem\ta\tmatching\tvalue. ... \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"radio\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\ttype=\\\"radio\\\"\tname=\\\"size\\\"\tvalue=\\\"grande\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tGrande \t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/label> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"flavorShot\\\">Flavor\tShot<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<select\tid=\\\"flavorShot\\\"\tclass=\\\"form-control\\\"\tname=\\\"flavor\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option\tvalue=\\\"\\\">None<\/option> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option\tvalue=\\\"caramel\\\">Caramel<\/option> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option\tvalue=\\\"almond\\\">Almond<\/option> \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option\tvalue=\\\"mocha\\\">Mocha<\/option> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/select> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t<\/form> \t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t<\/div> ... Each\tof\tthe\t<option>\telements\tprovides\tone\tof\tthe\tpossible\tvalues,\twhile\tthe\t<select> element\tspecifies\tthe\tname. Save\tindex.html\tand\tcheck\tthat\tyour\tdropdown\tis\tdisplayed\twith\tall\tof\tthe\toptions you\tadded\t(Figure\t9.10).","Figure\t9.10\t\tCoffee\tflavor\tdropdown By\tdefault,\tthe\tfirst\t<option>\telement\tis\tselected.\tYou\tcan\talso\tadd\tthe\tselected\tBoolean attribute\tto\tan\toption\telement,\tif\tyou\twant\tone\tother\tthan\tthe\tfirst\tto\tbe\tselected automatically. You\tset\tthe\tvalue\tattribute\tto\tan\tempty\tstring\tfor\tthe\tfirst\tdropdown\titem.\tIf\tyou\tleft\toff the\tvalue\tattribute\tcompletely,\tthe\tbrowser\twould\thave\tused\tthe\tstring\t\\\"None\\\"\tas\tthe value.\tIt\tis\tbest\tto\tset\tthe\tvalue\tattribute,\tas\tyou\tshould\tnever\tassume\tthat\tbrowsers\twill do\twhat\tyou\texpect. Adding\ta\trange\tslider Not\teveryone\twants\ta\tkiller\tcoffee\tbuzz.\tYou\twant\tto\tlet\tusers\tchoose\ta\tvalue\tbetween\t0 and\t100\tfor\tthe\tstrength\tof\ttheir\tcoffee.\tOn\tthe\tother\thand,\tyou\tdo\tnot\twant\tthem\tto\thave to\ttype\tin\tan\texact\tvalue. For\tthis,\tadd\tan\t<input>\telement\tin\tindex.html\twhose\ttype\tis\trange.\tThis\tcreates\ta range\tslider.\tThe\t<input>\tand\t<label>\tshould\tbe\tlinked\tand\twrapped\tin\ta\t<div>\twith\tthe form-group\tclass.\tGo\teasy\ton\tyour\tcoffee\tcustomers\tand\tprovide\ta\tdefault\tvalue\tof\t30. ... \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option\tvalue=\\\"mocha\\\">Mocha<\/option> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/select> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"strengthLevel\\\">Caffeine\tRating<\/label>","<input\tname=\\\"strength\\\"\tid=\\\"strengthLevel\\\"\ttype=\\\"range\\\"\tvalue=\\\"30\\\"> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t<\/form> ... Save\tindex.html\tand\ttry\tout\tyour\tnew\tslider\tin\tthe\tbrowser.\tIt\twill\tlook\tlike Figure\t9.11. Figure\t9.11\t\tSlider\tfor\tcaffeine\tstrength Adding\tSubmit\tand\tReset\tbuttons The\tlast\tthing\tto\tdo\tin\tthe\tmarkup\tis\tto\tadd\ta\tSubmit\tbutton.\tAs\ta\tusability\tconvenience, you\tshould\talso\tadd\ta\tReset\tbutton\tto\tclear\tthe\tform,\tin\tcase\tthe\tuser\twants\tto\tstart\tover. Normally,\tSubmit\tbuttons\tare\tjust\tan\t<input>\telement\twhose\ttype\tis\tsubmit.\tLikewise, Reset\tbuttons\tare\t<input>\telements\twhose\ttype\tis\treset.\tHowever,\tto\ttake\tadvantage\tof Bootstrap\u2019s\tCSS,\tyou\twill\tuse\ta\t<button>\telement\tinstead. In\tindex.html,\tadd\ttwo\t<button>\telements\twith\tthe\tclass\tnames\tbtn\tbtn-default. Set\tthe\ttype\tof\tthe\tfirst\tone\tto\tsubmit,\tand\tset\tthe\ttype\tof\tthe\tsecond\tone\tto\treset.\tIn between\tthe\topening\tand\tclosing\ttags,\tput\tSubmit\tand\tReset\tas\tdescriptive\ttext. ... \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"strengthLevel\\\">Caffeine\tRating<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\tname=\\\"strength\\\"\tid=\\\"strengthLevel\\\"\ttype=\\\"range\\\"\tvalue=\\\"30\\\">","<\/div> \t\t\t\t\t\t\t\t\t\t\t\t<button\ttype=\\\"submit\\\"\tclass=\\\"btn\tbtn-default\\\">Submit<\/button> \t\t\t\t\t\t\t\t\t\t\t\t<button\ttype=\\\"reset\\\"\tclass=\\\"btn\tbtn-default\\\">Reset<\/button> \t\t\t\t\t\t\t\t\t\t<\/form> ... When\tyou\tsave\tyour\tchanges,\tyour\tbrowser\twill\tadd\tthe\tbuttons\tat\tthe\tbottom\tof\tthe\tform (Figure\t9.12). Figure\t9.12\t\tSubmit\tand\tReset\tbuttons Your\tSubmit\tbutton\twill\tnot\tdo\tanything\tyet.\tThat\tis\tcoming\tin\tthe\tnext\tchapter.\tHowever, your\tReset\tbutton\twill\treset\tthe\tvalues\tto\ttheir\tdefaults. These\tbuttons\thave\ta\tpair\tof\tclasses\tthat\tmight\tseem\tredundant.\tThis\tis\ta\tconvention\tof Bootstrap\tand\tis\tpurely\tfor\tstyling.\tThe\tbtn\tclass\tprovides\tall\tof\tthe\tstandard\tvisual properties\tof\ta\tBootstrap\tbutton.\tThis\tincludes\trounded\tcorners\tand\tpadding.\tThe\tbtn- default\tclass\tadds\ta\twhite\tbackground\tcolor. You\thave\tused\tthe\tBootstrap\tUI\tframework\tto\tstyle\tyour\tCoffeeRun\tapp.\tBy\tapplying Bootstrap\u2019s\tpattern\tof\tmarkup\tand\tclass\tnames,\tyour\tapp\twill\thave\ta\tconsistent\tlook\tand feel\tfor\ta\tvariety\tof\tscreen\tsizes\tand\tbrowser\tversions. To\tlearn\tmore\tabout\twhat\tBootstrap\thas\tto\toffer,\tlook\tthrough\tthe\texcellent\tdocumentation at\tgetbootstrap.com\/\u200bcss.","Bootstrap\tis\tparticularly\tgood\tfor\tquickly\tstyling\tan\tapp\twhile\tyou\tfocus\ton\tthe\tapplication logic.\tIn\tthe\tnext\tchapters,\tyou\twill\tdo\tjust\tthat.","10\t Processing\tForms\twith\tJavaScript CoffeeRun\tis\toff\tto\ta\tgood\tstart.\tIt\thas\ttwo\tJavaScript\tmodules\tthat\thandle\tits\tinternal logic\tand\tan\tHTML\tform\tstyled\twith\tBootstrap.\tIn\tthis\tchapter,\tyou\twill\twrite\ta\tmore complex\tmodule\tthat\tconnects\tthe\tform\tto\tthe\tlogic,\tallowing\tyou\tto\tuse\tthe\tform\tto\tenter coffee\torders. Recall\tfrom\tChapter\t2\tthat\tbrowsers\tcommunicate\twith\tservers\tby\tsending\trequests\tfor information\tfor\ta\tparticular\tURL.\tSpecifically,\tfor\tevery\tfile\tthat\tthe\tbrowser\tneeds\tto load,\tit\tsends\ta\tGET\trequest\tto\tthe\tserver\tfor\tthat\tfile. When\tthe\tbrowser\tneeds\tto\tsend\tinformation\tto\ta\tserver,\tsuch\tas\twhen\ta\tuser\tfills\tout\tand submits\ta\tform,\tthe\tbrowser\ttakes\tthe\tform\tdata\tand\tputs\tit\tin\ta\tPOST\trequest.\tThe\tserver receives\tthe\trequest,\tprocesses\tthe\tdata,\tand\tthen\tsends\tback\ta\tresponse\t(Figure\t10.1). Figure\t10.1\t\tTraditional\tserver-side\tform\tprocessing In\tCoffeeRun,\tyou\twill\tnot\tneed\tto\tsend\tthe\tform\tdata\tto\ta\tserver\tfor\tprocessing.\tYour Truck\tand\tDataStore\tmodules\tserve\tthe\tsame\tpurpose\tas\ttraditional\tserver-side\tcode. Their\tjob\tis\tto\thandle\tthe\tbusiness\tlogic\tand\tdata\tstorage\tfor\tyour\tapplication.","Because\tthis\tcode\tlives\tin\tthe\tbrowser\tand\tnot\ton\ta\tserver,\tyou\tneed\tto\tcapture\tthe\tdata from\tthe\tform\tbefore\tit\tgoes\tout.\tIn\tthis\tchapter\tyou\twill\tcreate\ta\tnew\tmodule\tcalled FormHandler\tto\tdo\tjust\tthat.\tIn\taddition,\tyou\twill\tadd\tthe\tjQuery\tlibrary\tto\tCoffeeRun to\thelp\tyou\twith\tyour\twork.\tAs\tyou\tbuild\tout\tCoffeeRun\tover\tthe\tnext\tfew\tchapters,\tyou will\tuse\tmore\tof\tjQuery\u2019s\tpowerful\tfeatures. Creating\tthe\tFormHandler\tModule The\tFormHandler\tmodule\twill\tprevent\tthe\tbrowser\tfrom\ttrying\tto\tsend\tform\tdata\tto\ta server.\tInstead,\tit\twill\tread\tthe\tvalues\tfrom\tthe\tform\twhen\tthe\tuser\tclicks\tthe\tSubmit\tbutton. Then\tit\twill\tsend\tthat\tdata\tto\ta\tTruck\tinstance,\tusing\tthe\tcreateOrder\tmethod\tyou wrote\tin\tChapter\t8\t(Figure\t10.2). Figure\t10.2\t\tApplication\tarchitecture\tof\tCoffeeRun\twith\tApp.FormHandler Create\ta\tnew\tfile\tcalled\tformhandler.js\tin\tyour\tscripts\tfolder\tand\tadd\ta <script>\ttag\tfor\tit\tin\tindex.html. ... \t\t\t\t\t\t\t\t\t\t<\/form> \t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t<\/div> \t\t\t\t<\/section> \t\t\t\t<script\tsrc=\\\"scripts\/formhandler.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/datastore.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/truck.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/main.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t<\/body> <\/html> Like\tyour\tother\tmodules,\tFormHandler\twill\tuse\tan\tIIFE\tto\tencapsulate\tthe\tcode\tand attach\ta\tconstructor\tto\tthe\twindow.App\tproperty. Open\tscripts\/formhandler.js\tand\tcreate\tan\tIIFE.\tInside\tthe\tIIFE,\tcreate\tan\tApp variable.\tAssign\tit\tthe\texisting\tvalue\tof\twindow.App.\tIf\twindow.App\tdoes\tnot\texist\tyet, assign\tit\tan\tempty\tobject\tliteral.\tDeclare\ta\tFormHandler\tconstructor\tfunction,\tand export\tit\tto\tthe\twindow.App\tproperty. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tfunction\tFormHandler()\t{ \t\t\t\t\/\/\tCode\twill\tgo\there \t\t} \t\tApp.FormHandler\t=\tFormHandler; \t\twindow.App\t=\tApp; })(window); So\tfar,\tthis\tcode\tfollows\tthe\tfamiliar\tpattern\tyou\tused\tin\tyour\tTruck\tand\tDataStore","modules.\tIt\twill\tbe\tdifferent\tsoon,\tthough,\tin\tthat\tit\twill\timport\tand\tuse\tjQuery\tto\tdo\tits work. Introduction\tto\tjQuery The\tjQuery\tlibrary\twas\tcreated\tby\tJohn\tResig\tin\t2006.\tIt\tis\tone\tof\tthe\tmost\tpopular general-purpose\topen-source\tJavaScript\tlibraries.\tAmong\tother\tthings,\tit\tprovides convenient\tshorthands\tfor\tDOM\tmanipulation,\telement\tcreation,\tserver\tcommunication, and\tevent\thandling. It\tis\tuseful\tto\tbe\tfamiliar\twith\tjQuery,\tbecause\tthere\tis\tso\tmuch\tcode\tthat\thas\tbeen\twritten using\tit.\tAlso,\tmany\tlibraries\thave\tcopied\tjQuery\u2019s\tconventions.\tIn\tfact,\tjQuery\thas directly\tinfluenced\tthe\tstandard\tDOM\tAPI\t(document.querySelector\tand document.querySelectorAll\tare\ttwo\texamples\tof\tthis\tinfluence). jQuery\twill\tnot\tbe\tcovered\tin\tdepth\tright\tnow.\tInstead,\taspects\tof\tit\twill\tbe\tintroduced\tas needed\tto\thelp\tyou\tbuild\tmore\tcomplex\tparts\tof\tCoffeeRun.\tShould\tyou\twant\tto\texplore jQuery\tfurther,\tcheck\tout\tthe\tdocumentation\tat\tjquery.com. As\tyou\tdid\twith\tBootstrap,\tyou\twill\tadd\ta\tcopy\tof\tjQuery\tto\tyour\tproject\tfrom cdnjs.com.\tGo\tto\tcdnjs.com\/l\u200b ibraries\/j\u200b query\tto\tfind\tversion\t2.1.4\tand\tcopy its\taddress.\t(There\tmay\tbe\ta\tmore\trecent\tversion\tavailable,\tbut\tyou\tshould\tuse\t2.1.4\tfor CoffeeRun\tto\tavoid\tany\tcompatibility\tissues.) Add\tjQuery\tin\ta\t<script>\ttag\tin\tindex.html. ... \t\t\t\t\t\t<\/div> \t\t\t\t<\/section> \t\t\t\t<script\tsrc=\\\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jquery\/2.1.4\/jquery.min.js\\\" \t\t\t\t\t\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/formhandler.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/datastore.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/truck.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/main.js\\\"\tcharset=\\\"utf-8\\\"><\/script> ... Save\tindex.html. Importing\tjQuery FormHandler\twill\timport\tjQuery\tthe\tsame\tway\tthat\tit\tis\timporting\tApp.\tThe\treason\tfor doing\tthis\tis\tto\tmake\tit\texplicit\tthat\tyour\tmodule\tis\tusing\tcode\tthat\tis\tdefined\telsewhere. This\tis\ta\tbest\tpractice\tfor\tcoordinating\twith\tteam\tmembers\tand\tfor\tfuture\tmaintenance. In\tformhandler.js,\tcreate\ta\tlocal\tvariable\tnamed\t$\tand\tthen\tassign\tit\tthe\tvalue window.jQuery. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tvar\t$\t=\twindow.jQuery; \t\tfunction\tFormHandler()\t{ \t\t\t\t\/\/\tCode\twill\tgo\there \t\t} \t\tApp.FormHandler\t=\tFormHandler; \t\twindow.App\t=\tApp; })(window);","When\tyou\tadded\tthe\tjQuery\t<script>\ttag,\tit\tcreated\ta\tfunction\tnamed\tjQuery\tas\twell\tas a\tvariable,\tnamed\t$,\tpointing\tto\tthe\tfunction.\tMost\tdevelopers\tprefer\tto\tuse\t$\tin\ttheir code.\tIn\tkeeping\twith\tthat\tpractice,\tyou\tare\timporting\twindow.jQuery\tand\tassigning\tit\tto the\tlocal\tvariable\t$. Wondering\twhy\t$\tis\tused\tfor\tthe\tvariable\tname?\tJavaScript\tvariable\tnames\tcan\tcontain letters,\tnumbers,\tthe\tunderscore\t(_),\tor\tthe\tdollar\tsign\t($).\t(They\tcan\tonly\tstart\twith letters,\tunderscores,\tor\tdollar\tsigns,\tthough\t\u2013\tnot\tnumbers.)\tThe\tcreator\tof\tjQuery\tchose the\t$\tvariable\tname\tbecause\tit\tis\tshort\tand\tunlikely\tto\tbe\tused\tby\tany\tother\tcode\tin\ta project. Configuring\tinstances\tof\tFormHandler\twith\ta\tselector Your\tFormHandler\tmodule\tshould\tbe\tusable\twith\tany\t<form>\telement.\tTo\tachieve\tthis, the\tFormHandler\tconstructor\twill\tbe\tpassed\ta\tselector\tmatching\tthe\t<form>\telement\tin index.html. Update\tformhandler.js\tto\tadd\ta\tparameter\tcalled\tselector\tto\tthe\tFormHandler constructor.\tThrow\tan\tError\tif\tit\tis\tnot\tpassed\tin. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tvar\t$\t=\twindow.jQuery; \t\tfunction\tFormHandler(selector)\t{ \t\t\t\t\/\/\tCode\twill\tgo\there \t\t\t\tif\t(!selector)\t{ \t\t\t\t\t\tthrow\tnew\tError('No\tselector\tprovided'); \t\t\t\t} \t\t} \t\tApp.FormHandler\t=\tFormHandler; \t\twindow.App\t=\tApp; })(window); Error\tis\ta\tbuilt-in\ttype\tthat\tlets\tyou\tformally\tsignal\tthat\tthere\tis\tan\tunexpected\tvalue\tor condition\tin\tyour\tcode.\tFor\tnow,\tyour\tError\tinstance\twill\tsimply\tprint\tout\tyour\tmessage on\tthe\tconsole. Save\tand\ttry\tinstantiating\ta\tnew\tFormHandler\tobject\twithout\tpassing\tit\tan\targument (Figure\t10.3).\t(Remember\tto\tstart\tbrowser-sync,\tif\tit\tis\tnot\talready\trunning.) Figure\t10.3\t\tInstantiating\ta\tFormHandler\tobject\twithout\tpassing\targuments This\tis\tthe\tfirst\tstep\tin\tmaking\tFormHandler\tmore\treusable.\tIn\tOttergram,\tyou\tcreated variables\tfor\tthe\tselectors\tyou\tused\tin\tyour\tDOM\tcode.\tYou\twill\tnot\tbe\tdoing\tthat\twith\tthe FormHandler\tmodule.\tInstead,\tyou\twill\tuse\tthe\tselector\tthat\twas\tpassed\tin\tto\tthe","constructor\tand\tuse\tjQuery\tto\tfind\tthe\tmatching\telements. jQuery\tis\tmost\toften\tused\tfor\tfinding\telements\tin\tthe\tDOM.\tTo\tdo\tthat,\tyou\tcall\tthe jQuery\t$\tfunction\tand\tpass\tit\ta\tselector\tas\ta\tstring.\tIn\tfact,\tyou\tuse\tit\tthe\tsame\tway\tyou have\tbeen\tusing\tdocument.querySelectorAll\t(although\tjQuery\tworks\tdifferently under\tthe\thood,\tas\twe\twill\texplain\tin\ta\tmoment).\tIt\tis\tcommon\tto\trefer\tto\tthis\tas\t\u201cselecting elements\tfrom\tthe\tDOM\u201d\twith\tjQuery. Declare\tan\tinstance\tvariable\tnamed\t$formElement\tin\tformhandler.js.\tThen\tfind a\tmatching\telement\tin\tthe\tDOM\tusing\tthat\tselector\tand\tassign\tthe\tresult\tto this.$formElement. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tvar\t$\t=\twindow.jQuery; \t\tfunction\tFormHandler(selector)\t{ \t\t\t\tif\t(!selector)\t{ \t\t\t\t\t\tthrow\tnew\tError('No\tselector\tprovided'); \t\t\t\t} \t\t\t\tthis.$formElement\t=\t$(selector); \t\t} \t\tApp.FormHandler\t=\tFormHandler; \t\twindow.App\t=\tApp; })(window); Prefixing\ta\tvariable\twith\t$\tis\ta\tsign\tthat\tthe\tvariable\trefers\tto\telements\tselected\tusing jQuery.\tThis\tprefix\tis\tnot\ta\trequirement\twhen\tusing\tjQuery,\tbut\tit\tis\ta\tcommon\tconvention used\tby\tmany\tfront-end\tdevelopers. When\tyou\tuse\tjQuery\u2019s\t$\tfunction\tto\tselect\telements,\tit\tdoes\tnot\treturn\treferences\tto DOM\telements,\tthe\tway\tthat\tdocument.querySelectorAll\tdoes.\tInstead,\tit\treturns a\tsingle\tobject,\tand\tthe\tobject\tcontains\treferences\tto\tthe\tselected\telements.\tThe\tobject\talso has\tspecial\tmethods\tfor\tmanipulating\tthe\tcollection\tof\treferences.\tThis\tobject\tis\tcalled\ta \u201cjQuery-wrapped\tselection\u201d\tor\t\u201cjQuery-wrapped\tcollection.\u201d Next,\tyou\twant\tto\tmake\tsure\tthat\tthe\tselection\tsuccessfully\tretrieved\tan\telement\tfrom\tthe DOM.\tjQuery\twill\treturn\tan\tempty\tselection\tif\tit\tdoes\tnot\tfind\tanything\t\u2013\tit\twill\tnot\tthrow an\terror\tif\tthe\tselector\tdoes\tnot\tmatch\tanything.\tYou\twill\tneed\tto\tcheck\tmanually,\tbecause FormHandler\tcannot\tdo\tits\twork\twithout\tan\telement. The\tlength\tproperty\tof\ta\tjQuery-wrapped\tselection\ttells\tyou\thow\tmany\telements\twere matched.\tUpdate\tformhandler.js\tto\tcheck\tthe\tlength\tproperty\tof this.$formElement.\tIf\tit\tis\t0,\tthrow\tan\tError. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tvar\t$\t=\twindow.jQuery; \t\tfunction\tFormHandler(selector)\t{ \t\t\t\tif\t(!selector)\t{ \t\t\t\t\t\tthrow\tnew\tError('No\tselector\tprovided'); \t\t\t\t} \t\t\t\tthis.$formElement\t=\t$(selector); \t\t\t\tif\t(this.$formElement.length\t===\t0)\t{ \t\t\t\t\t\tthrow\tnew\tError('Could\tnot\tfind\telement\twith\tselector:\t'\t+\tselector); \t\t\t\t} \t\t} \t\tApp.FormHandler\t=\tFormHandler; \t\twindow.App\t=\tApp; })(window);","Your\tFormHandler\tconstructor\tcan\tbe\tconfigured\tto\twork\twith\tany\t<form>\telement based\ton\tthe\tselector\tpassed\tin.\tAlso,\tit\tkeeps\ta\treference\tto\tthat\t<form>\telement\tas\tan instance\tvariable.\tThis\tensures\tthat\tyour\tcode\twill\tnot\tmake\tmake\tunnecessary\ttrips\tto\tthe DOM.\tThis\tis\ta\tperformance\tbest\tpractice.\t(The\talternative\tis\tto\tcall\t$\tover\tand\tover, which\tre-selects\tthe\tsame\telements\teach\ttime.)","Adding\tthe\tsubmit\tHandler The\tnext\tstep\tis\tfor\tFormHandler\tto\tlisten\tfor\tthe\tsubmit\tevent\ton\tthe\t<form>\telement and\trun\ta\tcallback\twhen\tit\toccurs. To\tmake\tthe\tFormHandler\tmodule\tmore\treusable,\tyou\twill\tnot\thardcode\tthe\tsubmit handler\tcode.\tYou\twill\tinstead\twrite\ta\tmethod\tthat\taccepts\ta\tfunction\targument,\tadds\tthe submit\tlistener,\tand\tthen\tcalls\tthe\tfunction\targument\tinside\tthat\tlistener. First,\tadd\ta\tprototype\tmethod\tcalled\taddSubmitHandler\tto\tformhandler.js. ... \t\t\t\tif\t(this.$formElement.length\t===\t0)\t{ \t\t\t\t\t\tthrow\tnew\tError('Could\tnot\tfind\telement\twith\tselector:\t'\t+\tselector); \t\t\t\t} \t\t} \t\tFormHandler.prototype.addSubmitHandler\t=\tfunction\t()\t{ \t\t\t\tconsole.log('Setting\tsubmit\thandler\tfor\tform'); \t\t\t\t\/\/\tMore\tcode\twill\tgo\there \t\t}; \t\tApp.FormHandler\t=\tFormHandler; ... Instead\tof\tusing\tthe\taddEventListener\tmethod\tas\tyou\tdid\twith\tOttergram,\tyou\twill use\tjQuery\u2019s\ton\tmethod.\tIt\tis\tsimilar\tto\taddEventListener\tbut\tprovides\tadded conveniences.\tFor\tnow,\tthough,\tyou\twill\tuse\tit\tthe\tsame\tway\tyou\twould\tuse addEventListener.\t(You\twill\ttake\tadvantage\tof\tsome\tof\tthe\textra\tconveniences\tin the\tnext\tchapter.) ... \t\t\t\tif\t(this.$formElement.length\t===\t0)\t{ \t\t\t\t\t\tthrow\tnew\tError('Could\tnot\tfind\telement\twith\tselector:\t'\t+\tselector); \t\t\t\t} \t\t} \t\tFormHandler.prototype.addSubmitHandler\t=\tfunction\t()\t{ \t\t\t\tconsole.log('Setting\tsubmit\thandler\tfor\tform'); \t\t\t\t\/\/\tMore\tcode\twill\tgo\there \t\t\t\tthis.$formElement.on('submit',\tfunction\t(event)\t{ \t\t\t\t\t\tevent.preventDefault(); \t\t\t\t}); \t\t}; ... The\ton\tmethod\taccepts\tthe\tname\tof\tthe\tevent\tand\ta\tcallback\tto\trun\twhen\tthe\tevent\tis triggered.\tIts\tcallback\tshould\texpect\tto\treceive\tthe\tevent\tobject.\tYou\tcalled event.preventDefault\tto\tensure\tthat\tsubmitting\tthe\tform\tdoes\tnot\ttake\tthe\tuser away\tfrom\tthe\tCoffeeRun\tpage.\t(You\tdid\tthe\tsame\tthing\twith\tthe\tthumbnail\tlinks\tin Ottergram.) Extracting\tthe\tdata When\tthe\tform\tis\tsubmitted,\tyour\tcode\tshould\tread\tthe\tuser\tinput\tfrom\tthe\tform,\tthen\tdo something\twith\tthat\tdata.\tIn\tthe\tsubmit\thandler\tin\tformhandler.js,\tcreate\ta\tnew variable\tnamed\tdata.\tAssign\tit\tan\tobject\tliteral.\tIt\twill\thold\tthe\tvalue\tof\teach\telement\tof the\tform. ... \t\tFormHandler.prototype.addSubmitHandler\t=\tfunction\t()\t{ \t\t\t\tconsole.log('Setting\tsubmit\thandler\tfor\tform'); \t\t\t\tthis.$formElement.on('submit',\tfunction\t(event)\t{ \t\t\t\t\t\tevent.preventDefault();","var\tdata\t=\t$(this).serializeArray(); \t\t\t\t\t\tconsole.log(data); \t\t\t\t}); \t\t}; ... Inside\tyour\tsubmit\thandler\tcallback,\tthe\tthis\tobject\tis\ta\treference\tto\tthe\tform\telement. jQuery\tprovides\ta\tconvenience\tmethod\t(serializeArray)\tfor\tgetting\tthe\tvalues\tfrom the\tform.\tIn\torder\tto\tuse\tserializeArray,\tyou\tneed\tto\t\u201cwrap\u201d\tthe\tform\tusing\tjQuery. Calling\t$(this)\tgives\tyou\ta\twrapped\tobject,\twhich\thas\taccess\tto\tthe\tserializeArray method. serializeArray\treturns\tthe\tform\tdata\tas\tan\tarray\tof\tobjects.\tYou\tare\tassigning\tthat\tto a\ttemporary\tvariable\tnamed\tdata\tand\tlogging\tit\tto\tthe\tconsole.\tTo\tget\tan\tidea\tof\twhat serializeArray\tlooks\tlike,\tsave\tyour\tfile\tand\trun\tthe\tfollowing\tcode\tin\tthe\tconsole: var\tfh\t=\tnew\tApp.FormHandler('[data-coffee-order=\\\"form\\\"]'); fh.addSubmitHandler(); Next,\tfill\tout\tthe\tform\twith\tsome\ttest\tdata\tand\tclick\tthe\tSubmit\tbutton.\tYou\tshould\tsee\tthe array\tprinted\tto\tthe\tconsole.\tClick\tthe\t \tnext\tto\ta\tcouple\tof\tthe\tObject\titems\tin\tthe array.\tYou\tshould\tsee\tsomething\tlike\tFigure\t10.4. Figure\t10.4\t\tserializeArray\treturns\tform\tdata\tas\tan\tarray\tof\tobjects You\tcan\tsee\tthat\teach\tobject\tin\tthe\tarray\thas\ta\tkey\tthat\tcorresponds\tto\tthe\tname\tattribute\tof a\t<form>\telement\tand\tthe\tuser-supplied\tvalue\tfor\tthat\telement. Now\tyou\tcan\titerate\tthrough\tthe\tarray\tand\tcopy\tthe\tvalues\tfrom\teach\telement.\tAdd\ta\tcall to\tthe\tforEach\tmethod\tto\tserializeArray\tin\tformhandler.js\tand\tpass\tit\ta callback.\tAs\tthe\tcallback\tis\trun\tfor\teach\tobject\tin\tthe\tarray,\tit\twill\tuse\tthe\tobject\u2019s\tname and\tvalue\tto\tcreate\ta\tnew\tproperty\ton\tthe\tdata\tobject. ... \t\tFormHandler.prototype.addSubmitHandler\t=\tfunction\t()\t{ \t\t\t\tconsole.log('Setting\tsubmit\thandler\tfor\tform'); \t\t\t\tthis.$formElement.on('submit',\tfunction\t(event)\t{","event.preventDefault(); \t\t\t\t\t\tvar\tdata\t=\t$(this).serializeArray();\t{}; \t\t\t\t\t\t$(this).serializeArray().forEach(function\t(item)\t{ \t\t\t\t\t\t\t\tdata[item.name]\t=\titem.value; \t\t\t\t\t\t\t\tconsole.log(item.name\t+\t'\tis\t'\t+\titem.value); \t\t\t\t\t\t}); \t\t\t\t\t\tconsole.log(data); \t\t\t\t}); \t\t}; ... To\tsee\tthis\tin\taction,\tsave\tyour\tchanges\tand\trun\tyour\ttest\tcode\tagain\tin\tthe\tconsole\tbefore filling\tout\tthe\tform: var\tfh\t=\tnew\tApp.FormHandler('[data-coffee-order=\\\"form\\\"]'); fh.addSubmitHandler(); When\tyou\tfill\tout\tthe\tform\tand\tclick\tthe\tSubmit\tbutton,\tyou\tshould\tsee\tthat\tthe\tinformation you\tentered\tis\tcopied\tto\tthe\tdata\tobject\tand\tlogged\tto\tthe\tconsole\t(Figure\t10.5). Figure\t10.5\t\tForm\tdata\tis\tcopied\tin\tthe\titerator\tcallback Accepting\tand\tcalling\ta\tcallback Now\tthat\tyou\thave\tthe\tform\tdata\tas\ta\tsingle\tobject,\tyou\tneed\tto\tpass\tthat\tobject\tto\tyour Truck\tinstance\u2019s\tcreateOrder\tmethod.\tBut\tFormHandler\thas\tno\taccess\tto\tthe Truck\tinstance.\t(And\tit\twould\tdo\tno\tgood\tto\tcreate\ta\tnew\tTruck\tinstance\there.) You\tcan\tsolve\tthis\tby\tmaking\taddSubmitHandler\taccept\ta\tfunction\tparameter,\twhich it\tcan\tcall\tinside\tthe\tevent\thandler. In\tformhandler.js,\tadd\ta\tparameter\tcalled\tfn. ... \t\tFormHandler.prototype.addSubmitHandler\t=\tfunction\t(fn)\t{ \t\t\t\tconsole.log('Setting\tsubmit\thandler\tfor\tform'); \t\t\t\tthis.$formElement.on('submit',\tfunction\t(event)\t{ \t\t\t\t\t\tevent.preventDefault(); ...","The\tsubmit\thandler\tcallback\twill\tbe\tcalled\tany\ttime\tthe\tform\u2019s\tsubmit\tevent\tis\ttriggered in\tthe\tbrowser.\tWhen\tthat\thappens,\tyou\twant\tthe\tfn\tfunction\tto\tbe\tcalled. Call\tfn\tinside\tthe\tsubmit\thandler\tcallback\tin\tformhandler.js\tand\tpass\tit\tthe\tdata object\tthat\tcontains\tthe\tuser\tinput. ... \t\tFormHandler.prototype.addSubmitHandler\t=\tfunction\t(fn)\t{ \t\t\t\t... \t\t\t\t\t\tconsole.log(data); \t\t\t\t\t\tfn(data); \t\t\t\t}); \t\t}; ... Now,\twhen\ta\tFormHandler\tinstance\tis\tcreated,\tany\tcallback\tcan\tbe\tpassed\tto addSubmitHandler.\tFrom\tthen\ton,\twhen\tthe\tform\tis\tsubmitted,\tthe\tcallback\twill\tbe invoked\tand\twill\tbe\tpassed\twhatever\tdata\tthe\tuser\tentered\tinto\tthe\tform.","Using\tFormHandler In\tmain.js,\tyou\tneed\tto\tinstantiate\ta\tFormHandler\tinstance\tand\tpass\tit\tthe\tselector\tfor the\t<form>\telement:\t[data-coffee-order=\\\"form\\\"].\tCreate\ta\tvariable\tat\tthe\ttop\tof main.js\tfor\tthis\tselector\tso\tthat\tit\tcan\tbe\treused\tif\tneeded. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tFORM_SELECTOR\t=\t'[data-coffee-order=\\\"form\\\"]'; \t\tvar\tApp\t=\twindow.App; ... Next,\tcreate\ta\tlocal\tvariable\tcalled\tFormHandler\tand\tassign\tit\tto\tApp.FormHandler. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tFORM_SELECTOR\t=\t'[data-coffee-order=\\\"form\\\"]'; \t\tvar\tApp\t=\twindow.App; \t\tvar\tTruck\t=\tApp.Truck; \t\tvar\tDataStore\t=\tApp.DataStore; \t\tvar\tFormHandler\t=\tApp.FormHandler; \t\tvar\tmyTruck\t=\tnew\tTruck('ncc-1701',\tnew\tDataStore()); \t\t... At\tthe\tend\tof\tthe\tmain.js\tmodule,\tcall\tthe\tFormHandler\tconstructor\tand\tpass\tit\tthe FORM_SELECTOR\tvariable.\tThis\twill\tmake\tsure\tthat\tthe\tinstance\tof\tFormHandler\twill work\twith\tthe\tDOM\telement\tmatching\tthat\tselector.\tAssign\tthe\tinstance\tto\ta\tnew\tvariable called\tFormHandler. ... \t\tvar\tTruck\t=\tApp.Truck; \t\tvar\tDataStore\t=\tApp.DataStore; \t\tvar\tFormHandler\t=\tApp.FormHandler; \t\tvar\tmyTruck\t=\tnew\tTruck('ncc-1701',\tnew\tDataStore()); \t\twindow.myTruck\t=\tmyTruck; \t\tvar\tformHandler\t=\tnew\tFormHandler(FORM_SELECTOR); \t\tformHandler.addSubmitHandler(); \t\tconsole.log(formHandler); })(window); When\tyou\tsave\tyour\tcode\tand\treturn\tto\tthe\tbrowser,\tthe\tconsole\tshould\treport\tSetting submit\thandler\tfor\tform,\tshowing\tthat\taddSubmitHandler\twas\tcalled\twhen\tthe page\tloaded.\tHowever,\tif\tyou\tfill\tout\tand\tsubmit\tthe\tform,\tyou\twill\tget\tan\terror (Figure\t10.6).","Figure\t10.6\t\tCalling\taddSubmitHandler\ton\tpage\tload This\tis\tbecause\tyou\tdid\tnot\tpass\tanything\tto\taddSubmitHandler.\tYou\twill\tcorrect\tthat in\tthe\tnext\tsection. Registering\tcreateOrder\tas\ta\tsubmit\thandler You\twant\tcreateOrder\tto\tbe\tcalled\teach\ttime\ta\tsubmit\tevent\toccurs.\tBut\tyou\tcannot just\tpass\ta\treference\tto\tcreateOrder\tto\tformHandler.addSubmitHandler.\tThis is\tbecause\tcreateOrder\u2019s\towner\tchanges\twhen\tit\tis\tinvoked\tinside\tof\tthe\tevent\thandling callback.\tWith\ta\tdifferent\towner,\tthe\tvalue\tof\tthis\tinside\tthe\tbody\tof\tcreateOrder\twill not\tbe\tthe\tTruck\tinstance,\tthus\tcausing\tan\terror\twhen\tcreateOrder\truns. Instead,\tyou\twill\tpass\ta\tbound\treference\tto\tmyTruck.createOrder\tto formHandler.addSubmitHandler. Update\tformhandler.js\twith\tthis\tchange.\tMake\tsure\tto\tbind\tthe\tmethod\treference so\tthat\tits\towner\tis\tguaranteed\tto\tbe\tmyTruck. ... \t\twindow.myTruck\t=\tmyTruck; \t\tvar\tformHandler\t=\tnew\tFormHandler(FORM_SELECTOR); \t\tformHandler.addSubmitHandler(myTruck.createOrder.bind(myTruck)); \t\tconsole.log(formHandler); })(window); Could\tyou\thave\tadded\tbind\tto\tthe\tdefinition\tof\tthe\toriginal\tprototype\tmethod?\tWhen defining\tprototype\tmethods,\tyou\thave\taccess\tto\tthe\tinstance,\tbut\tonly\tinside\tthe\tmethod body.\tbind\trequires\tyou\tto\thave\ta\treference\tto\tthe\tintended\towner\tof\tthe\tinvocation\t\u2013\ta reference\tthat\tmust\tbe\tavailable\toutside\tof\tthe\tmethod\tbody.\tAs\tyou\thave\tno\tway\tof referencing\tthe\tinstance\tfrom\toutside\tthe\tmethod\tbody,\tyou\tcannot\tbind\tthe\toriginal prototype\tmethod.","Save\tand\tfill\tout\tyour\tform.\tAfter\tyou\tsubmit,\tyou\tshould\tbe\table\tto\tcall myTruck.printOrders\tand\tsee\tthat\tthe\tdata\tyou\tentered\tinto\tthe\tform\thas\tbeen\tadded\tto the\tlist\tof\tpending\torders,\tas\tshown\tin\tFigure\t10.7. Figure\t10.7\t\tcreateOrder\tis\tcalled\twhen\tthe\tform\tis\tsubmitted","UI\tEnhancements It\twould\tbe\tnice\tif\tthe\tform\twere\tcleared\tof\tits\told\tdata\tafter\tit\twas\tsubmitted,\tso\tthat\tthe user\tcould\timmediately\tstart\tentering\tthe\tnext\torder.\tResetting\tthe\tform\tis\tas\tsimple\tas calling\tthe\t<form>\telement\u2019s\treset\tmethod. Find\tthe\tFormHandler.prototype.addSubmitHandler\tmethod\tin\tformhandler.js.\tAt the\tend\tof\tthe\tthis.$formElement.on('submit'...)\tcallback,\tadd\ta\tcall\tto\tthe\tform\u2019s reset\tmethod: ... \t\tFormHandler.prototype.addSubmitHandler\t=\tfunction\t(fn)\t{ \t\t\t\tconsole.log('Setting\tsubmit\thandler\tfor\tform'); \t\t\t\tthis.$formElement.on('submit',\tfunction\t(event)\t{ \t\t\t\t\t\tevent.preventDefault(); \t\t\t\t\t\tvar\tdata\t=\t{}; \t\t\t\t\t\t$(this).serializeArray().forEach(function\t(item)\t{ \t\t\t\t\t\t\t\tdata[item.name]\t=\titem.value; \t\t\t\t\t\t\t\tconsole.log(item.name\t+\t'\tis\t'\t+\titem.value); \t\t\t\t\t\t}); \t\t\t\t\t\tconsole.log(data); \t\t\t\t\t\tfn(data); \t\t\t\t\t\tthis.reset(); \t\t\t\t}); \t\t}; ... Save\tand\tenter\tsome\tdata\tinto\tthe\tform.\tWhen\tyou\tsubmit\tthe\tform,\tyou\tshould\tsee\tthat the\tdata\tis\tcleared\tout. Finally,\tadd\tone\tlast\ttweak\tto\tthe\tUI.\tWhen\ta\tform\tfield\tis\tready\tfor\tinput,\tit\thas\tfocus,\tas you\tsaw\tin\tthe\tlast\tchapter.\tTo\tset\tthe\tfocus\ton\ta\tspecific\tform\tfield,\tyou\tcan\tcall\tits focus\tmethod.\t(The\tautofocus\tattribute\tyou\tadded\tto\tthe\tcoffee\torder\tfield\tonly\ttakes effect\twhen\tthe\tpage\tfirst\tloads.) You\tcan\tconveniently\taccess\tthe\tindividual\tform\tfields\tvia\tthe\tform\u2019s\telements\tproperty. The\telements\tproperty\tis\tan\tarray\tof\tthe\tform\u2019s\tfields,\twhich\tyou\tcan\trefer\tto\tby\ttheir indices,\tstarting\twith\t0. In\tformhandler.js,\tright\tafter\tthe\tcall\tto\tthis.reset\tin\tthe\tsubmit\thandler callback,\tinvoke\tthe\tfocus\tmethod\ton\tthe\tfirst\tfield. ... \t\tFormHandler.prototype.addSubmitHandler\t=\tfunction\t(fn)\t{ \t\t\t\tconsole.log('Setting\tsubmit\thandler\tfor\tform'); \t\t\t\tthis.$formElement.on('submit',\tfunction\t(event)\t{ \t\t\t\t\t\tevent.preventDefault(); \t\t\t\t\t\tvar\tdata\t=\t{}; \t\t\t\t\t\t$(this).serializeArray().forEach(function\t(item)\t{ \t\t\t\t\t\t\t\tdata[item.name]\t=\titem.value; \t\t\t\t\t\t\t\tconsole.log(item.name\t+\t'\tis\t'\t+\titem.value); \t\t\t\t\t\t}); \t\t\t\t\t\tconsole.log(data); \t\t\t\t\t\tfn(data); \t\t\t\t\t\tthis.reset(); \t\t\t\t\t\tthis.elements[0].focus(); \t\t\t\t}); \t\t}; ... CoffeeRun\tis\tnow\tjQuery-powered\tand\tcan\taccept\tuser\tinput!\tYou\thave\tbridged\tthe\tgap between\tyour\tHTML\tand\tyour\tJavaScript\tmodules.\tIn\tthe\tnext\tchapter,\tyou\twill\tcomplete the\tpicture\tby\tcreating\tinteractive\tDOM\telements\tbased\ton\tthe\tdata\tcaptured\tfrom\tthe form.","Bronze\tChallenge:\tSupersize\tIt Add\tanother\tsize\toption\tfor\tcoffee\torders\t\u2013\tone\twith\tan\tinspiringly\tlarge-sounding\tname, such\tas\t\u201cCoffee-zilla.\u201d Add\ta\tnew\torder\tusing\tthis\textra-large\tsize\tand\tcheck\tyour\tapplication\tdata\tin\tthe\tconsole to\tmake\tsure\tit\tis\tbeing\tsaved\tcorrectly.","Silver\tChallenge:\tShowing\tthe\tValue\tas\tthe\tSlider Changes Create\ta\thandler\tfor\tthe\tslider\u2019s\tchange\tevent.\tAs\tthe\tvalue\tof\tthe\tslider\tchanges,\tshow\tthe number\tnext\tto\tthe\tlabel\tfor\tthe\tslider. As\tan\textra\tchallenge,\tchange\tthe\tcolor\tof\tthe\tnumber\t(or\tthe\tlabel)\tto\treflect\tthe\tintensity of\tthe\tcaffeine\tstrength.\tUse\tgreen\tfor\tweaker\tcoffee,\tyellow\tfor\tregular\tstrength\tcoffee, and\tred\tfor\tvery\tstrong\tcoffee.","Gold\tChallenge:\tAdding\tAchievements When\tusers\tsubmit\tan\torder\tfor\tthe\tlargest,\tstrongest\tcoffee\twith\ta\tflavor\tshot,\tunlock\tan achievement:\tBring\tup\ta\tBootstrap\tmodal\tto\tinform\tthem\tof\ttheir\tamazing\tintensity\tand commitment\tto\tflavor.\tAsk\tthem\tif\tthey\twould\tlike\tto\tuse\ttheir\tachievement,\tand,\tif\tso, add\tan\tadditional\tform\tfield\tthat\tis\tonly\tvisible\twhen\ttheir\temail\taddress\tis\tentered\tin\tthe email\tfield.\tIt\tshould\tlet\tthem\tchoose\tone\tor\tmore\tpower-up\toptions\tfor\ttheir\tcoffee,\tlike time\ttravel,\tmind\treading,\tor\tbug-free\tcode. Refer\tto\tthe\tdocumentation\tat\tgetbootstrap.com\/j\u200b avascript\tfor\tinformation\ton how\tto\tinclude\tand\ttrigger\tBootstrap\u2019s\tmodal\tbehaviors.\t(You\twill\tneed\tto\tadd\ta\t<script> tag\tfrom\tcdnjs.com\tfor\tBootstrap\u2019s\tJavaScript\tcode.)","11\t From\tData\tto\tDOM In\tthe\tlast\tchapter,\tyou\tbuilt\tthe\tFormHandler\tmodule.\tIt\tserves\tas\ta\tbridge\tbetween\tthe form\tthat\tthe\tuser\tinteracts\twith\tand\tthe\trest\tof\tyour\tcode.\tBy\tintercepting\tits\tsubmit event,\tyou\tsupply\tthe\tuser\u2019s\tinput\tto\tyour\tTruck\tmodule,\twhich\tsaves\tit\tto\tits DataStore\tinstance. In\tthis\tchapter,\tyou\twill\tbuild\tthe\tother\tpiece\tof\tUI\tcode,\tthe\tCheckList\tmodule.\tLike the\tTruck\tmodule,\tit\twill\treceive\tdata\tfrom\tthe\tFormHandler,\tbut\tits\tjob\tis\tto\tadd\ta checklist\tof\tpending\torders\tto\tthe\tpage.\tWhen\ta\tchecklist\titem\tis\tclicked,\tthe\tCheckList will\tremove\tit\tfrom\tthe\tpage\tand\tsignal\tthe\tTruck\tto\tremove\tit\tfrom\tthe\tDataStore. Figure\t11.1\tshows\tCoffeeRun\tequipped\twith\tits\tchecklist\tof\tpending\torders. Figure\t11.1\t\tKeep\tthose\torders\tcoming! Setting\tUp\tthe\tChecklist You\twill\tcontinue\tto\tuse\tBootstrap\tclasses\tfor\tstyling\tyour\tform\telements.\tBegin\tin index.html\tby\tadding\ta\tpair\tof\t<div>\telements\twith\tthe\tBootstrap\tclass\tnames\tpanel, panel-default,\tand\tpanel-body,\tas\tyou\tdid\tfor\tyour\tcoffee\torder\tform.\tInside\tof\tthem, add\ta\theader\tand\tanother\t<div>\tthat\twill\thold\tthe\tactual\tchecklist\titems.\tThis\tmarkup","should\tbe\tadded\tafter\tthe\t<div>s\tthat\thold\tyour\tform. ... \t\t\t\t<header> \t\t\t\t\t\t<h1>CoffeeRun<\/h1> \t\t\t\t<\/header> \t\t\t\t<section> \t\t\t\t\t\t<div\tclass=\\\"panel\tpanel-default\\\"> \t\t\t\t\t\t\t\t<div\tclass=\\\"panel-body\\\"> \t\t\t\t\t\t\t\t\t\t<form\tdata-coffee-order=\\\"form\\\"> \t\t\t\t\t\t\t\t\t\t\t\t... \t\t\t\t\t\t\t\t\t\t<\/form> \t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t<\/div> \t\t\t\t\t\t<div\tclass=\\\"panel\tpanel-default\\\"> \t\t\t\t\t\t\t\t<div\tclass=\\\"panel-body\\\"> \t\t\t\t\t\t\t\t\t\t<h4>Pending\tOrders:<\/h4> \t\t\t\t\t\t\t\t\t\t<div\tdata-coffee-order=\\\"checklist\\\"> \t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t<\/div> \t\t\t\t<\/section> ... As\tbefore,\tyou\tadded\t<div>s\tto\tcarry\tthe\tstyling\tprovided\tby\tBootstrap.\tThe\tmain\tpart\tof your\tchecklist\tis\tthe\t[data-coffee-order=\\\"checklist\\\"]\telement.\tIt\twill\tbe\tthe\ttarget\tfor the\tJavaScript\tthat\tcreates\tan\tindividual\tcoffee\torder\tchecklist\titem\tand\tadds\tit\tto\tthe DOM. Save\tindex.html,\tstart\tbrowser-sync,\tand\tmake\tsure\tCoffeeRun\tshows\tan\tempty Pending\tOrders\tarea\t(Figure\t11.2). Figure\t11.2\t\tAfter\tadding\tthe\tmarkup\tfor\tthe\tchecklist\titems Now\tyou\tare\tready\tto\tdive\tback\tinto\tthe\tJavaScript.","Creating\tthe\tCheckList\tModule Create\ta\tnew\tfile\tin\tyour\tscripts\tfolder\tcalled\tchecklist.js\tand\tadd\ta\tlink\tto\tit\tin index.html: ... \t\t\t\t<script\tsrc=\\\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jquery\/2.1.4\/jquery.js\\\" \t\t\t\t\t\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/checklist.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/formhandler.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/datastore.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/truck.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/main.js\\\"\tcharset=\\\"utf-8\\\"><\/script> ... Save\tindex.html.\tIn\tchecklist.js,\tadd\tthe\tstandard\tmodule\tcode\tusing\tan\tIIFE. Import\tthe\tApp\tnamespace\tand\tjQuery,\tassigning\teach\tto\ta\tlocal\tvariable.\tCreate\ta constructor\tfor\tCheckList,\tmaking\tsure\tto\tconfirm\tthat\tthere\tis\ta\tselector\tpassed\tin\tand that\tthe\tselector\tmatches\tat\tleast\tone\telement\tin\tthe\tDOM.\tAt\tthe\tend\tof\tthe\tIIFE,\texport the\tCheckList\tconstructor\tas\tpart\tof\tthe\tApp\tnamespace. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tvar\t$\t=\twindow.jQuery; \t\tfunction\tCheckList(selector)\t{ \t\t\t\tif\t(!selector)\t{ \t\t\t\t\t\tthrow\tnew\tError('No\tselector\tprovided'); \t\t\t\t} \t\t\t\tthis.$element\t=\t$(selector); \t\t\t\tif\t(this.$element.length\t===\t0)\t{ \t\t\t\t\t\tthrow\tnew\tError('Could\tnot\tfind\telement\twith\tselector:\t'\t+\tselector); \t\t\t\t} \t\t} \t\tApp.CheckList\t=\tCheckList; \t\twindow.App\t=\tApp; })(window); The\tCheckList\tmodule\twill\tneed\tthree\tmethods\tto\tdo\tits\twork.\tOne\twill\tcreate\ta checklist\titem,\tincluding\tthe\tcheckbox\tand\tthe\ttext\tdescription.\tThink\tof\tthis\tgroup\tof elements\tas\ta\trow\tin\ta\ttable. Another\tmethod\twill\tremove\ta\trow\tfrom\tthe\ttable.\tThe\tthird\tmethod\twill\tadd\ta\tlistener\tfor click\tevents,\tso\tthat\tyour\tcode\tknows\twhen\tto\tremove\ta\trow. The\tfirst\tmethod\tyou\twill\ttackle\tis\tthe\tone\tto\tcreate\ta\trow\tfor\ta\tnew\torder.\tFigure\t11.3 shows\thow\tCheckList\twill\tadd\tchecklist\titems\tto\tthe\tpage\twhen\tthe\torder\tform\tis submitted.","Figure\t11.3\t\tOrder\tof\tevents\twhen\tthe\torder\tform\tis\tsubmitted","Creating\tthe\tRow\tConstructor You\tcannot\tcreate\tthe\tmarkup\tin\tindex.html\tfor\tthe\tchecklist\titems,\tbecause\tthey\tneed to\tbe\tadded\tafter\tthe\tpage\thas\talready\tbeen\trendered,\tin\tresponse\tto\tform\tsubmissions. Instead,\tyou\twill\tadd\ta\tRow\tconstructor\tto\tthe\tCheckList\tmodule. The\tRow\tconstructor\twill\tbe\tin\tcharge\tof\tcreating\tall\tthe\tDOM\telements\tnecessary\tto represent\ta\tsingle\tcoffee\torder,\tincluding\tthe\tcheckbox\tand\ttext\tdescription.\tBut\tthe\tRow constructor\twill\tnot\tbe\texported\tto\tthe\tApp\tnamespace.\tIt\twill\tonly\tbe\tused\tinternally\tby one\tof\tthe\tCheckList.prototype\tmethods. Add\tthe\tRow\tconstructor\tin\tchecklist.js,\tjust\tbefore\tthe\tApp.CheckList\t= CheckList;\tstatement.\tIt\tshould\taccept\tan\targument\tcalled\tcoffeeOrder\tthat\twill\tbe\tthe same\tdata\tthat\tis\tsent\tto\tTruck.prototype.createOrder. ... \t\t\t\tthis.$element\t=\t$(selector); \t\t\t\tif\t(this.$element.length\t===\t0)\t{ \t\t\t\t\t\tthrow\tnew\tError('Could\tnot\tfind\telement\twith\tselector:\t'\t+\tselector); \t\t\t\t} \t\t} \t\tfunction\tRow(coffeeOrder)\t{ \t\t\t\t\/\/\tConstructor\tcode\twill\tgo\there \t\t} \t\tApp.CheckList\t=\tCheckList; \t\twindow.App\t=\tApp; })(window); Creating\tDOM\telements\twith\tjQuery Your\tRow\tconstructor\twill\tuse\tjQuery\tto\tbuild\tDOM\telements.\tYou\twill\tdeclare\tvariables for\tthe\tindividual\telements\tthat\tmake\tup\ta\tchecklist\titem.\tThen\tthe\tconstructor\twill append\tthem\ttogether\tinto\ta\tsubtree\tof\tDOM\telements,\tas\tshown\tin\tFigure\t11.4.\tThe CheckList\twill\ttake\tthat\tsubtree\tand\tattach\tit\tto\tthe\tpage\u2019s\tDOM\ttree\tas\ta\tchild\tof\tthe [data-coffee-order=\\\"checklist\\\"]\telement.","Figure\t11.4\t\tCheckList\tcreates\ta\trow\tand\tappends\tits\tDOM\telements (The\t\u201c[39x]\u201d\tin\tthe\torder\tdescription\trepresents\tthe\tcaffeine\tstrength.) The\tDOM\tsubtree\tcreated\tby\tthe\tRow\tconstructor\tin\tFigure\t11.4\tis\tthe\tequivalent\tof\tthe following\tmarkup: <div\tdata-coffee-order=\\\"checkbox\\\"\tclass=\\\"checkbox\\\"> \t\t<label> \t\t\t\t<input\ttype=\\\"checkbox\\\"\tvalue=\\\"[email protected]\\\"> \t\t\t\ttall\tmocha\ticed\tcoffee,\t([email protected])\t[39x] \t\t<\/label> <\/div> A\t<div>\twith\ta\tcheckbox\tclass\tis\tused\tto\thouse\tyour\t<label>\tand\tan\t<input>\telement. The\tcheckbox\tclass\twill\tapply\tthe\tappropriate\tBootstrap\tstyles\tto\tthe\t<div>.\tThe\tdata- coffee-order\tattribute\twill\tbe\tused\tin\tyour\tJavaScript\twhen\tyou\tneed\tto\ttrigger\tthe\tclick action\ton\tthe\tcheckbox. Note\tthat\tthe\ttype\tattribute\tof\tyour\t<input>\tis\talso\tcheckbox.\tThis\ttells\tthe\tbrowser\tto draw\tthe\tinput\tas\ta\tcheckbox\tform\telement.\tA\tplain\ttext\tdescription\tof\tthe\torder\tcomes right\tafter\tthe\t<input>.\tThe\t<label>\twraps\tboth\tthe\tcheckbox\tinput\tand\tthe\tplain\ttext description.\tThis\tturns\tthe\ttext\tand\tthe\tinput\tinto\ta\tclick\ttarget\tfor\tthe\tcheckbox. You\twill\tcreate\tthe\t<label>,\t<div>,\tand\t<input>\telements\tone\tat\ta\ttime.\tThen\tyou\twill manually\tplace\tthe\telements\tinside\tof\tone\tanother\tto\tcreate\ta\tDOM\tsubtree\tthat\tyou\twill attach\tto\tthe\tlive\tDOM\t(the\tDOM\ttree\tcurrently\tshown\ton\tthe\tpage).\tYou\twill\talso\tcreate a\tstring\tthat\tholds\tthe\ttext\tdescription\tof\tthe\torder,\tlike\t\u201ctall\tmocha\ticed\tcoffee, ([email protected])\t[39x].\u201d","To\tcreate\tthese\telements,\tyou\twill\tuse\tjQuery\u2019s\t$\tfunction.\tUp\tto\tnow,\tyou\tonly\tused\tthe $\tfunction\tto\tselect\telements\tfrom\tthe\tDOM,\tbut\tit\tcan\talso\tbe\tused\tto\tcreate\tthem. First,\tyou\tare\tgoing\tto\tcreate\tthe\t<div>\tby\tcalling\tthe\t$\tfunction\tin\tthe\tRow\tconstructor\tin checklist.js.\tPass\tit\ttwo\targuments\tdescribing\tthe\tDOM\telement\tyou\twant\tit\tto create.\tMake\tthe\tfirst\targument\ta\tstring\twith\tthe\tHTML\ttag\tof\tthe\tDOM\telement,\tin\tthis case\t'<div><\/div>'.\tMake\tthe\tsecond\targument\tan\tobject\tthat\tspecifies\tthe\tattributes\tthat jQuery\tshould\tadd\tto\tthe\t<div>.\tThe\tkey\/value\tpairs\tof\tthe\tobject\tliteral\tare\ttranslated\tinto the\tattributes\tof\tthe\tnew\telement. The\tresult\tis\ta\tDOM\telement\tcreated\tby\tjQuery\tthat\tyou\twill\tassign\tto\ta\tnew\tvariable called\t$div.\tThis\twill\tnot\tbe\tan\tinstance\tvariable\t(that\tis,\tit\tis\tjust\t$div\tand\tnot this.$div).\tIt\tis\tprefixed\twith\tthe\t$\tto\tdenote\tthat\tit\tis\tnot\ta\tplain\tDOM\telement,\tbut\tone that\tjQuery\tcreated\ta\treference\tto. Make\tit\tso\tin\tchecklist.js. ... \t\tfunction\tRow(coffeeOrder)\t{ \t\t\t\t\/\/\tConstructor\tcode\twill\tgo\there \t\t\t\tvar\t$div\t=\t$('<div><\/div>',\t{ \t\t\t\t\t\t'data-coffee-order':\t'checkbox', \t\t\t\t\t\t'class':\t'checkbox' \t\t\t\t}); \t\t} ... Notice\tthat\tyour\ttwo\tproperty\tnames\tare\tin\tsingle\tquotation\tmarks.\tYou\tmight\tassume from\tthis\tthat\tyou\tshould\talways\tuse\tsingle\tquotes\taround\tproperty\tnames\twhen\tcreating\ta DOM\telement\tusing\tjQuery,\tbut\tactually\tthat\tis\tnot\tthe\tcase.\tProperty\tnames\tthat\thave special\tcharacters\t(like\tthe\tdash)\tneed\tto\tbe\tin\tquotes,\totherwise\tit\tis\tconsidered\ta\tsyntax error.\tValid\tcharacters\tthat\tcan\tbe\tused\tin\ta\tproperty\tname\t(or\ta\tvariable\tname)\twithout single\tquotes\tare\tthe\tletters\tof\tthe\talphabet,\tnumerical\tdigits,\tthe\tunderscore\t(_),\tand\tthe dollar\tsign\t($). 'class'\tis\tin\tsingle\tquotes\tbecause\t\u201cclass\u201d\tis\ta\tJavaScript-reserved\tword,\tso\tsingle\tquotes are\tneeded\tto\tprevent\tthe\tbrowser\tfrom\treading\tit\tas\tJavaScript\t(which\twould\talso\tresult in\ta\tsyntax\terror). Next,\tcreate\tthe\t<label>\telement\tin\tchecklist.js\twith\tthe\t$\tfunction\tbut\twithout\tan object\targument.\tIt\tdoes\tnot\tneed\tany\textra\tattributes. ... \t\tfunction\tRow(coffeeOrder)\t{ \t\t\t\tvar\t$div\t=\t$('<div><\/div>',\t{ \t\t\t\t\t\t'data-coffee-order':\t'checkbox', \t\t\t\t\t\t'class':\t'checkbox' \t\t\t\t}); \t\t\t\tvar\t$label\t=\t$('<label><\/label>'); \t\t} ... Now,\tcreate\tthe\t<input>\telement\tfor\tthe\tcheckbox\tby\tcalling\tthe\t$\tfunction\tand\tpassing\tit the\tHTML\tfor\tan\t<input>\ttag.\tFor\tthe\tsecond\targument,\tspecify\tthat\tthe\ttype\tshould\tbe\ta checkbox\tand\tthat\tthe\tvalue\tshould\tbe\tthe\temail\taddress\tof\tthe\tcustomer.\tBecause\tnone\tof these\tproperty\tnames\tuse\tspecial\tcharacters,\tyou\tdo\tnot\tneed\tto\tput\tthem\tin\tsingle\tquotes. ... \t\tfunction\tRow(coffeeOrder)\t{ \t\t\t\tvar\t$div\t=\t$('<div><\/div>',\t{ \t\t\t\t\t\t'data-coffee-order':\t'checkbox', \t\t\t\t\t\t'class':\t'checkbox' \t\t\t\t});","var\t$label\t=\t$('<label><\/label>'); \t\t\t\tvar\t$checkbox\t=\t$('<input><\/input>',\t{ \t\t\t\t\t\ttype:\t'checkbox', \t\t\t\t\t\tvalue:\tcoffeeOrder.emailAddress \t\t\t\t}); \t\t} ... By\tsetting\tthe\tvalue\tto\tthe\tcustomer\u2019s\temail\taddress,\tyou\tare\tassociating\tthe\tcheckbox with\tthe\tcustomer\u2019s\tcoffee\torder.\tLater,\twhen\tyou\tadd\tthe\tclick\thandler,\tyou\tcan\tidentify which\tcoffee\torder\twas\tclicked\tbased\ton\tthe\temail\taddress\tin\tthe\tvalue\tattribute. The\tlast\tthing\tto\tcreate\tis\tthe\ttext\tdescription\tthat\twill\tbe\tdisplayed\tnext\tto\tthe\tcheckbox. You\twill\tbuild\ta\tstring\tfor\tthis\tby\tconcatenating\tthe\tpieces\tusing\tthe\t+=\toperator. Create\ta\tvariable\tcalled\tdescription\tin\tchecklist.js.\tSet\tit\tto\tthe\tsize\tproperty of\tthe\torder,\tthen\tadd\ta\tcomma\tand\ta\tspace.\tIf\ta\tflavor\twas\tprovided,\tconcatenate\tit\tusing +=.\tThen\tconcatenate\tthe\tcoffee,\temailAddress,\tand\tstrength\tvalues.\tThe\temailAddress should\tbe\twrapped\tin\tparentheses\tand\tthe\tstrength\tshould\tbe\tin\tbrackets\tand\tfollowed\tby the\tletter\t\u201cx.\u201d\t(The\tparentheses\tand\tbrackets\tare\tnot\tfor\tsyntactic\tpurposes,\tjust\tfor formatting\tthe\ttext.) ... \t\tfunction\tRow(coffeeOrder)\t{ \t\t\t\t... \t\t\t\tvar\t$checkbox\t=\t$('<input><\/input>',\t{ \t\t\t\t\t\ttype:\t'checkbox', \t\t\t\t\t\tvalue:\tcoffeeOrder.emailAddress \t\t\t\t}); \t\t\t\tvar\tdescription\t=\tcoffeeOrder.size\t+\t'\t'; \t\t\t\tif\t(coffeeOrder.flavor)\t{ \t\t\t\t\t\tdescription\t+=\tcoffeeOrder.flavor\t+\t'\t'; \t\t\t\t} \t\t\t\tdescription\t+=\tcoffeeOrder.coffee\t+\t',\t'; \t\t\t\tdescription\t+=\t'\t('\t+\tcoffeeOrder.emailAddress\t+\t')'; \t\t\t\tdescription\t+=\t'\t['\t+\tcoffeeOrder.strength\t+\t'x]'; \t\t} ... The\t+=\tconcatenation\toperator\tdoes\taddition\tand\tassignment\tin\tone\tstep.\tThat\tmeans\tthat the\tfollowing\ttwo\tlines\tof\tcode\tare\tequivalent: description\t+=\tcoffeeOrder.flavor\t+\t'\t'; description\t=\tdescription\t+\tcoffeeOrder.flavor\t+\t'\t'; You\tnow\thave\tall\tthe\tindividual\tparts\tof\tthe\tchecklist\titem\tand\tare\tready\tto\tappend\tthem to\tone\tanother\t(Figure\t11.5).","Figure\t11.5\t\tAssembling\tthe\tindividual\tDOM\telements\tinto\ta\tsubtree You\twill\tdo\tthis\tin\tthree\tsteps: 1.\t Append\tthe\t$checkbox\tto\tthe\t$label 2.\t Append\tthe\tdescription\tto\tthe\t$label 3.\t Append\tthe\t$label\tto\tthe\t$div More\tgenerally,\tyou\twill\tbuild\tthe\tsubtree\tby\tworking\tfrom\tleft\tto\tright,\tbottom\tto\ttop.","This\tapproach\tis\tsimilar\tto\thow\tyou\tdeveloped\tyour\tCSS\tfor\tOttergram\tin\tChapter\t3,\tby beginning\twith\tthe\tsmallest,\tinnermost\telements\tand\tworking\tyour\tway\tup. In\tchecklist.js,\tuse\tthe\tjQuery\tappend\tmethod\tto\tconnect\tthe\telements\ttogether. This\tmethod\taccepts\teither\ta\tDOM\telement\tor\ta\tjQuery-wrapped\tcollection\tand\tadds\tit\tas a\tchild\telement. ... \t\tfunction\tRow(coffeeOrder)\t{ \t\t\t\t... \t\t\t\tdescription\t+=\tcoffeeOrder.coffee\t+\t',\t'; \t\t\t\tdescription\t+=\t'\t('\t+\tcoffeeOrder.emailAddress\t+\t')'; \t\t\t\tdescription\t+=\t'\t['\t+\tcoffeeOrder.strength\t+\t'x]'; \t\t\t\t$label.append($checkbox); \t\t\t\t$label.append(description); \t\t\t\t$div.append($label); \t\t} ... Your\tRow\tconstructor\tcan\tnow\tcreate\tand\tassemble\tthe\tsubtree\tof\telements\tusing\tthe coffee\torder\tdata\tpassed\tin.\tHowever,\tbecause\tRow\twill\tbe\tused\tas\ta\tconstructor\tand\tnot as\ta\tregular\tfunction,\tit\tcannot\tsimply\treturn\tthis\tsubtree.\t(In\tfact,\tconstructors\tshould never\thave\ta\treturn\tstatement;\tJavaScript\tautomatically\treturns\ta\tvalue\tfor\tyou\twhen\tyou use\tthe\tkeyword\tnew\twith\ta\tconstructor.) Instead,\tmake\tthe\tsubtree\tavailable\tas\ta\tproperty\tof\tthe\tinstance\tby\tassigning\tit\tto this.$element\tin\tchecklist.js.\t(This\tname\twas\tchosen\tjust\tto\tfollow\tthe convention\tused\twith\tyour\tother\tconstructors;\tit\tdoes\tnot\thave\tany\tspecial\tmeaning\tby itself.) ... \t\tfunction\tRow(coffeeOrder)\t{ \t\t\t\t... \t\t\t\t$label.append($checkbox); \t\t\t\t$label.append(description); \t\t\t\t$div.append($label); \t\t\t\tthis.$element\t=\t$div; \t\t} ... The\tRow\tconstructor\tis\tready\tfor\twork.\tIt\tcan\tbuild\tup\tthe\tDOM\tsubtree\tnecessary\tto represent\tan\tindividual\tcoffee\torder\twith\ta\tcheckbox.\tIt\tholds\ton\tto\tthat\tDOM representation\tin\tan\tinstance\tvariable.","Creating\tCheckList\tRows\ton\tSubmit Next,\tyou\twill\tadd\ta\tmethod\tto\tCheckList\tthat\twill\tuse\tthe\tRow\tconstructor\tto\tcreate Row\tinstances.\tIt\twill\tappend\teach\tRow\tinstance\u2019s\t$element\tto\tthe\tlive\tDOM\ton\tthe page. In\tchecklist.js,\tadd\ta\tmethod\tto\tCheckList.prototype\tcalled\taddRow.\tIt\tshould accept\tan\targument\tcalled\tcoffeeOrder,\twhich\twill\tbe\tan\tobject\tthat\tcontains\tall\tof\tthe data\tfor\ta\tsingle\tcoffee\torder. In\tthis\tnew\tmethod,\tcreate\ta\tnew\tRow\tinstance\tby\tcalling\tthe\tRow\tconstructor\tand\tpassing it\tthe\tcoffeeOrder\tobject.\tAssign\tthe\tnew\tinstance\tto\tthe\tvariable\trowElement.\tThen, append\tthe\trowElement\u2019s\t$element\tproperty\t(which\tcontains\tthe\tDOM\tsubtree)\tto the\tCheckList\tinstance\u2019s\t$element\tproperty\t(which\tis\ta\treference\tto\tthe\tcontainer\tfor the\tchecklist\titems). ... \t\tfunction\tCheckList(selector)\t{ \t\t\t\t... \t\t} \t\tCheckList.prototype.addRow\t=\tfunction\t(coffeeOrder)\t{ \t\t\t\t\/\/\tCreate\ta\tnew\tinstance\tof\ta\trow,\tusing\tthe\tcoffee\torder\tinfo \t\t\t\tvar\trowElement\t=\tnew\tRow(coffeeOrder); \t\t\t\t\/\/\tAdd\tthe\tnew\trow\tinstance's\t$element\tproperty\tto\tthe\tchecklist \t\t\t\tthis.$element.append(rowElement.$element); \t\t}; \t\tfunction\tRow(coffeeOrder)\t{ \t\t\t\t... This\tis\tall\tyou\tneed\tto\tdo\tto\tadd\tthe\tRow\u2019s\tDOM\tsubtree\tto\tthe\tpage.\tSave checklist.js. In\tmain.js,\tadd\ta\tvariable\tfor\tthe\tselector\tthat\tmatches\tthe\tentire\tchecklist\tarea,\t[data- coffee-order=\\\"checklist\\\"].\tThen,\timport\tthe\tCheckList\tmodule\tfrom\tthe\tApp namespace\tto\ta\tlocal\tvariable,\tCHECKLIST_SELECTOR. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tFORM_SELECTOR\t=\t'[data-coffee-order=\\\"form\\\"]'; \t\tvar\tCHECKLIST_SELECTOR\t=\t'[data-coffee-order=\\\"checklist\\\"]'; \t\tvar\tApp\t=\twindow.App; \t\tvar\tTruck\t=\tApp.Truck; \t\tvar\tDataStore\t=\tApp.DataStore; \t\tvar\tFormHandler\t=\tApp.FormHandler; \t\tvar\tCheckList\t=\tApp.CheckList; \t\tvar\tmyTruck\t=\tnew\tTruck('ncc-1701',\tnew\tDataStore()); ... Now\tyou\tcan\tinstantiate\ta\tCheckList\tinstance\tto\tadd\tchecklist\titems. You\tmight\tbe\ttempted\tto\tjust\tadd\tanother\tcall\tto formHandler.addSubmitHandler,\tbut\tthis\twould\tnot\twork\tthe\tway\tyou\tmight expect.\tWhy\tnot?\tEach\ttime\tyou\tcall\taddSubmitHandler,\tit\tregisters\ta\tnew\tcallback that\tresets\tthe\tform\t(by\tcalling\tthis.reset). Consider\tthe\tfollowing\tcode: ... \/\/\tInstantiate\ta\tnew\tCheckList var\tcheckList\t=\tnew\tCheckList(CHECKLIST_SELECTOR); var\tformHandler\t=\tnew\tFormHandler(FORM_SELECTOR); formHandler.addSubmitHandler(myTruck.createOrder.bind(myTruck));","\/\/\tThis\twill\tnot\tdo\twhat\tyou\twant! formHandler.addSubmitHandler(checkList.addRow.bind(checkList)); ... This\tcode\tregisters\ttwo\tcallbacks\tthat\twill\trun\twhen\tthe\tform\tis\tsubmitted.\tAfter\tthe\tfirst submit\thandler\t(myTruck.createOrder)\tis\tcalled,\tthe\tform\tgets\treset.\tWhen\tthe second\tsubmit\thandler\t(checkList.addRow)\tis\tcalled,\tthere\tis\tno\tinformation\tleft\tin the\tform.\tThe\tresult\tis\tthat\tthe\tdata\tis\tadded\tto\tthe\tDataStore,\tbut\ta\tchecklist\titem\tdoes not\tget\tadded\tto\tthe\tpage. To\tget\taround\tthis,\tyou\tneed\tto\tpass\ta\tsingle\tanonymous\tfunction\tto formHandler.addSubmitHandler\tand\thave\tthat\tanonymous\tfunction\tcall\tboth myTruck.createOrder\tand\tcheckList.addRow. Also,\teach\tof\tthese\tmethods\tneeds\tto\tbe\tbound\tto\ta\tspecific\tinstance\t(meaning\tits\tthis keyword\tneeds\tto\tbe\tset).\tYou\thave\tbeen\tusing\tbind\tto\tset\tthe\tvalue\tof\tthis,\tbut\tyou\twill use\ta\tdifferent\ttechnique\there. Manipulating\tthis\twith\tcall The\tcall\tmethod\tworks\tsimilarly\tto\tbind\tto\tset\tthe\tvalue\tof\tthis.\tThe\tdifference between\tthe\ttwo\tis\tthat\twhile\tbind\treturns\ta\tnew\tversion\tof\tthe\tfunction\tor\tmethod,\tit does\tnot\tinvoke\tit.\tcall\tactually\tinvokes\tthe\tfunction\tor\tmethod\tand\tallows\tyou\tto\tpass in\tthe\tvalue\tof\tthis\tas\tthe\tfirst\targument.\t(If\tyou\tneed\tto\tpass\tany\tother\targuments\tto\tthe function,\tyou\tjust\tadd\tthem\tto\tthe\targument\tlist.)\tcall\truns\tthe\tbody\tof\tthe\tfunction\tand returns\tany\tvalue\tthat\twould\tnormally\tbe\treturned. You\tneed\tto\tuse\tcall\tinstead\tof\tbind\there\tbecause\tyou\tneed\tto\tinvoke myTruck.createOrder\tand\tcheckList.addRow\tin\taddition\tto\tsetting\tthe\tvalue of\tthis. In\tmain.js,\tremove\tthe\texisting\tinvocation\tof formHandler.addSubmitHandler.\tAdd\ta\tnew\tcall\tto formHandler.addSubmitHandler\tand\tpass\tit\tan\tanonymous\tfunction\tthat\texpects a\tsingle\targument,\tdata.\tInside\tthe\tanonymous\tfunction,\tuse\tthe\tcall\tmethods\tof myTruck.createOrder\tand\tcheckList.addRow\tto\tset\tthe\tvalue\tof\tthis,\tpassing the\tdata\tobject\tas\tthe\tsecond\targument. ... \t\tvar\tmyTruck\t=\tnew\tTruck('ncc-1701',\tnew\tDataStore()); \t\twindow.myTruck\t=\tmyTruck; \t\tvar\tcheckList\t=\tnew\tCheckList(CHECKLIST_SELECTOR); \t\tvar\tformHandler\t=\tnew\tFormHandler(FORM_SELECTOR); \t\tformHandler.addSubmitHandler(myTruck.createOrder.bind(myTruck)); \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfunction\t(data)\t{ \t\t\t\tconsole.log(formHandler); \t\t\t\tmyTruck.createOrder.call(myTruck,\tdata); \t\t\t\tcheckList.addRow.call(checkList,\tdata); \t\t}); })(window); You\thave\tcreated\ta\tsingle\tsubmit\thandler\tfunction\tthat\tinvokes\tboth\tcreateOrder\tand addRow.\tWhen\tit\tinvokes\tthem,\tit\tpasses\tthe\tcorrect\tvalue\tof\tthis\tand\tthe\tdata\tfrom\tthe form. Save\tyour\tchanges\tand\ttry\tout\tyour\tchecklist\tfunctionality\tin\tthe\tbrowser\tby\tentering","some\tdata\tand\tsubmitting\tthe\tform.\tWhen\tyou\tsubmit\teach\torder,\tyou\twill\tsee\tit\tadded\tto the\tPending\tOrders\tchecklist,\tas\tin\tFigure\t11.6. Figure\t11.6\t\tSubmitting\tthe\tform\tadds\tan\titem\tto\tthe\tchecklist","Delivering\tan\tOrder\tby\tClicking\ta\tRow You\tare\talmost\tthere!\tCoffeeRun\u2019s\tusers\tcan\tfill\tout\tthe\tform\tto\tadd\torders.\tWhen\tthey submit\tthe\tform,\tit\tadds\tthe\torder\tinformation\tto\tthe\tapplication\u2019s\tdatabase\tand\tdraws\ta checklist\titem\tfor\tthe\torder. Next,\tusers\tshould\tbe\table\tto\tcheck\toff\tthe\tchecklist\titems.\tWhen\ta\tchecklist\titem\tis clicked,\tmeaning\tthat\tthe\torder\thas\tbeen\tdelivered,\tthe\torder\tinformation\tshould\tbe deleted\tfrom\tthe\tdatabase\tand\tthe\tchecklist\titem\tshould\tbe\tremoved\tfrom\tthe\tpage. Figure\t11.7\tshows\tthis\tprocess. Figure\t11.7\t\tSequence\tdiagram:\tclicking\ta\tchecklist\titem First,\tyou\twill\tcreate\tthe\tfunctionality\tfor\tremoving\tthe\tchecklist\titem\tfrom\tthe\tpage. Creating\tthe\tCheckList.prototype.removeRow\tmethod When\tyou\tcreate\ta\tRow,\tthe\tvalue\tof\tthe\t<input>\tis\tset\tto\tthe\tcustomer\u2019s\temail\taddress. removeRow\twill\tuse\tthe\temail\taddress\targument\tto\tfind\tthe\tright\tCheckList\titem\tto remove\tfrom\tthe\tUI.\tIt\twill\tdo\tthat\tby\tcreating\tan\tattribute\tselector\tto\tfind\tthe\t<input> whose\tvalue\tattribute\tmatches\tthe\temail\taddress. When\tit\thas\tfound\tthe\tmatching\telement,\tit\twill\tmove\tup\tthe\tDOM\tuntil\tit\tfinds\tthe [data-coffee-order=\\\"checkbox\\\"]. This\tis\tthe\t<div>\tthat\twraps\taround\tall\tof\tthe\telements\tthat\tare\tpart\tof\ta\trow.\tFinally,\twith that\t<div>\tselected\tusing\tjQuery,\tits\t.remove\tmethod\tcan\tbe\tcalled,\tremoving\tthe element\tfrom\tthe\tDOM\tand\talso\tcleaning\tup\tany\tevent\tlisteners\tthat\twere\tattached\tto\tany element\tin\tthat\tDOM\tsubtree. Add\tthe\tremoveRow\tmethod\tin\tchecklist.js\tand\tspecify\tan\temailAddress parameter.\tUse\tthe\t$element\tinstance\tproperty\tto\tsearch\tfor\tany\tdescendant\telements whose\tvalue\tattribute\tmatches\tthe\temail\tparameter.\tFrom\tthat\tmatching\telement,\tadd\ta call\tto\tclosest\tto\tsearch\tfor\tan\tancestor\twhose\tdata-coffee-order\tattribute\tis\tequal\tto \\\"checkbox\\\".\tFinally,\tcall\tremove\ton\tthat\telement.\t(You\twill\tnotice\tsome\tnew\tsyntax\tin this\tcode,\twhich\twe\twill\texplain\tafter\tyou\tenter\tit.) ... \t\tCheckList.prototype.addRow\t=\tfunction\t(coffeeOrder)\t{ \t\t\t\t...","}; \t\tCheckList.prototype.removeRow\t=\tfunction\t(email)\t{ \t\t\t\tthis.$element \t\t\t\t\t\t.find('[value=\\\"'\t+\temail\t+\t'\\\"]') \t\t\t\t\t\t.closest('[data-coffee-order=\\\"checkbox\\\"]') \t\t\t\t\t\t.remove(); \t\t}; \t\tfunction\tRow(coffeeOrder)\t{ \t\t\t\t... Here,\tyou\thave\tchained\tseveral\tmethod\tcalls\ttogether.\tjQuery\tis\tdesigned\tso\tthat\tyou\tcan write\tmultiple\tmethod\tcalls\tfor\tan\tobject\tlike\ta\tlist\tof\tsteps.\tYou\tonly\tinclude\tthe semicolon\tat\tthe\tend\tof\tthe\tvery\tlast\tmethod\tcall. The\trequirement\tfor\tchaining\tis\tthat\ta\tmethod\tmust\treturn\ta\tjQuery-wrapped\tselection\tin order\tto\thave\tanother\tmethod\tcall\tchained\tto\tit.\tfind\treturns\ta\tjQuery-wrapped\tselection, as\tdoes\tclosest.\tThis\tallows\tyou\tto\tchain\tthe\tthree\tmethod\tcalls\ttogether. Notice\tthat\tyou\tused\tthis.$element.find.\tThis\tdoes\ta\tscoped\tselection:\tInstead\tof searching\tthe\tentire\tDOM,\tit\tonly\tsearches\tthe\tdescendants\tof\tthe\tchecklist,\twhich\tyou have\ta\treference\tto\twith\tthis.$element. Removing\toverwritten\tentries Save\tyour\tfile\tand\tswitch\tto\tthe\tbrowser.\tUsing\tyour\tform,\tenter\ttwo\torders\tfor\tthe\tsame email\taddress.\tMake\tthe\tcoffee\tfor\tthe\tfirst\t\u201corder\t1\u201d\tand\tfor\tthe\tsecond\t\u201corder\t2.\u201d\tAfter submitting\tboth\torders,\tcall\tmyTruck.printOrders\tin\tthe\tconsole.\tFigure\t11.8\tshows the\tresult. Figure\t11.8\t\tOrders\tfor\tsame\temail\taddress\tremain\tin\tUI You\tdecided\tearly\ton\tto\tallow\tonly\tone\topen\torder\tper\tcustomer.\tBecause\tyou\tare\tusing\ta simple\tkey\/value\tstore\tfor\tyour\tdata,\tany\tsubsequent\torders\tfor\tthe\tsame\tcustomer\temail address\toverwrite\tthe\texisting\tone.\tSo,\tas\tthe\tconsole\tshows,\t\u201corder\t2\u201d\tis\tthe\tonly\tpending order.\t\u201cOrder\t1\u201d\thas\tbeen\toverwritten. But\tthe\tchecklist\tdoes\tnot\treflect\tthis\t\u2013\tit\tstill\tshows\trows\tfor\tboth\t\u201corder\t1\u201d\tand\t\u201corder 2.\u201d\tWhen\tyou\tadd\ta\trow\tfor\tan\torder,\tyou\tneed\tto\tmake\tsure\tthat\tany\texisting\trows associated\twith\tthe\tsame\tcustomer\temail\taddress\tare\tremoved. Now\tthat\tyou\tcan\tremove\trows\tbased\ton\tthe\tcustomer\u2019s\temail\taddress,\tthis\tis straightforward.\tIn\tchecklist.js,\tupdate\tthe\taddRow\tprototype\tmethod\tso\tthat\tthe first\tthing\tit\tdoes\tis\tcall\tremoveRow,\tpassing\tin\tthe\temail\taddress\tof\tthe\tcustomer. ... \t\tCheckList.prototype.addRow\t=\tfunction\t(coffeeOrder)\t{ \t\t\t\t\/\/\tRemove\tany\texisting\trows\tthat\tmatch\tthe\temail\taddress \t\t\t\tthis.removeRow(coffeeOrder.emailAddress); \t\t\t\t\/\/\tCreate\ta\tnew\tinstance\tof\ta\trow,\tusing\tthe\tcoffee\torder\tinfo \t\t\t\tvar\trowElement\t=\tnew\tRow(coffeeOrder);","\/\/\tAdd\tthe\tnew\trow\tinstance's\t$element\tproperty\tto\tthe\tchecklist \t\t\t\tthis.$element.append(rowElement.$element); \t\t}; ... Save\tchecklist.js\tand\tverify\tin\tthe\tbrowser\tthat\tthe\tfirst\torder\u2019s\tchecklist\titem\tis removed\twhen\ta\tsecond\torder\twith\tthe\tsame\temail\tis\tsubmitted. Now\tthat\tyou\tcan\tremove\ta\tchecklist\trow\tfrom\tthe\tUI,\tturn\tyour\tattention\tto\thandling\tthe checklist\tclick\tevent. Writing\tthe\taddClickHandler\tmethod To\thandle\tclicks\tto\tthe\tchecklist,\tyou\twill\tuse\tthe\tsame\tevent\thandler\tregistration technique\tthat\tyou\tused\twith\tFormHandler. FormHandler.prototype.addSubmitHandler\taccepts\ta\tfunction\targument,\tfn, and\tthen\tregisters\tan\tanonymous\tfunction\tto\thandle\tthe\tsubmit\tevent\tof this.$formElement.\tInside\tof\tthat\tanonymous\tfunction,\tfn\tis\tinvoked.\tHere\tis\tthat method\tdefinition\tfor\treference: \t\tFormHandler.prototype.addSubmitHandler\t=\tfunction\t(fn)\t{ \t\t\t\tconsole.log('Setting\tsubmit\thandler\tfor\tform'); \t\t\t\tthis.$formElement.on('submit',\tfunction\t(event)\t{ \t\t\t\t\t\tevent.preventDefault(); \t\t\t\t\t\tvar\tdata\t=\t{}; \t\t\t\t\t\t$(this).serializeArray().forEach(function\t(item)\t{ \t\t\t\t\t\t\t\tdata[item.name]\t=\titem.value; \t\t\t\t\t\t\t\tconsole.log(item.name\t+\t'\tis\t'\t+\titem.value); \t\t\t\t\t\t}); \t\t\t\t\t\tconsole.log(data); \t\t\t\t\t\tfn(data); \t\t\t\t\t\tthis.reset(); \t\t\t\t\t\tthis.elements[0].focus(); \t\t\t\t}); \t\t}; This\tmakes\tFormHandler.prototype.addSubmitHandler\tflexible,\tbecause\tit can\tbe\tpassed\tany\tfunction\tthat\tneeds\tto\trun\twhen\tthe\tform\tis\tsubmitted.\tThis\tway, FormHandler.prototype.addSubmitHandler\tdoes\tnot\tneed\tto\tknow\tthe details\tof\tthat\tfunction\tor\twhat\tsteps\tit\ttakes. You\twill\tadd\ta\tprototype\tmethod\tto\tCheckList\tcalled\taddClickHandler\tthat\twill work\tthe\tsame\tway\tas\tFormHandler\u2019s\taddSubmitHandler.\tThat\tis,\tit\twill: 1.\t Accept\ta\tfunction\targument. 2.\t Register\tan\tevent\thandler\tcallback. 3.\t Invoke\tthe\tfunction\targument\tinside\tthe\tevent\thandler\tcallback. CheckList.prototype.addClickHandler\tdiffers\tfrom FormHandler.prototype.addSubmitHandler\tin\tthat\tit\twill\tlisten\tfor\ta\tclick event\tand\tbind\tthe\tcallback\tto\tthe\tCheckList\tinstance. In\tchecklist.js,\tadd\tthe\taddClickHandler\tmethod\tand\tspecify\ta\tparameter named\tfn.\tListen\tfor\ta\tclick\tevent\tusing\tjQuery\u2019s\ton\tmethod. Inside\tthe\tevent\thandler\tfunction,\tdeclare\ta\tlocal\tvariable\tnamed\temail\tand\tassign\tit event.target.value,\twhich\tis\tthe\tcustomer\u2019s\temail\taddress.\tThen\tcall\tremoveRow,","passing\tit\temail.\tAfter\tthat,\tinvoke\tfn\tand\tpass\tit\temail\talso.\tMake\tsure\tto\tuse bind(this)\tto\tset\tthe\tcontext\tobject\tof\tthe\tevent\thandler\tfunction. ... \t\tfunction\tCheckList(selector)\t{ \t\t\t\t... \t\t} \t\tCheckList.prototype.addClickHandler\t=\tfunction\t(fn)\t{ \t\t\t\tthis.$element.on('click',\t'input',\tfunction\t(event)\t{ \t\t\t\t\t\tvar\temail\t=\tevent.target.value; \t\t\t\t\t\tthis.removeRow(email); \t\t\t\t\t\tfn(email); \t\t\t\t}.bind(this)); \t\t}; \t\tCheckList.prototype.addRow\t=\tfunction\t(coffeeOrder)\t{ \t\t\t\t... When\tyou\tregistered\tthe\tevent\thandler\tcallback\twith\tthis.$element.on,\tyou\tspecified click\tas\tthe\tevent\tname.\tBut\tyou\talso\tpassed\tin\ta\tfiltering\tselector\tas\tthe\tsecond argument.\tThe\tfiltering\tselector\ttells\tthe\tevent\thandler\tto\trun\tthe\tcallback\tfunction\tonly\tif the\tevent\twas\ttriggered\tby\tan\t<input>\telement. This\tis\ta\tpattern\tcalled\tevent\tdelegation.\tIt\tworks\tbecause\tsome\tevents,\tlike\tclicks\tand keypresses,\tpropagate\tthrough\tthe\tDOM,\tmeaning\teach\tancestor\telement\tis\tinformed about\tthe\tevent. Any\ttime\tyou\tneed\tto\tlisten\tfor\tan\tevent\ton\telements\tthat\tare\tdynamically\tcreated\tand removed,\tsuch\tas\tthe\tchecklist\titems,\tyou\tshould\tuse\tevent\tdelegation.\tIt\tis\teasier\tand more\tperformant\tto\tadd\ta\tsingle\tlistener\tto\tthe\tdynamic\telements\u2019\tcontainer\tand\tthen\trun the\thandler\tfunction\tbased\ton\twhat\telement\ttriggered\tthe\tevent. Notice\tthat\tyou\tdo\tnot\tcall\tevent.preventDefault\tinside\tthe\tevent\thandler.\tWhy\tnot?\tIf you\tcalled\tevent.preventDefault,\tthe\tcheckbox\twould\tnot\tactually\tchange\tits\tvisual state\tto\tshow\ta\tcheckmark\tin\tthe\tbox. Also,\tnotice\tthat\tyou\tbind\tthe\tevent\thandler\tcallback\tto\tthis,\twhich\trefers\tto\tthe instance\tof\tCheckList. Calling\taddClickHandler addClickHandler\tneeds\tto\tbe\tconnected\tto\tdeliverOrder.\tGo\tto\tmain.js\tto make\tthat\tconnection.\tPass\ta\tbound\tversion\tof\tdeliverOrder\tto checkList.addClickHandler. ... \t\tvar\tmyTruck\t=\tnew\tTruck('ncc-1701',\tnew\tDataStore()); \t\twindow.myTruck\t=\tmyTruck; \t\tvar\tcheckList\t=\tnew\tCheckList(CHECKLIST_SELECTOR); \t\tcheckList.addClickHandler(myTruck.deliverOrder.bind(myTruck)); \t\tvar\tformHandler\t=\tnew\tFormHandler(FORM_SELECTOR); ... Save\tyour\tchanges\tand\tadd\tsome\tcoffee\torders\tin\tthe\tform.\tClick\teither\tthe\tcheckbox\tor the\ttext\tof\tone\tof\tthe\tchecklist\titems,\tand\tit\twill\tbe\tremoved\t(Figure\t11.9)!","Figure\t11.9\t\tClicking\ta\tchecklist\titem\tremoves\tit You\thave\tlearned\thow\tto\tcreate\tdynamic\tform\telements\tand\twork\twith\tthe\tevents\tthey generate.\tYou\twere\table\tto\tassociate\teach\tone\twith\ta\tspecific\tcoffee\torder\tby\tusing\tthe email\taddress\tas\tan\tidentifier. Using\tthese\ttechniques,\tyou\tcompleted\tthe\tmodules\tthat\tmanage\tthe\tUI,\tturning\twhat\twas a\tconsole-only\tapplication\tinto\tone\tthat\tcould\tbe\tused\tfor\ta\treal-world\ttask. You\thave\tcompleted\ttwo\tof\tthe\tthree\tmajor\tparts\tof\tCoffeeRun.\tThe\tinternal\tlogic\tgoverns the\tdata\twithin\tthe\tapplication.\tThe\tform\telements,\tFormHandler,\tand\tCheckList provide\tthe\tinteractive\tUI.\tThe\tnext\tchapters\tdeal\twith\tpreparing\tand\texchanging\tdata with\ta\tremote\tserver.","Bronze\tChallenge:\tAdding\tthe\tStrength\tto\tthe Description You\thave\tdecided\tthat\tthe\tstrength\tof\tthe\tcoffee\tis\ta\tmore\timportant\tpiece\tof\tinformation and\tshould\tbe\tthe\tfirst\tpart\tof\tthe\tdescription. Change\tthe\tway\tyou\tare\twriting\tthe\torder\tdescriptions\tso\tthat\tthe\tcoffee\tstrength\tis\tat\tthe beginning\tof\tthe\tdescription\ttext.","Silver\tChallenge:\tColor\tCoding\tby\tFlavor\tShot Color\tcode\tyour\torders\tbased\ton\tthe\tflavor\tshot.\tBased\ton\tthe\toptions\tchosen\tfor\teach coffee,\tdisplay\tthe\trow\tin\tthe\tchecklist\twith\ta\tdifferent\tbackground\tcolor. Make\tsure\tthat\tthe\ttext\thas\tenough\tcontrast\twith\tthe\tbackground\tcolor.","Gold\tChallenge:\tAllowing\tOrder\tEditing Allow\texisting\torders\tto\tbe\tedited.\tYou\twill\tneed\tto\tchange\tthe\tway\tthe\tchecklist\tworks. If\tthe\tuser\tdouble-clicks\tan\torder,\tload\tit\tback\tinto\tthe\tform\tfor\tediting.\tIf\tthe\tuser\tonly clicks\tonce,\tgray\tout\tthe\trow.\tAfter\ta\tfew\tseconds,\ttreat\tthe\titem\tas\tif\tit\twere\tdelivered\tand remove\tit\tfrom\tthe\tchecklist\tand\tfrom\tthe\tapplication\u2019s\tdata. As\tan\textra\tbonus,\tmake\tsure\tthat\tafter\tthe\tuser\tfinishes\tediting\tthe\texisting\trow\tis updated\tin\tplace,\tnot\tremoved\tand\treplaced\twith\ta\tnew\trow.","12\t Validating\tForms CoffeeRun\tis\thumming\talong!\tUsers\tcan\tenter\tcoffee\torders\tin\tthe\tform,\tand\tthe\torder information\tis\tprocessed\tand\tstored.\tBut\twhat\twould\thappen\tto\tyour\tapp\t\u2013\tand\tyour\tcoffee truck\t\u2013\tif\tsomeone\tsubmitted\tan\torder\twith\tmissing\tor\tunusable\tinformation? Not\tto\tworry.\tYou\tcan\teasily\thandle\tthese\tscenarios\twith\ta\tlittle\tbit\tof\tcode\tto\tmake\tsure the\tdata\tis\tOK\tfor\tyour\tapplication\tto\tuse.\tIn\tfact,\tthis\tis\tan\tessential\tstep\tif\tyou\tever\tsend data\tback\tto\ta\tserver.\tAlmost\tevery\tmodern\tbrowser\tis\tprepared\tto\tvalidate\tform\tdata when\tit\tis\tsubmitted.\tAll\tyou\tneed\tto\tdo\tis\tprovide\tthe\trules. In\tthis\tchapter,\tyou\tare\tgoing\tto\tlearn\ttwo\ttechniques\tfor\tform\tvalidation.\tThe\tfirst technique\tis\tto\tadd\tvalidation\tattributes\tto\tthe\tHTML,\tallowing\tthe\tbrowser\u2019s\tbuilt-in validation\tmechanisms\tto\ttake\teffect.\tThe\tsecond\tis\tto\twrite\tyour\town\tvalidation\tcode\tin JavaScript,\tusing\tthe\tConstraint\tValidation\tAPI. The\trequired\tAttribute The\tmost\tbasic\tform\tof\tvalidation\tis\tto\tcheck\twhether\ta\tfield\thas\ta\tvalue\tand\tis\tnot completely\tempty.\tThis\tkind\tof\tcheck\tdoes\tnot\tmake\tsense\tfor\tfields\twith\tdefault\tvalues, like\tyour\tsize,\tflavor,\tand\tstrength\tfields.\tBut\tit\tis\tjust\twhat\tyou\tneed\tfor\tyour\torder\tand email\tfields\t\u2013\tyou\tdefinitely\tdo\tnot\twant\torders\tto\tbe\tsubmitted\twith\tthose\tfields\tleft blank. In\tindex.html,\tadd\tthe\trequired\tBoolean\tattribute\tto\tthe\torder\tand\temail\tfields. ... \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"coffeeOrder\\\">Order<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\tclass=\\\"form-control\\\"\tname=\\\"coffee\\\"\tid=\\\"coffeeOrder\\\" \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tautofocus\trequired\t\/> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label\tfor=\\\"emailInput\\\">Email<\/label> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<input\tclass=\\\"form-control\\\"\ttype=\\\"email\\\"\tname=\\\"emailAddress\\\" \t\t\t\t\t\t\t\t\t\t\t\t\t\tid=\\\"emailInput\\\"\tvalue=\\\"\\\"\tplaceholder=\\\"[email protected]\\\" \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trequired\t\/> \t\t\t\t\t\t\t\t\t\t\t\t<\/div> ... Remember\tthat\ta\tBoolean\tattribute\tshould\tnot\tbe\tassigned\ta\tvalue.\tIf\tyou\tmake\tthe mistake\tof\twriting\tsomething\tlike\trequired=\\\"false\\\",\tthe\tvalue\twill\tbe\ttrue\tand\tthe\tfield will\tbe\trequired!\tThe\tbrowser\tonly\tcares\tabout\tthe\texistence\tof\tthe\tattribute\tand\tignores any\tvalue\tassigned. That\tpoint\tbears\trepeating:\tIf\ta\tBoolean\tattribute\texists\tfor\tan\telement,\tthe\tbrowser considers\tthe\tvalue\tto\tbe\ttrue,\tregardless\tof\tthe\tvalue\tyou\tset\tfor\tit. Save\tindex.html,\tmake\tsure\tbrowser-sync\tis\trunning,\tand\tload\tCoffeeRun\tin\tthe browser.\tTry\tsubmitting\tthe\tform\twithout\tfilling\tout\teither\tor\tboth\tof\tthe\trequired\tfields. You\twill\tsee\ta\twarning,\tas\tin\tFigure\t12.1."]
Search
Read the Text Version
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443
- 444
- 445
- 446
- 447
- 448
- 449
- 450
- 451
- 452
- 453
- 454
- 455
- 456
- 457
- 458
- 459
- 460
- 461
- 462
- 463
- 464
- 465
- 466
- 467
- 468
- 469
- 470
- 471
- 472
- 473
- 474
- 475
- 476
- 477
- 478
- 479
- 480
- 481
- 482
- 483
- 484
- 485
- 486
- 487
- 488
- 489
- 490
- 491
- 492
- 493
- 494
- 495
- 496
- 497
- 498
- 499
- 500
- 501
- 502
- 503
- 504
- 505
- 506
- 507
- 508
- 509
- 510
- 511
- 512
- 513
- 514
- 515
- 516
- 517
- 518
- 519
- 520
- 521
- 522
- 523
- 524
- 525
- 526
- 527
- 528
- 529
- 530
- 531
- 532
- 533
- 534
- 535
- 536
- 537
- 538
- 539
- 540
- 541
- 542
- 543
- 544
- 545
- 546
- 547
- 548
- 549
- 550
- 551
- 552
- 553
- 554
- 555
- 556
- 557
- 558
- 559
- 560
- 561
- 562
- 563
- 564
- 565
- 566
- 567
- 568
- 569
- 570
- 571
- 572
- 573
- 574
- 575
- 576