243

Marionette Gentle Introduction

Embed Size (px)

DESCRIPTION

Marionette

Citation preview

Backbone.Marionette.js: A GentlelntroductionBuild a Marionette.|s app, one step at a timeDavid SulcThis book is for sale at http//leanpub.com/marionette-gentle-introductionThis version was published on zc1!-cv-zcThis is a leanpub book. leanpub empowers authors and publishers with the lean Publishingprocess. lean Publishing is the act of publishing an in-progress ebook using lightweight tools andmany iterations to get reader feedback, pivot until you have the right book and build traction onceyou do.zc1! David SulcAlso By David 5ulcStructuring Backbone Code with RequireJS and Marionette ModulesContentsForeword from Derick Bailey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iCover Credits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iiWho This Book is For . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iiiFollowing Along with Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ivJumping in for Advanced Readers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vSetting Up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1Asset Organization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1Getting Our Assets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . zDisplaying a Static View. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . SDynamically Specifying a View Template . . . . . . . . . . . . . . . . . . . . . . . . . . . 1cSpecifying Other View Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1zlxercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1!Displaying a Model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1SUsing Model Defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1clntroducing lvents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1vlxercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . zcDisplaying a Collection of Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . z1lntroducing the CollectionView. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . z1listing our Contacts with a CollectionView . . . . . . . . . . . . . . . . . . . . . . . . . . zzSorting a Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . zvlxercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . !cStructuring Code with Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3zlxtracting our App Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . !zMoving Contacts to the lntities Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . !!Creating a Module for the ContactsApp Sub-Application . . . . . . . . . . . . . . . . . . . 1cMoving the App lnitialization Handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11lxercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1eDealing with Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1eCONTlNTSUsing a CompositeView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1lxercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . cUsing lvents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . clxercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . !Events, Bubbling, and TriggerMethod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . SCommunicating via lvents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vAnimating the Removed ltemView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . eclxercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e1lntroducing TriggerMethod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ezDisplaying Contacts in Dedicated Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . oWiring up the Show lvent. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e1The ContactsApp.Show Sub-Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . eeImplementing Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1oHow to Think About Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . cAdding a Router to ContactsApp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1Routing Helpers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DRYing up Routing with lvents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . cAdding a Show Route . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vlxercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . c1Implementing a View for Nonexistent Contacts . . . . . . . . . . . . . . . . . . . . . . . . 8oDealing with Persisted Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8vAdding a location to our lntities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vcConfiguring our lntities to use Web Storage . . . . . . . . . . . . . . . . . . . . . . . . . vzloading our Contacts Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vzloading a Single Contact . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v1Deleting a Contact . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vHandling Data Iatency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v1Delaying our Contact letch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vUsing jQuery Deferreds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vcDisplaying a loading View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1c1lxercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1ccPassing Parameters to Views and SerializeData . . . . . . . . . . . . . . . . . . . . . . . .11cManaging Forms Editing a Contact . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113Saving the Modified Contact . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11cValidating Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1zcDisplaying a Modal Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1zSUsing jQuery Ul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1zCONTlNTSAdding the ldit link . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1zelmplementing Modal lunctionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1zcHandling the Modal lorm Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1!Subdividing Complex Views with Iayouts . . . . . . . . . . . . . . . . . . . . . . . . . . . 13vRegions vs layouts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11zExtending from Base Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13Managing Dialogs with a Dedicated Region . . . . . . . . . . . . . . . . . . . . . . . . . . 1S3Customizing onRender. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1vFiltering Contacts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1o1lmplementing an lmpty View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1eOptional Routes and Query Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1ecThe `About` Sub-Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113Coding the Sub-App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1!The `Header` Sub-Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111Setting up the Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1Adding Templates and Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1vlmplementing the Controller and Sub-Application . . . . . . . . . . . . . . . . . . . . . .1czNavigating with the Brand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1c1Highlighting the Active Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1ceHandling Menu Clicks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1vcClosing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1v3Keeping in Touch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1v!Other Books I`ve Written . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1vModule Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1vSExercise Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1v1Displaying a Single-ltem list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1vDisplaying a Contact With No Phone Number . . . . . . . . . . . . . . . . . . . . . . . .1vcSorting a Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .zccDeclaring a Template Sub-Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .zc1Building your own CompositeView. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .zczDisplaying the Contents of a Clicked Table Cell . . . . . . . . . . . . . . . . . . . . . . . .zc!lvent Bubbling from Child Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .zc1Getting Back to the Contacts list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .zceOverriding Marionette`s Template Ioader . . . . . . . . . . . . . . . . . . . . . . . . . . . zo8Declaring a Template Sub-Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .zcvCONTlNTSTackling the Template loader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .z1cSpecifying our new Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .z1zExtending Marionette . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . z13Using Web Storage for Persistence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . z1olmplementation Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .z1eAdding to the lntities Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .z1eUsing a Mixin with Underscore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .z1Determining the Storage Key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .z1vCreating a FilteredCollection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . zz3Foreword from Derick BaileyThe open and flexible nature of Marionette allows it to be used in more ways than can be imagined.l`ve seen applications that l would never have dreamed of, built with it games, financial reportingtools, search engines, mobile applications, ticket sales and e-commerce, database managementsystems, and more. The down side of this flexibility, though, is documentation. Creating acomprehensive suite of documents that show all of the different ways that the parts can be combinedis an overwhelming task.Plenty of introductory articles, blog posts and videos exist out there on the web. But, very little of thisinformation moved beyond the simple patterns of replace this Backbone code with this Marionettecode". Putting the pieces together requires a new level of abstraction and thinking, and a new setof patterns to work with. And this documentation simply did not exist, even if some applicationdevelopers other than myself were using these higher level patterns.lt wasn`t until Brian Mann started producing his BackboneRails.com' screencasts, and David Sulcstarted writing this book, that the Marionette community began to see all of the patterns ofimplementation that l was advocating, in one place. And l`m so very happy to see David writingthis book and Brian producing those screencasts. The community needs this information. Thedocumentation gap is finally being closed.This is the book that l wanted to write, but never had time to write. lt is a complete and thoroughintroduction to building scalable applications with Marionette.js. Better still, it advocates anddemonstrates the same patterns and principles that l use in my own applications. You owe it toyourself to work through all of the exercises in this book, even if you are a seasoned Backbone andMarionette developer. David has done a wonderful job of breaking down the architecture of largeMarionette applications, lighting the path for each step of the journey. Derick Bailey, creator of Marionette.js'http//BackboneRails.comhttp//marionettejs.comCover CreditsThe cover image depicts a theatrical appliance" designed to help ventriloquists by having a partnervoice their puppet. The image is from patent application 1,1v,1! filed in 1v11, which you can viewhere`.`http//patentimages.storage.googleapis.com/pdfs/US11v1!.pdfWho This Book is ForThis book is for web developers who want to build highly interactive javascript applications. Thisbook will cover using Backbone.Marionette.js to achieve that goal, and will empower you to buildyour own applications by understanding how Marionette apps are built.All you`ll need to follow along is a basic understanding of javascript and the DOM (DocumentObject Model), such as being able to manipulate elements on the page using a jQuery selector. lnother words, if you`ve used a few jQuery libraries here and there, you should be able to follow alongjust fine.Following Along with GitThis book is a step by step guide to building a complete Marionette.js application. As such, it`saccompanied by source code in a Git repository hosted at https//github.com/davidsulc/marionette-gentle-introduction.Throughout the book, as we code our app, we`ll refer to commit references within the git repositorylike thisGit commit with our scaffold codeb1d1ce1cz11bbazefddeezcbccevaaffc1dc1evThis will allow you to follow along and see exactly how the code base has changed you can eitherlook at that particular commit in your local copy of the git repository, or click on the link to see anonline display of the code differences.Any change in the code will affect all the following commit references, so the links inyour version of the book might become desynchronized. lf that`s the case, make sure youupdate your copy of the book to get the new links. At any time, you can also see the fulllist of commits here', which should enable you to locate the commit you`re looking for (thecommit names match their descriptions in the book).lven if you haven`t used Git yet, you should be able to get up and running quite easily using onlineresources such as the Git Book. This chapter is by no means a comprehensive introduction to Git,but the following should get you started- Set up Git with Github`s instructions`- To get a copy of the source code repository on your computer, open a command line and runq1L c1ooo q1L..!tao.co.Jt!Jsa!c.r!octtcct!c!troJact!o.!t- lrom the command line move into the mar1oooLLoqooL1o1oLrooocL1oo folder that Gitcreated in the step above, and executehttps//github.com/davidsulc/marionette-gentle-introductionhttps//github.com/davidsulc/marionette-gentle-introduction/commit/b1d1ce1cz11bbazefddeezcbccevaaffc1dc1ev'https//github.com/davidsulc/marionette-gentle-introduction/commits/masterhttp//git-scm.com/book`https//help.github.com/articles/set-up-gitlollowing Along with Git vq1L soou o4oIcoI02IIooa21ooo20o0070aa11c4o0I0to show the code differences implemented by that commit- `-` lines were removed- `-` lines were addedYou can also use Git to view the code at different stages as it evolves within the book- To extract the code as it was during a given commit, executeq1L cooc-ooL o4oIcoI02IIooa21ooo20o0070aa11c4o0I0- look around in the files, they`ll be in the exact state they were in at that point in time withinthe book- Once you`re done looking around and wish to go back to the current state of the code base,runq1L cooc-ooL masLorWhat if l don't want to use Git, and only wantthe latest version of the code7You can download a zipped copy of the repository. This will contain the full Git commithistory, in case you change your mind about following along.jumping in for Advanced ReadersMy goal with this book is to get you comfortable enough to tackle your own Marionette projects, soit assumes very little knowledge. Although you`ll learn the most by following along with the code,you can simply skim the content and checkout the Git commit corresponding to the point in thebook where you wish to join in.https//github.com/davidsulc/marionette-gentle-introduction/archive/master.zip5etting Upln this book, we`re going to build an application step by step. The finished application can be seenat http//davidsulc.github.io/marionette-gentle-introduction'.The first order of business before we can start programming our application, is setting up ourscaffold". We`ll be using pretty basic stuff- Bootstrap CSS and their starter template''- Marionette.js and dependencieslasy, right`Asset OrganizationBefore we get in the thick of things, let`s quickly consider how we`ll organize the various files (CSS,JS, etc.) that we`ll be using in this project. ln order to maintain our sanity as the files increase innumber, we`ll need some sort of system to keep the files tidy so we don`t spend our time looking forthings- project folder- index.html- assets* css* img* js vendorWithin the ]: folder, we`ll use a +enJor subfolder to contain the javascript files that are providedready-to-use (e.g. Marionette.js, jQuery, etc.). The javascript code that we will produce as we buildour application will go within the ]: folder.'http//davidsulc.github.io/marionette-gentle-introduction''http//twitter.github.io/bootstrap/examples/starter-template.htmlSetting Up zGetting Our Assetslet`s start by getting the various javascript libraries we`ll need, saving them in o::e:/]:/+enJor- jquery'- jsonz'`- underscore'- backbone'- backbone.marionette''You`ll notice we`ll be using the development (uncompressed) versions, mainly for theconvenience of having error messages that make sense. Besides, most modern webframeworks provide means to minify/obfuscate javascript when going into production.Next, let`s get the Bootstrap CSS download and extract the zip file', then move c::/|oo:ro.c::to your project folder in o::e:/c::/|oo:ro.c::. ln addition, move the images Bootstrap uses from:ng to your project folder in o::e:/:ng.So now that we`ve got the javascript libraries and CSS we`ll be needing, let`s go ahead and createour HTMl, based on the Bootstrap starter template'`. We`ll modify it slightly, so we don`t havenon-functional things in our page (e.g. menu items that don`t work), and we`ll also need to includethe various javascript files we`ve just obtained. Here`s what we`ll start withindex.htmlI !00!-| t!2 htmJ 1aoq-oo8 head4 meta coarsoL-oL10o tJtJeMar1oooLLo ooLacL Maoaqor/tJtJe JJnk oro1-/assoLs/css/oooLsLracss ro1-sLy1osoooL7 /head00 body'http//code.jquery.com/jquery-1.v.1.js'`https//raw.github.com/douglascrockford/JSON-js/master/jsonz.js'http//underscorejs.org/underscore.js'backbonejs.org/backbone.js''http//marionettejs.com/downloads/backbone.marionette.js'http//twitter.github.io/bootstrap/assets/bootstrap.zip'`http//twitter.github.io/bootstrap/examples/starter-template.htmlSetting Up !I0II dJv c1ass-oavoar oavoar1ovorso oavoar11xooLoI2 dJv c1ass-oavoar1ooorI8 dJv c1ass-cooLa1oorI4 span c1ass-oraooooLacL maoaqor/spanIo /dJvI /dJvI7 /dJvI0I0 dJv c1ass-cooLa1oor20 p+oro 1s sLaL1c cooLooL 1o Loo uoo aqo 1oo`11 ooL1co LoaL 1L qoLs2I ro1acoo oy oor a as sooo as uo sLarL 1L/p22 /dJv2824 scrJpt src-/assoLs/s/voooor/qoorys/scrJpt2o scrJpt src-/assoLs/s/voooor/soo2s/scrJpt2 scrJpt src-/assoLs/s/voooor/oooorscoros/scrJpt27 scrJpt src-/assoLs/s/voooor/oac-oooos/scrJpt20 scrJpt src-/assoLs/s/voooor/oac-oooomar1oooLLos/scrJpt2080 /body8I /htmJPay attention to the order we`re including the javascript files (lines z1-zc) dependenciesmust be respected. lor example, Backbone depends on jQuery and Underscore, so it getsincluded after those two libraries.lf you open 1oooxoLm1 now, you`ll see we`re not quite done you can`t see the placeholdertext because it`s hidden underneath the navigation bar on top. So let`s quickly create a smalla11caL1oocss we`ll put in o::e:/c:: and include in our 1oooxoLm1 file right after the BootstrapCSS (line e). Here`s our a11caL1oocssapplication.cssI body {2 .* 60ox to otc tc cot!cr Joa J8 * -c roo 1or tc t!t!o or *.4 paddJnj-top 0x,o }Setting Up 1Git commit with our scaffold codeb1d1ce1cz11bbazefddeezcbccevaaffc1dc1ev'We can now get started with our app! We`ll develop a contact manager" application, which willstore contact information on people (like a phone book). We`re going to develop it step by step,explaining at each stage how the different Marionette components work together, and why we`rerefactoring code.'https//github.com/davidsulc/marionette-gentle-introduction/commit/b1d1ce1cz11bbazefddeezcbccevaaffc1dc1evDisplaying a 5tatic ViewNow that we have the basics set up, let`s use Marionette to display content in our 1oooxoLm1.We`ll start by putting everything within the HTMl file. But as you can guess, this approach isn`tadvisable for anything beyond a trivial application you`d lose your mind. So we`ll quickly get aroundto refactoring our simple application into something more robust.let`s start by adding some javascript code at the bottom of our 1oooxoLm1I scrJpt Lyo-LoxL/avascr1L2 var ooLacLMaoaqor - oou Mar1oooLLo^11caL1oo(),84 ooLacLMaoaqorsLarL(),o /scrJptWhat did we do` Nothing really exciting we simply declared a new Marionette application, thenstarted it. lf you refresh the 1oooxoLm1 page in your browser, you`ll see absolutely nothing haschanged. This isn`t surprising our application doesn`t do anything yet.let`s now make our app display a message to the console once it has startedI scrJpt Lyo-LoxL/avascr1L2 var ooLacLMaoaqor - oou Mar1oooLLo^11caL1oo(),84 ooLacLMaoaqoroo(1o1L1a11zoa1Lor, 1oocL1oo(){o cooso1o1oq(ooLacLMaoaqor oas sLarLoo), }),70 ooLacLMaoaqorsLarL(),0 /scrJptNote we`ve defined the 1o1L1a11zoa1Lor handler code before we start the application.lf you refresh the page with (e.g.) lirebug`s console open, you`ll see the message we`ve just added.How about we make the app do somehting a little more useful (and visual) by displaying some staticcontent`Before we can have our app do that, we need to fulfill a few preconditionsDisplaying a Static View e- We need to have a view to display- We need a template to provide to our view, so it knows what to display and how to display it- We need to have an area in our page where Marionette can insert the view, in order to displayitlet`s have a quick look at what our 1oooxoLm1 looks like after these additionsindex.htmlI dJv 1o-ma1oroq1oo c1ass-cooLa1oor2 p+oro 1s sLaL1c cooLooL 1o Loo uoo aqo 1oo`11 ooL1co LoaL 1L qoLs8 ro1acoo oy oor a as sooo as uo sLarL 1L/p4 /dJvo scrJpt Lyo-LoxL/Lom1aLo 1o-sLaL1cLom1aLo7 1o1s 1s LoxL LoaL uas rooooroo oy oor Mar1oooLLo a/0 /scrJpt0I0 ! !c )tscr!ot !!orr!cs ct !c!aJcJ crc (cJ!tcJ 1or orct!t,) III2 scrJpt Lyo-LoxL/avascr1LI8 var ooLacLMaoaqor - new Mar1oooLLo^11caL1oo(),I4Io ooLacLMaoaqoraoo-oq1oos({I ma1o-oq1oo ma1oroq1ooI7 }),I0I0 ooLacLMaoaqorSLaL1cv1ou - Mar1oooLLo1Lomv1ouoxLooo({20 Lom1aLo sLaL1cLom1aLo2I }),2228 ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){24 var sLaL1cv1ou - new ooLacLMaoaqorSLaL1cv1ou(),2o ooLacLMaoaqorma1o-oq1oosoou(sLaL1cv1ou),2 }),2720 ooLacLMaoaqorsLarL(),20 /scrJptlor brevity, l`ve included only the HTMl below the navigation bar (and the lines to include thejavascript libraries were also edited). Here`s what our app looks likeDisplaying a Static View Displaying a static viewlnstead of constantly declaring global variables to store things like our view definition (andthereby polluting the global namespace), we`re attaching them to our app (as attributes)with (e.g.) ooLacLMaoaqorSLaL1cv1ou.What did we do with this change` We`ve simply added the features that are needed to display ourview, as discussed above. Here`s what it boils down to- We define a template on lines e-c and tell our view to use it on line zc- We define a region for our app to display views (lines 1-1)- We define a view to display on lines 1v-z1let`s take a moment to explain a few aspects in more detail. ln Marionette (and Backbone ingeneral), views need to be provided with a template to display. This is because they have differentresponsibilities- templates- are basically HTMl- govern how things should be displayed" (what HTMl should be in the view, CSS styles,where data should be displayed, etc.)- views- are javascript objects- take care of reacting to things that happen" (clicks, keeping track of a model, etc.)This can be somewhat confusing if you`re used to working with an MVC web framework such asRails. ln these, the template and view are typically mixed in the view" part of the MVC they getdata from the model instances provided by the controller, then generate some HTMl that is sent tothe browser. What you must keep in mind is that once the HTMl is rendered by these frameworks,it never gets modified a new view may get created by the same controller (e.g. on refresh), but thisparticular instance will never be noJ:[:eJ.ln Marionette apps, however, a view gets instantiated and the user will usually interact with it (clickthings, modify data somewhere else, etc.). Since we`re not refreshing the page each time the userDisplaying a Static View cclicks, we need to manage user interactions (clicks, e.g.) within the view. But in addition, if theuser changes some data, the views displaying that data must update immediately (and rememberthere won`t be any server interaction, or page refresh). ln other words, if a user modifies a contact`sphone number within a popup window, all the views displaying that contact must be refreshed whenthe data is saved. But how can we refresh the data without the server, and how can we know thecontact`s information has changed` This is the view`s responsibility in Marionette it monitors themodels it`s displaying, and if those models change, the view renders itself again (using the sametemplate). And to follow the separation of concerns" pattern, the views" functionality has beenseparated into templates (how to display information) and views (how to react to changes in theenvironment).As you see more Marionette code, you`ll notice that models, views, etc. get instantiated byproviding a javascript object containing key-value properties. ln javascript, var myMooo1-{my^LLr1ooLomyva1oo} declares a valid object, and myMooo1my^LLr1ooLo willreturn myValue". To learn more about javascript objects, see Working with Objects' bythe Mozilla Developer Network.Our template is defined within a scr1L tag, with Lyo attribute of LoxL/Lom1aLo. This is simplyto trick the browser- it`s not HTMl, so the browser won`t try to display it- it`s not javascript, so the browser won`t try to execute itHowever, we can conveniently set an 1o attribute to the scr1L tag, allowing us to select it withjQuery. And that`s exactly what`s happening on line zc, we`re indicating which template to use bygiving our view a jQuery selector and Marionette does the rest for us.What about the region on lines 1-1` Well, as we mentioned above, Marionette will needsomewhere within our page to display our view. To create a region to contain our view, we`vesimply provided a jQuery selector to the DOM element that will contain our view (notice we`veadded an 1o attribute to the tag on line 1). Of course, we`ll see that having many regions come inhandy with a more complex interface, but that`s for later.Now, instead of displaying a simple message in the console, we instantiate a new view when ourapplication has started and use our pre-defined region to display it. You`ll now understand howregion definitions work (line 1e) the key on the left is what we call our region within our Marionetteapplication, while the value on the right is a jQuery selector present in our page. ln other words, bydeclaring a region with ma1o-oq1oo ma1oroq1oo, we`re saying that callinghttp//en.wikipedia.org/wiki/Separationofconcerns'https//developer.mozilla.org/en/docs/JavaScript/Guide/WorkingwithobjectsDisplaying a Static View vooLacLMaoaqorma1o-oq1oosoou(sLaL1cv1ou),means put the contents of sLaL1cv1ou inside the element corresponding to the jQuery selectorma1oroq1oo".With our latest modifications, our 1oooxoLm1 now looks like thisindex.htmlI !00!-| t!2 htmJ 1aoq-oo8 head4 meta coarsoL-oL10o tJtJeMar1oooLLo ooLacL Maoaqor/tJtJe JJnk oro1-/assoLs/css/oooLsLracss ro1-sLy1osoooL7 JJnk oro1-/assoLs/css/a11caL1oocss ro1-sLy1osoooL0 /head0I0 bodyIII2 dJv c1ass-oavoar oavoar1ovorso oavoar11xooLoI8 dJv c1ass-oavoar1ooorI4 dJv c1ass-cooLa1oorIo span c1ass-oraooooLacL maoaqor/spanI /dJvI7 /dJvI0 /dJvI020 dJv 1o-ma1oroq1oo c1ass-cooLa1oor2I p+oro 1s sLaL1c cooLooL 1o Loo uoo aqo 1oo`11 ooL1co LoaL 1L qoLs22 ro1acoo oy oor a as sooo as uo sLarL 1L/p28 /dJv242o scrJpt Lyo-LoxL/Lom1aLo 1o-sLaL1cLom1aLo2 1o1s 1s LoxL LoaL uas rooooroo oy oor Mar1oooLLo a/27 /scrJpt2020 scrJpt src-/assoLs/s/voooor/qoorys/scrJpt80 scrJpt src-/assoLs/s/voooor/soo2s/scrJpt8I scrJpt src-/assoLs/s/voooor/oooorscoros/scrJpt82 scrJpt src-/assoLs/s/voooor/oac-oooos/scrJpt88 scrJpt src-/assoLs/s/voooor/oac-oooomar1oooLLos/scrJptDisplaying a Static View 1c848o scrJpt Lyo-LoxL/avascr1L8 ooLacLMaoaqor - new Mar1oooLLo^11caL1oo(),8780 ooLacLMaoaqoraoo-oq1oos({80 ma1o-oq1oo ma1oroq1oo40 }),4I42 ooLacLMaoaqorSLaL1cv1ou - Mar1oooLLo1Lomv1ouoxLooo({48 Lom1aLo sLaL1cLom1aLo44 }),4o4 ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){47 var sLaL1cv1ou - new ooLacLMaoaqorSLaL1cv1ou(),40 ooLacLMaoaqorma1o-oq1oosoou(sLaL1cv1ou),40 }),o0oI ooLacLMaoaqorsLarL(),o2 /scrJpto8 /bodyo4 /htmJWe`ll see more of Marionette`s 1Lomv1ou later on, but if you`re in a hurry you can refer to thedocumentation.Git commit to display our static view1bc1cvc1c1eb!bv1f!b!aacevvvfdazef1bv!`Dynamically 5pecifying a View Templateln the code above, we`ve specified the template as a permanent attribute on our view because we`realways going to want to use the same template in this case. But it`s also possible to dynamicallyprovide templates to views, so let`s see how that`s done. We already have our app working to displaya static view that is hard-coded" within our view definition. So let`s override it at runtime with adifferent template.lirst, we need to define a new template to use, which we`ll include right below our existing templatehttps//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.itemview.md`https//github.com/davidsulc/marionette-gentle-introduction/commit/1bc1cvc1c1eb!bv1f!b!aacevvvfdazef1bv!Displaying a Static View 11I scrJpt Lyo-LoxL/Lom1aLo 1o-o111orooLsLaL1cLom1aLo2 p1oxL 1rom a o111orooL Lom1aLo/p8 /scrJptNothing special going on here, we`ve simply got different text to demonstrate the different templatebeing used. Next, we need to provide the template to the view when we instantiate it, like soI var sLaL1cv1ou - oou ooLacLMaoaqorSLaL1cv1ou({2 Lom1aLo o111orooLsLaL1cLom1aLo8 }),And there we have it! When this view is displayed in our main region, the new text will be displayed.Here`s our 1oooxoLm1 with a dynamically provided templateindex.htmlI !00!-| t!2 htmJ 1aoq-oo8 head4 meta coarsoL-oL10o tJtJeMar1oooLLo ooLacL Maoaqor/tJtJe JJnk oro1-/assoLs/css/oooLsLracss ro1-sLy1osoooL7 JJnk oro1-/assoLs/css/a11caL1oocss ro1-sLy1osoooL0 /head0I0 bodyIII2 dJv c1ass-oavoar oavoar1ovorso oavoar11xooLoI8 dJv c1ass-oavoar1ooorI4 dJv c1ass-cooLa1oorIo span c1ass-oraooooLacL maoaqor/spanI /dJvI7 /dJvI0 /dJvI020 dJv 1o-ma1oroq1oo c1ass-cooLa1oor2I p+oro 1s sLaL1c cooLooL 1o Loo uoo aqo 1oo`11 ooL1co LoaL 1L qoLs22 ro1acoo oy oor a as sooo as uo sLarL 1L/p28 /dJv242o scrJpt Lyo-LoxL/Lom1aLo 1o-sLaL1cLom1aLoDisplaying a Static View 1z2 1o1s 1s LoxL LoaL uas rooooroo oy oor Mar1oooLLo a/27 /scrJpt2020 scrJpt Lyo-LoxL/Lom1aLo 1o-o111orooLsLaL1cLom1aLo80 1oxL 1rom a o111orooL Lom1aLo/8I /scrJpt8288 scrJpt src-/assoLs/s/voooor/qoorys/scrJpt84 scrJpt src-/assoLs/s/voooor/soo2s/scrJpt8o scrJpt src-/assoLs/s/voooor/oooorscoros/scrJpt8 scrJpt src-/assoLs/s/voooor/oac-oooos/scrJpt87 scrJpt src-/assoLs/s/voooor/oac-oooomar1oooLLos/scrJpt8080 scrJpt Lyo-LoxL/avascr1L40 var ooLacLMaoaqor - new Mar1oooLLo^11caL1oo(),4I42 ooLacLMaoaqoraoo-oq1oos({48 ma1o-oq1oo ma1oroq1oo44 }),4o4 ooLacLMaoaqorSLaL1cv1ou - Mar1oooLLo1Lomv1ouoxLooo({47 Lom1aLo sLaL1cLom1aLo40 }),40o0 ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){oI var sLaL1cv1ou - new ooLacLMaoaqorSLaL1cv1ou({o2 Lom1aLo o111orooLsLaL1cLom1aLoo8 }),o4 ooLacLMaoaqorma1o-oq1oosoou(sLaL1cv1ou),oo }),oo7 ooLacLMaoaqorsLarL(),o0 /scrJpto0 /body0 /htmJ5pecifying Other View Attributeslet`s see how you can provide options that are passed to the view, enabling you to specify the HTMltag that is used to render your view, add an 1o and c1ass, etc.Displaying a Static View 1!lf you take a look at the source code (with lirebug or a comparable developer tool) after Marionettehas rendered our view, you`ll see it is contained within a o1v tagI dJv2 p1o1s 1s LoxL LoaL uas rooooroo oy oor Mar1oooLLo a/p8 /dJvThis is because Marionette needs an element to contain the view being inserted within the DOM,and by default, it`s a o1v. However, you can specify various attributes in your view, for exampleI ooLacLMaoaqorSLaL1cv1ou - Mar1oooLLo1Lomv1ouoxLooo({2 1o sLaL1cv1ou,8 Laq0amo sao,4 c1ass0amo 1osLrocL1oo,o Lom1aLo sLaL1cLom1aLo }),Such a view definition would generate the following HTMl when the view gets renderedI span 1o-sLaL1cv1ou c1ass-1osLrocL1oo2 p1o1s 1s LoxL LoaL uas rooooroo oy oor Mar1oooLLo a/p8 /spanTo learn more about view options, take a look at the Backbone documentation for the Viewconstructor. lt`s worth noting that just like the template property, these options can be providedwhen the view is being instantiatedI var sLaL1cv1ou - oou ooLacLMaoaqorSLaL1cv1ou({2 1o sLaL1cv1ou,8 Laq0amo sao,4 c1ass0amo 1osLrocL1ooo }),ExerciseDisplaying a 5ingle-ltem ListDisplay a single list item within a o1 element, using this templateTo inspect the source code, you`ll need a developer tool such as lirebug, or similar for your browser (some browsers have tools built-in). This isbecause if you use the browser`s View source code" menu entry, it will display the HTMl it received originally. But since we`ve modified it heavilywith javascript and we`re interested in viewing the current state, we need to display the source using developer tools.http//backbonejs.org/=View-constructorDisplaying a Static View 11I scrJpt Lyo-LoxL/Lom1aLo 1o-11sL1LomLom1aLo2 JJ0oo 1Lom/JJ8 /scrJptln addition, leave the ooLacLMaoaqorSLaL1cv1ou template definition as it is, and specify thetemplate to render during the view`s instantiation. You can, however, add other attributes to theview definition. You can see the exercise solution at the end of the book.Displaying a ModelNow that we`ve covered displaying static content, let`s move on to displaying content containingdata from a model. As you may know, one of Backbone`s selling points is the possibility to structurejavascript applications with a Model-View-Controller' (MVC) pattern. ln this pattern, we use so-called noJe|: to interact with our data, passing them onto views for rendering the information theycontain. You can learn more about models in Backbone`s documentation.So let`s declare a model within our javascript block, above our view declarationooLacLMaoaqorooLacL - 0ac-ooooMooo1oxLooo({}),That wasn`t very hard. What did we do` We simply declared a model named ooLacL and attachedit to our ooLacLMaoaqor app. As you can see, this model extends Backbone`s model definition andinherits various methods from it. When we extend Backbone`s base model like this, we provide ajavascript object (which is empty in our case) that can contain additional information pertaining toour model (we`ll get back to that later).Same as before, we`ll need a template and a view definition before we can display anything in thebrowser. let`s replace our previous template and SLaL1cv1ou with the followingI scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacLLom1aLo2 p- 11rsL0amo - 1asL0amo /p8 /scrJpt4o ooLacLMaoaqorooLacLv1ou - Mar1oooLLo1Lomv1ouoxLooo({ Lom1aLo cooLacLLom1aLo7 }),The template will be included within the HTMl oooy, but outside of the script blockcontaining our application code. Refer to the full 1oooxoLm1 included below if you`reunsure where this code gets inserted.You`ll notice that we`ve got some special - tags in there. These serve the same purpose asin many templating languages (lRB in Rails, PHP, JSP, etc.) they allow the templating engine tointerpret them and include the resulting output within the rendered result. By default, Marionette'http//en.wikipedia.org/wiki/Modellzccv!viewlzccv!controllerhttp//backbonejs.org/=ModelDisplaying a Model 1euses Underscore`s templating engine` where - means output will be displayed, and tags which allow arbitrary javascript to be executed (such as an 11 condition). Since the modelis serialized and passed on to the view template, writing - 11rsL0amo means the model`s11rsL0amo attribute will be displayed.So how do we display our view with model information` With our definitions written, we still needto create instances of a model and view, then display the view. All of this will happen within the1o1L1a11zoa1Lor handlerI ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){2 var a11co - new ooLacLMaoaqorooLacL({8 11rsL0amo ^11co,4 1asL0amo ^rLoo,o oooo0omoor ooo0I04 }),70 var a11cov1ou - new ooLacLMaoaqorooLacLv1ou({0 mooo1 a11coI0 }),III2 ooLacLMaoaqorma1o-oq1oosoou(a11cov1ou),I8 }),lirst, we create a model instance with data on lines z-e you`ll notice we specify various modelattributes and their respective values within a javascript object. Then, we create a new view instanceand provide the model instance as an attribute on lines c-1c.Remember how we discussed passing options to the view when it gets instantiated` That`sexactly what we`re doing here when we use the contact view, we`ll always be using thesame template (and have indicated it in the view definition for convenience), but the modelwe`ll want to display will change. Therefore, we leave the model attribute out of the view`sdefinition, and we specify which model to use each time we instantiate a newviewinstance.And all that`s left to do after that is to display the view within the region (line 1z), same as before.Here`s what our 1oooxoLm1 looks like at this stage`http//underscorejs.org/=templateDisplaying a Model 1I dJv 1o-ma1oroq1oo c1ass-cooLa1oor2 p+oro 1s sLaL1c cooLooL 1o Loo uoo aqo 1oo`11 ooL1co LoaL 1L qoLs8 ro1acoo oy oor a as sooo as uo sLarL 1L/p4 /dJvo scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacLLom1aLo7 - 11rsL0amo - 1asL0amo /0 /scrJpt0I0 ! !c )tscr!ot !c!aJcs rc crc III2 scrJpt Lyo-LoxL/avascr1LI8 var ooLacLMaoaqor - new Mar1oooLLo^11caL1oo(),I4Io ooLacLMaoaqoraoo-oq1oos({I ma1o-oq1oo ma1oroq1ooI7 }),I0I0 ooLacLMaoaqorooLacL - 0ac-ooooMooo1oxLooo({}),202I ooLacLMaoaqorooLacLv1ou - Mar1oooLLo1Lomv1ouoxLooo({22 Lom1aLo cooLacLLom1aLo28 }),242o ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){2 var a11co - new ooLacLMaoaqorooLacL({27 11rsL0amo ^11co,20 1asL0amo ^rLoo,20 oooo0omoor ooo0I0480 }),8I82 var a11cov1ou - new ooLacLMaoaqorooLacLv1ou({88 mooo1 a11co84 }),8o8 ooLacLMaoaqorma1o-oq1oosoou(a11cov1ou),87 }),8080 ooLacLMaoaqorsLarL(),40 /scrJptAnd the visual resultDisplaying a Model 1cDisplaying a modelGit commit to display our basic model view1ebzv1bcbc1f11c!dbeb1cz1fc!1!baaazfeUsing Model DefaultsWhat if our contact didn`t have a first name` We don`t want our app to break if the 11rsL0amoattribute is missing the template would be trying to retrieve an attribute that doesn`t exist on themodel. How can we manage this case` The functionality we`re looking for is default values for modelattributes.To declare default attribute values, simply add a oo1ao1Ls object to the main object provided to ourmodel definitionI ooLacLMaoaqorooLacL - 0ac-ooooMooo1oxLooo({2 oo1ao1Ls {8 11rsL0amo ``4 }o }),lf we now declare the following model instanceI var cooLacL - oou ooLacLMaoaqorooLacL({2 1asL0amo ^rLoo,8 oooo0omoor ooo0I044 }),and we try to display the missing 11rsL0amo attribute, the empty string we defined as the defaultvalue will be shown instead.https//github.com/davidsulc/marionette-gentle-introduction/commit/1ebzv1bcbc1f11c!dbeb1cz1fc!1!baaazfeDisplaying a Model 1vNote that this code is included only to demonstrate default model attributes. lt will not bepart of our application`s code later on, we will add model validations to manage missingattribute values.lntroducing Eventslet`s enrich our view slightly we`ve got a phone number for Alice, so let`s display it in an alertwhen her name is clicked.Marionette views inherit all of Backbone`s functionality, among which the ability to define eventsand their associated handlers. Here`s what they look likeI ovooLs {2 c11c- a1orLoooo0omoor8 }This event translates as when the user c11c-s the tag that can be found in this view, call thea1orLoooo0omoor function". lf you`ve used jQuery, you`ll recognize it`s essentialy an event namefollowed by a selector (which could contain class names, etc.). let`s use this feature in our view todisplay Alice`s phone number, by modifying our view declarationI ooLacLMaoaqorooLacLv1ou - Mar1oooLLo1Lomv1ouoxLooo({2 Lom1aLo cooLacLLom1aLo,84 ovooLs {o c11c- a1orLoooo0omoor },70 a1orLoooo0omoor functJon(){0 a1orL(thJsmooo1oscao(oooo0omoor)),I0 }II }),Backbone models` oscao` works the same way as qoL`' they both return the value of theattribute provided as an argument, but oscao will escape HTMl content, protecting youfrom XSS attacks if you`re displaying user-provided data within the HTMl.`http//backbonejs.org/=Model-escape`'http//backbonejs.org/=Model-getDisplaying a Model zclf you now refresh the page and click on Alice`s name, you`ll see her phone number displayed. Prettystraightforward, right` You`ll notice that since we`re in the view definition when we`re writing oura1orLoooo0omoor function, we have access to the view`s model instance via Lo1smooo1, eventhough +|:c| model instance will be used isn`t known yet (it`s provided when we instantiate theview, remember`).Displaying an alert when clicking a contactThis code is not going to be included in our app, so you won`t see it going forward.ExerciseDisplaying a Contact With No Phone NumberAdd a default phone number of No phone number!". Then create a new model withouta phone number, and click on it. Make sure that No phone number!" is displayed in thealert. You can see the exercise solution at the end of the book.Displaying a Collection of ModelsMore often than not, we`ll be dealing with several instances of a given model (e.g. a list of contacts).Backbone has built-in functionality for this purpose, named co||ec:on: (you can learn more aboutthem in Backbone`s documentation`). These collections have many interesting features we`ll lookinto later, but for now we`ll focus on the functionality Marionette provides to display them.Collections are very straightforward to define, for exampleI var MyMooo1 - 0ac-ooooMooo1oxLooo({}),28 var Myo11ocL1oo - 0ac-ooooo11ocL1oooxLooo({4 mooo1 MyMooo1o }),As you can see, collections define which type of models they contain. Don`t worry, we`ll see apractical example in a few moments with our ContactManager app.lntroducing the CollectionViewlet`s take a minute to think about what is required to display a list of multiple model instances.We`d need1. a collection to hold all the modelsz. a mechanism to render the same view type for each model instance!. somewhere to display all of these viewslortunately, Marionette does all of this for us with a o11ocL1oov1ou that looks like this (from thedocumentation``)`http//backbonejs.org/=Collection``https//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.collectionview.mdDisplaying a Collection of Models zzI var My1Lomv1ou - Mar1oooLLo1Lomv1ouoxLooo({}),28 Mar1oooLLoo11ocL1oov1ouoxLooo({4 1Lomv1ou My1Lomv1ouo }),This code covers points z and ! above our o11ocL1oov1ou will render an instance of My1Lomv1oufor each model in the collection, and we can then show our o11ocL1oov1ou instance within ourregion to display all of these views at once. But where`s our collection` As you can guess, it isn`tdefined anywhere as we`ll most likely provide different collection configurations to our views itcould be a completely different list of models (e.g. a filtered list), or the same list sorted differently.Therefore, we`ll simply pass the collection as an option when the view is instantiated, as we saw inthe previous chapter.Listing our Contacts with a CollectionViewSo how do we implement this in our app` let`s display a collection of contacts as an unorderedlist (i.e. within a o1 element). This is how our javascript data will be transformed into HTMl, via ao11ocL1oov1ouCorrespondence between javascript data and rendered HTMI, using a CollectionViewlirst, we`ll need a template and view to display each modelDisplaying a Collection of Models z!I scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL1Lom2 JJ- 11rsL0amo - 1asL0amo /JJ8 /scrJpt4o ooLacLMaoaqorooLacL1Lomv1ou - Mar1oooLLo1Lomv1ouoxLooo({ Lom1aLo cooLacL11sL1Lom7 }),Don`t forget templates go in the HTMl section, while our views (being javascript) needto go within our application`s scr1L tag.Now let`s add a o11ocL1oov1ouI ooLacLMaoaqorooLacLsv1ou - Mar1oooLLoo11ocL1oov1ouoxLooo({2 Laq0amo o1,8 1Lomv1ou ooLacLMaoaqorooLacL1Lomv1ou4 }),Why are we using the Laq0amo attribute` lt will make our view get wrapped within a o1element instead of the default o1v. Then, once we get our 11 elements rendered within thecollection view (which is now a o1 element), we`ll have the list we want to be displayed.We already have a contact model from last chapter, so let`s create a collectionI ooLacLMaoaqorooLacLo11ocL1oo - 0ac-ooooo11ocL1oooxLooo({2 mooo1 ooLacLMaoaqorooLacL8 }),Now, all we need is to start everything up within our 1o1L1a11zoa1Lor handlerDisplaying a Collection of Models z1I ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){2 var cooLacLs - new ooLacLMaoaqorooLacLo11ocL1oo(8 {4 11rsL0amo 0oo,o 1asL0amo 0r1qoam, oooo0omoor ooo0I87 },0 {0 11rsL0amo ^11co,I0 1asL0amo ^rLoo,II oooo0omoor ooo0I04I2 },I8 {I4 11rsL0amo oar11o,Io 1asL0amo amoo11,I oooo0omoor ooo0I20I7 }I0 ]),I020 var cooLacLs.1sLv1ou - new ooLacLMaoaqorooLacLsv1ou({2I co11ocL1oo cooLacLs22 }),2824 ooLacLMaoaqorma1o-oq1oosoou(cooLacLs.1sLv1ou),2o }),lt can be hard to see, but to create our collection instance we`re providing an orroy ofobjects note the || characters on lines z and 1c. The collection initializer will then createmodel instances for each element in the array.Just to make sure, our code should now look like thisindex.htmlI dJv 1o-ma1oroq1oo c1ass-cooLa1oor2 p+oro 1s sLaL1c cooLooL 1o Loo uoo aqo 1oo`11 ooL1co LoaL 1L qoLs8 ro1acoo oy oor a as sooo as uo sLarL 1L/p4 /dJvo scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL1Lom7 11- 11rsL0amo - 1asL0amo /11Displaying a Collection of Models z0 /scrJpt0I0 ! !c )tscr!ot !c!aJcs rc crc III2 scrJpt Lyo-LoxL/avascr1LI8 var ooLacLMaoaqor - new Mar1oooLLo^11caL1oo(),I4Io ooLacLMaoaqoraoo-oq1oos({I ma1o-oq1oo ma1oroq1ooI7 }),I0I0 ooLacLMaoaqorooLacL - 0ac-ooooMooo1oxLooo({}),202I ooLacLMaoaqorooLacLo11ocL1oo - 0ac-ooooo11ocL1oooxLooo({22 mooo1 ooLacLMaoaqorooLacL28 }),242o ooLacLMaoaqorooLacL1Lomv1ou - Mar1oooLLo1Lomv1ouoxLooo({2 Lom1aLo cooLacL11sL1Lom27 }),2020 ooLacLMaoaqorooLacLsv1ou - Mar1oooLLoo11ocL1oov1ouoxLooo({80 Laq0amo o1,8I 1Lomv1ou ooLacLMaoaqorooLacL1Lomv1ou82 }),8884 ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){8o var cooLacLs - new ooLacLMaoaqorooLacLo11ocL1oo(|8 {87 11rsL0amo 0oo,80 1asL0amo 0r1qoam,80 oooo0omoor ooo0I840 },4I {42 11rsL0amo ^11co,48 1asL0amo ^rLoo,44 oooo0omoor ooo0I044o },4 {47 11rsL0amo oar11o,40 1asL0amo amoo11,40 oooo0omoor ooo0I20Displaying a Collection of Models zeo0 }oI |),o2o8 var cooLacLs.1sLv1ou - new ooLacLMaoaqorooLacLsv1ou({o4 co11ocL1oo cooLacLsoo }),oo7 ooLacLMaoaqorma1o-oq1oosoou(cooLacLs.1sLv1ou),o0 }),o00 ooLacLMaoaqorsLarL(),I /scrJptNow, if we take a look at the result, it`ll propbably look ok. But that`s only because modern browsersare really good at interpreting invalid/broken HTMl markup. let`s inspect the source code to seewhat`s been renderedI uJ2 dJv8 JJ0oo 0r1qoam/JJ4 /dJvo dJv JJ^11co ^rLoo/JJ7 /dJv0 dJv0 JJoar11o amoo11/JJI0 /dJvII /uJWhat`s going on there` Well, if you recall, we`ve mentioned that Backbone will use a o1v to wrapviews by default. Since we didn`t specify a Laq0amo for our item view, it was rendered within a o1v.But we don`t want that extra tag, so what can we do` lt`s easy if you think about it we want ourcontact`s item view to be rendered within an 11 tag without any wrapping o1v tags, so we`ll needto specify a Laq0amo of 11. But now that our 1Lomv1ou will be using an 11 tag, there`s no need for itin the templateDisplaying a Collection of Models zI scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL1Lom2 - 11rsL0amo - 1asL0amo 8 /scrJpt4o ooLacLMaoaqorooLacL1Lomv1ou - Mar1oooLLo1Lomv1ouoxLooo({ Laq0amo 11,7 Lom1aLo cooLacL11sL1Lom0 }),And now, when we refresh the page, we`ll have our list properly renderedI uJ2 JJ0oo 0r1qoam/JJ8 JJ^11co ^rLoo/JJ4 JJoar11o amoo11/JJo /uJHere`s what our HTMl now looks likeDisplaying a collection in an unordered listOur corrected code now looks like thisindex.htmlI dJv 1o-ma1oroq1oo c1ass-cooLa1oor2 p+oro 1s sLaL1c cooLooL 1o Loo uoo aqo 1oo`11 ooL1co LoaL 1L qoLs8 ro1acoo oy oor a as sooo as uo sLarL 1L/p4 /dJvo scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL1Lom7 - 11rsL0amo - 1asL0amo 0 /scrJpt0I0 ! !c )tscr!ot !c!aJcs rc crc Displaying a Collection of Models zcIII2 scrJpt Lyo-LoxL/avascr1LI8 var ooLacLMaoaqor - new Mar1oooLLo^11caL1oo(),I4Io ooLacLMaoaqoraoo-oq1oos({I ma1o-oq1oo ma1oroq1ooI7 }),I0I0 ooLacLMaoaqorooLacL - 0ac-ooooMooo1oxLooo({}),202I ooLacLMaoaqorooLacLo11ocL1oo - 0ac-ooooo11ocL1oooxLooo({22 mooo1 ooLacLMaoaqorooLacL28 }),242o ooLacLMaoaqorooLacL1Lomv1ou - Mar1oooLLo1Lomv1ouoxLooo({2 Laq0amo 11,27 Lom1aLo cooLacL11sL1Lom20 }),2080 ooLacLMaoaqorooLacLsv1ou - Mar1oooLLoo11ocL1oov1ouoxLooo({8I Laq0amo o1,82 1Lomv1ou ooLacLMaoaqorooLacL1Lomv1ou88 }),848o ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){8 var cooLacLs - new ooLacLMaoaqorooLacLo11ocL1oo(|87 {80 11rsL0amo 0oo,80 1asL0amo 0r1qoam,40 oooo0omoor ooo0I84I },42 {48 11rsL0amo ^11co,44 1asL0amo ^rLoo,4o oooo0omoor ooo0I044 },47 {40 11rsL0amo oar11o,40 1asL0amo amoo11,o0 oooo0omoor ooo0I20oI }o2 |),Displaying a Collection of Models zvo8o4 var cooLacLs.1sLv1ou - new ooLacLMaoaqorooLacLsv1ou({oo co11ocL1oo cooLacLso }),o7o0 ooLacLMaoaqorma1o-oq1oosoou(cooLacLs.1sLv1ou),o0 }),0I ooLacLMaoaqorsLarL(),2 /scrJptGit commit to display contacts within an unordered listede1zfabefzcb!1vazfa1ccfebzdf!ba`5orting a CollectionYou`re probably slightly annoyed our contacts aren`t displayed in alphabetical order. lf you`reobsessed with sorting, you might have fixed that already by changing the order in which the modelsare created in the collection. But l`m sure you`ll agree that`s hardly a robust solution. lnstead, let`shave the collection do the hard work for us.Backbone collections have an attribute called a comparator` which, when defined, will keep ourcollection in order. So let`s tell our cooLacLs collection to get itself sorted by 11rsL0amoI ooLacLMaoaqorooLacLo11ocL1oo - 0ac-ooooo11ocL1oooxLooo({2 mooo1 ooLacLMaoaqorooLacL,84 comaraLor 11rsL0amoo }),Displaying our collection after implementing a comparator`https//github.com/davidsulc/marionette-gentle-introduction/commit/ede1zfabefzcb!1vazfa1ccfebzdf!ba`http//backbonejs.org/=Collection-comparatorDisplaying a Collection of Models !cGit commit adding a comparator to our contacts collection1fcvbbddfaefeacev1ebevcccfb!e1e!c1e`'lor more complex sorting needs, you can define functions to determine sorting order (seeBackbone`s documentation` and the solution to the exercise that follows).Exercise5orting a Collection with a Functionlet`s say we have the following collectionI var contacts - new 0ontactHanajer.0ontact0oJJectJon(2 {8 11rsL0amo ^11co,4 1asL0amo 1amooo }, {7 11rsL0amo 0oo,0 1asL0amo 0r1qoam0 },I0 {II 11rsL0amo ^11co,I2 1asL0amo ^rLsyI8 },I4 {Io 11rsL0amo ^11co,I 1asL0amo ^rLooI7 },I0 {I0 11rsL0amo oar11o,20 1asL0amo amoo112I },22 {`'https//github.com/davidsulc/marionette-gentle-introduction/commit/1fcvbbddfaefeacev1ebevcccfb!e1e!c1e`http//backbonejs.org/=Collection-comparatorDisplaying a Collection of Models !128 11rsL0amo ^11co,24 1asL0amo Sm1Lo2o },2 ]),lf you refresh the page, you`ll see the contacts in the following order- Alice Tampen- Alice Artsy- Alice Arten- Alice Smith- Bob Brigham- Charlie CampbellWhat we`d like in this case, is to have them sorted by first name, then by last name in case of equality.look at the documentation`` and see if you can figure out how to define a comparator function thatwill display our collection in the following order- Alice Arten- Alice Artsy- Alice Smith- Alice Tampen- Bob Brigham- Charlie CampbellYou can see the exercise`s solutions at the end of the book.``http//backbonejs.org/=Collection-comparator5tructuring Code with ModulesWhile building our app, we`ve simply been putting the code into 1oooxoLm1 so far. While that`s greatfor a small app, it won`t scale as our code base grows. So let`s refactor our code using Marionettemodules`. The basic strategy we`ll follow is this- one file for our general ContactManager app code (defining regions, the 1o1L1a11zoa1Lorhandler, etc.) assoLs/s/as- one module to manage our en::e: (i.e. models and collections), broken down into one file pertype, e.g. assoLs/s/ooL1L1os/cooLacLs- one module for each sub-application (e.g. the sub-application that will manage our contacts, orthe one that will manage our header menu), with sub-modules for each functional end result"(e.g. listing all contacts, or editing a single contact). lor these sub-modules, we`ll separatefunctionality into a cooLro11or and a v1ou, giving us z files. Here`s where we`d find the filesto |:: conoc:- assoLs/s/as/cooLacLs/11sL/11sL_cooLro11ors- assoLs/s/as/cooLacLs/11sL/11sL_v1ousThis might be a bit much to take in at once, so l suggest you come back to this later if it doesn`t quitemake sense yet. lt will be much easier to understand the concept in practice, so let`s get started. lfat any time you get overwhelmed by the architecture, you can refer to the diagram and explanationincluded at the end of the book.Credit where credit is due this structure is the one used by Brian Mann in his excellentscreen casts at BackboneRails.comExtracting our App Definitionlet`s start by defining the basics of our app in a separate file. So let`s move this code`https//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.application.module.mdhttp//www.backbonerails.com/Structuring Code with Modules !!Code to move from index.html to assets/js/app.jsI var ooLacLMaoaqor - new Mar1oooLLo^11caL1oo(),28 ooLacLMaoaqoraoo-oq1oos({4 ma1o-oq1oo ma1oroq1ooo }),from 1oooxoLm1 into assoLs/s/as (you`ll need to create that file, since it doesn`t exist yet).Naturally, we now need to include that javascript file in our 1oooxoLm1 by adding it at the end ofthe other javascript includesI ! !c )tscr!ot !c!aJcs rc crc 28 scrJpt src-/assoLs/s/as/scrJptWe`ll refactor more as we go along, but this is a good start.Moving Contacts to the Entities ModuleDefining a ModuleNow, we`ll move our contacts to a separate module. That way, we can centralize their management,and when our app needs the contacts data, it can simply request them. let`s start by creating a newMarionette module'I ooLacLMaoaqormooo1o(`-oL1L1os`, functJon(-oL1L1os, ooLacLMaoaqor,2 0ac-oooo, Mar1oooLLo, $, _){8 }),lines 1 and z are actually a single line in our application, but are displayed across z linesfor better readability. You will often come across this situation within the book, and youcan keep the code on one line if you`re following along.Save this file as assoLs/s/ooL1L1os/cooLacLs and include it within 1oooxoLm1 by adding it atthe end of the other javascript includes'https//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.application.module.mdStructuring Code with Modules !1I ! !c )tscr!ot !c!aJcs rc crc 28 scrJpt src-/assoLs/s/as/scrJpt4 scrJpt src-/assoLs/s/ooL1L1os/cooLacLs/scrJptWith the above module definition, we`ve defined a module on our ooLacLMaoaqor application. lfyou refer to the documentation, you`ll see that module definitions can be given a callback thattakes e arguments1. the module itself (i.e. what name we`re going to use within the callback to refer to the modulewe`re defining)z. the application object that mooo1o was called from!. Backbone1. Backbone.Marionette. jQuerye. UnderscoreAccessibility within ModulesStill quoting the documentation`You can add functions and data directly to your module to make them publiclyaccessible. You can also add private functions and data by using locally scoped variables.Consider the following codeI ooLacLMaoaqormooo1o(`-oL1L1os`, functJon(-oL1L1os, ooLacLMaoaqor,2 0ac-oooo, Mar1oooLLo, $, _){8 var a1orLr1vaLo - functJon(mossaqo){4 a1orL(r1vaLo a1orL + mossaqo),o },7 -oL1L1osa1orLoo11c - functJon(mossaqo){0 a1orL(1 u111 oou ca11 a1orLr1vaLo),0 a1orLr1vaLo(mossaqo),I0 },II }),lf you include that code (after the as file created above, of course), you could do the followinghttps//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.application.module.md=module-definitions`https//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.application.module.md=module-definitionsStructuring Code with Modules !ooLacLMaoaqor-oL1L1osa1orLoo11c(+o11o),And the following alerts would be displayed sequentially1. l will now call alertPrivatez. Private alert Helloln other words, you have access to the a1orLr1vaLo function from within the module callback.However, as soon as you leave that scope, a1orLr1vaLo can no longer be called it is effectively aprivate method within the callback.Moving the Contact EntitiesNow that we have a better understanding of modules, let`s move our contacts from 1oooxoLm1 intotheir moduleassets/js/entities/contact.jsI ooLacLMaoaqormooo1o(`-oL1L1os`, functJon(-oL1L1os, ooLacLMaoaqor,2 0ac-oooo, Mar1oooLLo, $, _){8 -oL1L1osooLacL - 0ac-ooooMooo1oxLooo({}),4o -oL1L1osooLacLo11ocL1oo - 0ac-ooooo11ocL1oooxLooo({ mooo1 -oL1L1osooLacL,7 comaraLor 11rsL0amo0 }),0 }),Notice that we`ve attached our model and collection as attributes to the noJv|e, andnot the o|:co:on as was the case before. ln other words, we`ve gone from (e.g.)ooLacLMaoaqorooLacL to -oL1L1osooLacL. And, as explained above, since we`reattaching them to the module, they will be publicly accessible (meaning we can accessthem from elsewhere in the application, if necessary).Since we`ve changed where our contact definitions are, we need to adapt our 1oooxoLm1Structuring Code with Modules !eI var contacts - new 0ontactHanajer.ntJtJes.0ontact0oJJectJon(2 .. oar cotct Jt ocs crc8 ]),Note we`ve simply changed ooLacLMaoaqorooLacLo11ocL1oo toooLacLMaoaqor-oL1L1osooLacLo11ocL1oosince the ooLacLo11ocL1oo is now attached to the -oL1L1os module, and no longer directly to theooLacLMaoaqor app.lf you refresh our page, everything will still be working properly even though we`re now using amodule to house our contacts, the application behaves as before.Getting our Contacts by Requestlet`s now improve our cooLacL entity file, by using Marionette.RequestResponse. According tothe documentationThis allows components in an application to request some information or work be doneby another part of the app, but without having to be explicitly coupled to the componentthat is performing the work.This will allow our app to request the contacts, and they will be provided by our module. But first,we need some code to initialize our contacts collection if it doesn`t existassets/js/entities/contact.jsI ooLacLMaoaqormooo1o(`-oL1L1os`, functJon(-oL1L1os, ooLacLMaoaqor,2 0ac-oooo, Mar1oooLLo, $, _){84 .. oJc! J co!!cct!o Jc1!!t!os rc crco var cooLacLs,70 var 1o1L1a11zoooLacLs - functJon(){0 cooLacLs - new -oL1L1osooLacLo11ocL1oo(|I0 { 1o I, 11rsL0amo `^11co`, 1asL0amo `^rLoo`,II oooo0omoor `ooo0I04` },I2 { 1o 2, 11rsL0amo `0oo`, 1asL0amo `0r1qoam`,https//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.requestresponse.mdStructuring Code with Modules !I8 oooo0omoor `ooo0I8` },I4 { 1o 8, 11rsL0amo `oar11o`, 1asL0amo `amoo11`,Io oooo0omoor `ooo0I20` }I |),I7 },I0I0 var ^1 - {20 qoLooLacL-oL1L1os functJon(){2I Jf(cooLacLs --- undefJned){22 1o1L1a11zoooLacLs(),28 }24 return cooLacLs,2o }2 },27 }),At this time, we`re not dealing with any persistent storage (server or client side), which willcome later. lgnoring persistence for now will let you better understand how to managedata in memory, and will demonstrate certain concepts introduced above, such as dataaccessibility.Note that we have added 1o attributes to our models, because we`re going to needan attribute to uniquely identify our models (within our application) whether or notpersistence is implemented.Remember how we discussed public versus private data within the module definition callback` Youcan see it at work here the cooLacLs collection is stored within the variable declared on line e. Thisvariable will remain private, as it wasn`t attached to the -oL1L1os module.On lines c-11, we define an 1o1L1a11zoooLacLs function that will allow us to create some contactsif necessary. Once again, this function hasn`t been attached to the model, so it will remain privateand it will not be possible to call it from elsewhere in the application. As a side note, in a typicalclient-server configuration, you wouldn`t create this type of data on the client (since you`d fetch itfrom the server). Nonetheless, this type of data initialization can be handy when dealing with datathat is relevant to the user but doesn`t need to be stored (or retrieved) server-side.As a rule, try to expose as little as possible via public functions and attributes this willlead to cleaner code and avoid coupling (by forcing data interactions to transit by definedinterfaces).On lines 1e-z!, we define an ^1 object to contain the functions we will allow the rest of theapplication to use. ln particular, notice that the qoLooLacL-oL1L1os function declared on line 1 canStructuring Code with Modules !creturn the cooLacLs variable, because it`s declared within the module definition`s callback function.Outside of this module definition, the cooLacLs variable won`t be readable, since it will be outof scope. ln addition, note that the qoLooLacL-oL1L1os function isn`t technically v||:c becauseit`s not attached to the -oL1L1os module. This is by design, since we want to force the rest of theapplication to get the contacts by using a request.How do requests work` Anywhere in our application, we can callooLacLMaoaqorroqoosL(cooLacLooL1L1os),and expect to get our cooLacLs collection as the return value.How does our application know what to do` We need to register a reqve: |onJ|er to call when thecooLacLooL1L1os request is received. let`s add it to the bottom of our contact moduleassets/js/entities/contact.jsI ooLacLMaoaqormooo1o(`-oL1L1os`, functJon(-oL1L1os, ooLacLMaoaqor,2 0ac-oooo, Mar1oooLLo, $, _){8 -oL1L1osooLacL - 0ac-ooooMooo1oxLooo({}),4o -oL1L1osooLacLo11ocL1oo - 0ac-ooooo11ocL1oooxLooo({ mooo1 -oL1L1osooLacL,7 comaraLor 11rsL0amo0 }),0I0 var cooLacLs,III2 var 1o1L1a11zoooLacLs - functJon(){I8 cooLacLs - new -oL1L1osooLacLo11ocL1oo(|I4 { 1o I, 11rsL0amo `^11co`, 1asL0amo `^rLoo`,Io oooo0omoor `ooo0I04` },I { 1o 2, 11rsL0amo `0oo`, 1asL0amo `0r1qoam`,I7 oooo0omoor `ooo0I8` },I0 { 1o 8, 11rsL0amo `oar11o`, 1asL0amo `amoo11`,I0 oooo0omoor `ooo0I20` }20 |),2I },2228 var ^1 - {24 qoLooLacL-oL1L1os functJon(){2o Jf(cooLacLs --- undefJned){2 1o1L1a11zoooLacLs(),Structuring Code with Modules !v27 }20 return cooLacLs,20 }80 },8I82 ooLacLMaoaqorroqrossoL+aoo1or(cooLacLooL1L1os, functJon(){88 return ^1qoLooLacL-oL1L1os(),84 }),8o }),What is this roqros attribute on line zv` lt`s the request-response" system, and it`sautomatically defined at the application level by Marionnette.As our new module is now functional, let`s change our 1o1L1a11zoa1Lor handler in 1oooxoLm1to request the contactsI ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){2 var cooLacLs - ooLacLMaoaqorroqoosL(cooLacLooL1L1os),84 .. rcst o1 tc J!cr coJco }),This is what our 1oooxoLm1 looks like nowindex.htmlI ! !c )tscr!ot !!orr, !c!aJcs rc crc 28 scrJpt src-/assoLs/s/as/scrJpt4 scrJpt src-/assoLs/s/ooL1L1os/cooLacLs/scrJpto scrJpt Lyo-LoxL/avascr1L7 ooLacLMaoaqorooLacL1Lomv1ou - Mar1oooLLo1Lomv1ouoxLooo({0 Laq0amo 11,0 Lom1aLo cooLacL11sL1LomI0 }),III2 ooLacLMaoaqorooLacLsv1ou - Mar1oooLLoo11ocL1oov1ouoxLooo({I8 Laq0amo o1,I4 1Lomv1ou ooLacLMaoaqorooLacL1Lomv1ouStructuring Code with Modules 1cIo }),II7 ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){I0 var cooLacLs - ooLacLMaoaqorroqoosL(cooLacLooL1L1os),I020 var cooLacLs.1sLv1ou - new ooLacLMaoaqorooLacLsv1ou({2I co11ocL1oo cooLacLs22 }),2824 ooLacLMaoaqorma1o-oq1oosoou(cooLacLs.1sLv1ou),2o }),227 ooLacLMaoaqorsLarL(),20 /scrJptlt`s starting to look a lot cleaner, isn`t it` But we`re not done yet.Creating a Module for the ContactsApp5ub-ApplicationSo far, we`ve created a separate module for our entities, and we`ve moved our contact model andcollection there. lf you think about it, the entities are general concepts that will be used throughoutthe ContactManager app. But our main ContactManager app could contain several sub-applications,such as- an app to manage contact information (create new contacts, edit their information, etc.);- an app to manage contact groups (friends, coworkers, etc.) and which contacts belong to them;- an app giving information about the ContactManager app (copyright info, compatibility, etc.);- and more.We`re going to create a module to contain our ContactsApp, which will in turn contain aooLacLs^.1sL sub-module to list our contacts. This .1sL sub-module will contain our controllerto manage listing the contacts, and it will also contain the required views. Our structure will thenlook like so- ContactManager- ContactsApp* list Controller +or:ov: +:e+:Structuring Code with Modules 11Moving our Viewslet`s declare our ooLacLs^.1sL sub-module so we can move our views from 1oooxoLm1 intothis new fileassets/js/apps/contacts/list/list_view.jsI ooLacLMaoaqormooo1o(`ooLacLs^.1sL`, functJon(.1sL, ooLacLMaoaqor,2 0ac-oooo, Mar1oooLLo, $, _){8 .1sLooLacL - Mar1oooLLo1Lomv1ouoxLooo({4 Laq0amo 11,o Lom1aLo cooLacL11sL1Lom }),70 .1sLooLacLs - Mar1oooLLoo11ocL1oov1ouoxLooo({0 Laq0amo o1,I0 1Lomv1ou .1sLooLacLII }),I2 }),We`ve renamed our ooLacLsv1ou to ooLacLs, and ooLacL1Lomv1ou to ooLacL. Thesenames will enable us to maintain the same naming conventions across modules, but weren`tavailable before ooLacLMaoaqorooLacL was our model definition. Now that view andentities are defined in separate modules, we no longer have naming conflicts and can pickthe appropriate names.With these new names in place, we`ve had to adapt our code on lines !, c, and 1c to usethem.Once again, the views are no longer attached to the ContactManager application, so we need toadapt our code on lines !, c, and 1c, by replacing ooLacLMaoaqor with .1sL since that`s what we`recalling our sub-module within the module definition callback (on line 1).We`vedeclared a ooLacLs^.1sL sub-module,butwe`veneverdeclared theooLacLs^ module. Then why does this code work` As explained in the documentation,When defining sub-modules using the dot-notation, the parent modules do not need toexist. They will be created for you if they don`t exist."Now, we need to adapt our 1oooxoLm1https//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.application.module.md=defining-sub-modules-with--notationStructuring Code with Modules 1zindex.htmlI scrJpt src-/assoLs/s/as/scrJpt2 scrJpt src-/assoLs/s/ooL1L1os/cooLacLs/scrJpt8 scrJpt src-/assoLs/s/as/cooLacLs/11sL/11sL_v1ous/scrJpt4o scrJpt Lyo-LoxL/avascr1L ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){7 var cooLacLs - ooLacLMaoaqorroqoosL(cooLacLooL1L1os),00 var cooLacLs.1sLv1ou - new ooLacLMaoaqorooLacLs^.1sLooLacLs({I0 co11ocL1oo cooLacLsII }),I2I8 ooLacLMaoaqorma1o-oq1oosoou(cooLacLs.1sLv1ou),I4 }),IoI ooLacLMaoaqorsLarL(),I7 /scrJptOnce again, don`t forget to include this new file on line !. Then, we need to adapt our viewinstantiation code on line v, as the view is no longer directly attached to ContactManager.So far, so good our app is still working, and our code keeps looking better!Creating a ControllerWhat is our .1sL controller going to do` lt`s basically the application equivalent of an orchestraconductor it coordinates the various pieces (typically models/collections and views), and gets themto produce a coherent result (i.e. a displayed page). later on, when we add routing to our application,typing in URls will fire various controller actions.Here`s our controller, again in a new fileStructuring Code with Modules 1!assets/js/apps/contacts/list/list_controller.jsI ooLacLMaoaqormooo1o(`ooLacLs^.1sL`, functJon(.1sL, ooLacLMaoaqor,2 0ac-oooo, Mar1oooLLo, $, _){8 .1sLooLro11or - {4 11sLooLacLs functJon(){o var cooLacLs - ooLacLMaoaqorroqoosL(cooLacLooL1L1os),7 var cooLacLs.1sLv1ou - new .1sLooLacLs({0 co11ocL1oo cooLacLs0 }),I0II ooLacLMaoaqorma1o-oq1oosoou(cooLacLs.1sLv1ou),I2 }I8 }I4 }),The first thing to notice, is that we`re defining this code within a ooLacLs^.1sL sub-module.Therefore, on line we can refer to our views (which are also defined within a ooLacLs^.1sLsub-module) with .1sLooLacLs.We`ve already declared a sub-module named ooLacLs^.1sL within our 11sL_v1ousfile, so how come we can declare it again` And not only that, but they must be the samemodule, since we can refer to a view with .1sLooLacLs. That`s because Marionette ishelping us out lf [the sub-module exists], [it] will be used instead of creating a new one"(see the documentation'). This conveniently allows us to have our controller and viewsdefined in separate files, while keeping them within the same Marionette sub-module.We`ve created a ooLro11or object attached to our sub-module on line !, where we`ll put all thefunctions we intend to be publicly available (such as the 11sLooLacLs function on line 1). Thesepublic methods will typically be the ones that are triggered by entering URls into the address bar.let`s see how these changes impact our index page'https//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.application.module.md=defining-sub-modules-with--notationStructuring Code with Modules 11index.htmlI scrJpt src-/assoLs/s/as/scrJpt2 scrJpt src-/assoLs/s/ooL1L1os/cooLacLs/scrJpt8 scrJpt src-/assoLs/s/as/cooLacLs/11sL/11sL_v1ous/scrJpt4 scrJpt src-/assoLs/s/as/cooLacLs/11sL/11sL_cooLro11ors/scrJpto scrJpt Lyo-LoxL/avascr1L7 ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){0 ooLacLMaoaqorooLacLs^.1sLooLro11or11sLooLacLs(),0 }),I0II ooLacLMaoaqorsLarL(),I2 /scrJptAs you`ve guessed, we`ve included the new file on line 1, then we simply call our controller`s actionon line c.Moving the App lnitialization HandlerThere`s not much left in our index page, but let`s finish cleaning up by moving our 1oL1a11zoa1Lorhandler code to our application fileCode to move from index.html to assets/js/app.jsI ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){2 ooLacLMaoaqorooLacLs^.1sLooLro11or11sLooLacLs(),8 }),Our as file now contains the following codeStructuring Code with Modules 1assets/js/app.jsI var ooLacLMaoaqor - new Mar1oooLLo^11caL1oo(),28 ooLacLMaoaqoraoo-oq1oos({4 ma1o-oq1oo ma1oroq1ooo }),7 ooLacLMaoaqoroo(1o1L1a11zoa1Lor, functJon(){0 ooLacLMaoaqorooLacLs^.1sLooLro11or11sLooLacLs(),0 }),Now, we`ve successfully refactored our app into nice little components, and the only things left inour 1oooxoLm1 are the file includes, the templates, and the code to call the sLarL method on ourapplicationI scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL1Lom2 - 11rsL0amo - 1asL0amo 8 /scrJpt4o ! !c )tscr!ot !!orr, !c!aJcs rc crc 7 ! 0ar )tscr!ot oo!!ct!o !c!aJcs rc crc 00 scrJpt Lyo-LoxL/avascr1LI0 ooLacLMaoaqorsLarL(),II /scrJptNote that since we`re starting our app after all javascript files have been loaded, andwe`re not modifying the DOM in any way, we don`t need to wrap our starter code ina $(oocomooL)roaoy() call (which would slow down startup). lf you application requireswaiting until the DOM is ready before starting, don`t forget to wrap the call to sLarL in a$(oocomooL)roaoy().Git commit refactoring the application into modulesadaefc1cvzd1d!!1fcec1vaecezdvaf!chttps//github.com/davidsulc/marionette-gentle-introduction/commit/adaefc1cvzd1d!!1fcec1vaecezdvaf!cStructuring Code with Modules 1eExerciseDeclaring a Template 5ub-ModuleWe want to access a 11sL1Lomv1ou template from within a dedicated sub-module withooLacLMaoaqorooLacLs^.1sL1om1aLos11sL1Lomv1ouWhat should our code look like` You can see the exercise solution at the end of the book.Dealing with TemplatesAlthough we`ve refactored our application, our templates haven`t moved. How come` Well, mainlybecause managing templates can easily be accomplished on the server, from the quick and dirtytechnique of including a file containing the templates, to more elegant solutions involving compiledtemplates (such as using RequireJS` or sprockets with Rails` asset pipeline). lf you`d like to learnmore about loading compiled templates from separate files using RequireJS, take a look at my bookon using RequireJS with Marionette.lor the sake of education, we`ll cover overriding Marionette`s template loader to demonstrate howwe could organize our templates differently. However, this won`t be part of the main text (or appdevelopment) refer to the Overriding Marionette`s Template loader" chapter at the end of the book.`http//requirejs.org/https//github.com/sstephenson/sprockets=javascript-templating-with-ejs-and-ecohttps//leanpub.com/structuring-backbone-with-requirejs-and-marionetteUsing a CompositeViewNow that we`ve done some house cleaning in our code base, let`s display our contacts within a table.lasy, right` We already have our contacts in a collection, so we simply need to render a Lr DOMelement for each one of them.let`s modify the contact template to make it generate the contents for a table rowModifying the contact template in index.htmlI scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL1Lom2 td- 11rsL0amo /tdtd- 1asL0amo /td8 /scrJptWe now need our table row to be wrapped within a Lr tag, so let`s modify line z in the ooLacLviewModifying the ooLacL view in assets/js/apps/contacts/list/list_view.jsI .1sLooLacL - Mar1oooLLo1Lomv1ouoxLooo({2 Laq0amo Lr,8 Lom1aLo cooLacL11sL1Lom,4o .. ctctJ!! coJc !s crc }),And last, but not least, we need our ooLacLs view to be contained within a table, instead of thecurrent o1 tag. let`s edit line z to change the tagUsing a CompositeView 1cModifying the ooLacLs view in assets/js/apps/contacts/list/list_view.jsI .1sLooLacLs - Mar1oooLLoo11ocL1oov1ouoxLooo({2 Laq0amo Lao1o,8 c1ass0amo Lao1o Lao1ooovor,4 1Lomv1ou .1sLooLacLo }),ln the code above, we`ve also taken the opportunity to add some styling classes to our table on line!, so that Bootstrap will style it for us (see documentation').Refresh the page, and our contacts are now displayed in our Lao1o. let`s now add lirst Name" andlast Name" column headers. How are we going to get our o11ocL1oov1ou to do this` Simpleanswer it can`t, because it wasn`t designed for this. loosly quoting the documentation, theo11ocL1oov1ou loops over a collection of models, renders each one with the provided 1Lomv1ouattribute, and adds all of those rendered views to the DOM element used by the o11ocL1oov1ou.Put another way, there`s no means to specify a template organizing content.Happily, Marionette won`t leave us high and dry the omos1Lov1ou` can be used for scenarioswhere a collection needs to be rendered within a wrapper template". So let`s create the templatewe`ll use for our new omos1Lov1ouTable template to add to index.htmlI scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL2 thead8 trth-1rsL 0amo/thth.asL 0amo/th/tr4 /theado tbody /tbody7 /scrJptWe`ve already altered our ooLacL item view to be a table row, so now we can move on to modifyingour ooLacLs view to become a omos1Lov1ou'http//twitter.github.io/bootstrap/base-css.html=tableshttps//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.collectionview.md`https//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.compositeview.mdUsing a CompositeView 1vModifying the ooLacLs view in assets/js/apps/contacts/list/list_view.jsI .1sLooLacLs - Mar1oooLLoomos1Lov1ouoxLooo({2 Laq0amo Lao1o,8 c1ass0amo Lao1o Lao1ooovor,4 Lom1aLo cooLacL11sL,o 1Lomv1ou .1sLooLacL, 1Lomv1ouooLa1oor Loooy7 }),There are ! main things you need to notice here- on line 1, we`ve changed our definition to inherit from Mar1oooLLoomos1Lov1ou instead ofo11ocL1oov1ou;- on line 1, we`ve specified the template our omos1Lov1ou should use;- on line e, we`ve told the omos1Lov1ou to render the child views within the Loooy element.let`s expand on that last point a omos1Lov1ou can be seen as a more powerful o11ocL1oov1ouwith a Lom1aLo attribute. Since it extends from a o11ocL1oov1ou, the omos1Lov1ou will bydefault simply append the rendered child views to its own DOM element. But we want the renderedchild views to go inside the Loooy tag, which we indicate via the 1Lomv1ouooLa1oor attribute online e.lor more complex scenarios where you need more control on where/how to insert therendered child views, you can override the aooo+Lm1 function in your omos1Lov1ou.Our ooLacLs view, being a omos1Lov1ou, naturally requires a collection to display. luckily, sinceit used to be a o11ocL1oov1ou, we`re already providing it with a collection on instantiationThe code instantiating our ooLacLs view in assets/js/apps/contacts/list/list_controller.jsI var cooLacLs.1sLv1ou - oou .1sLooLacLs({2 co11ocL1oo cooLacLs8 }),lt is much more than that, but this is a good description of what we`re going to use it for in this case.https//github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.compositeview.md=compositeviews-appendhtmlUsing a CompositeView cThere we go, our app now displays our contacts within a table, complete with headers!Displaying our contacts within a tableGit commit displaying our contacts with a CompositeView!1a1e1ev!aebfczved!1aevccze1edd'ExerciseBuilding your own CompositeViewNow that we`ve seen how to use a omos1Lov1ou, try to build one on your own to generate thefollowing end resultI dJv2 p+oro 1s Loo 11sL o1 a11 Loo cooLacLs uo oavo 1o1ormaL1oo 1or/p8 uJ4 JJ^11co ^rLoo/JJo JJ0oo 0r1qoam/JJ JJoar11o amoo11/JJ7 /uJ0 /dJvYou can see the exercise solution at the end of the book.Using EventsAs we saw earlier, we can define events and their associated handlers within views. let`s use thisability to toggle highlighting on the rows that get clicked, by toggling Bootsrap`s warning" class tothe appropriate Lr element'https//github.com/davidsulc/marionette-gentle-introduction/commit/!1a1e1ev!aebfczved!1aevccze1eddUsing a CompositeView 1assets/js/apps/contacts/list/list_view.jsI .1sLooLacL - Mar1oooLLo1Lomv1ouoxLooo({2 Laq0amo Lr,8 Lom1aLo cooLacL11sL1Lom,4o ovooLs { c11c- o1qo11qoL0amo7 },00 o1qo11qoL0amo functJon(){I0 thJs$o1Loqq1o1ass(`uaro1oq`),II }I2 }),The events object on lines - associates jQuery event listeners to handler functions. So in the abovecode on line e, we`re saying when this view`s DOMelement is clicked, call functiono1qo11qoL0amo".lach view instance has an o1 attribute referencing the rendered DOM element. So withina view definition, using Lo1so1 will return the DOM element containing the view. And aBackbone view o|:o has an $o1 attribute` which is different (and explained below).let`s look at line 1c each view has an $o1 attribute returning a jQuery object wrapping the view`sDOM element. ln other words, Lo1s$o1 is equivalent to $(Lo1so1) but it`s already convenientlyready for you to use. So in order to toggle the warning" class on our Lr containing the clicked itemview, we simply call jQuery`s Loqq1o1ass method on the view`s jQuery object.Here`s our table with a highlighted rowHighlighting the row that was clickedhttp//backbonejs.org/=View-el`http//backbonejs.org/=View-\protect\char"ccz1\relaxelhttp//api.jquery.com/toggleClass/Using a CompositeView zGit commit to toggle highlighting on the clicked rowcacz1bcae!1cece!1e!!z!ev1vc1aecc1'Accessing the Event ObjectSometimes, we need to access the jQuery event object'' that triggered the call to the handler function.This is typically the case with links we want to have links pointing to certain URls within ourapplication, but we want to prevent the links from causing a page refresh (which is the defaultbehavior). As you probably know, we can achieve this by calling rovooL0o1ao1L' on the c11c-event objectDemonstrating access to the Event ObjectI .1sLooLacL - Mar1oooLLo1Lomv1ouoxLooo({2 Laq0amo Lr,8 Lom1aLo cooLacL11sL1Lom,4o ovooLs { c11c- o1qo11qoL0amo7 },00 o1qo11qoL0amo functJon(o){I0 orovooL0o1ao1L(),II thJs$o1Loqq1o1ass(`uaro1oq`),I2 }I8 }),As you can see, the handler function will be provided the event object as an argument. So as longas you put it in the function signature, you`ll have full access to it within the function`s body.Note that in our case, preventing the default action doesn`t change any behavior. lnaddition, we won`t be including this line in our application`s code.'https//github.com/davidsulc/marionette-gentle-introduction/commit/cacz1bcae!1cece!1e!!z!ev1vc1aecc1''http//api.jquery.com/category/event-object/'http//api.jquery.com/event.preventDefault/Using a CompositeView !ExerciseDisplaying the Contents of a Clicked Table CellWrite an event handler that is triggered when the user clicks a Lo element. Make this handler displayan alert containing the text within the Lo element.Here are a few tips to get you going in the right direction- We discussed how to specify event selectors here- You can retrieve which DOM element initiated an event with oLarqoL'`- You can make DOM elements into jQuery objects by passing them to the $()function- You can retrieve a jQuery object`s text content with LoxL()'You can see the exercise solution at the end of the book.'`http//api.jquery.com/event.target/'http//api.jquery.com/text/Events, Bubbling, and TriggerMethodNow that we`ve got our contacts listed as we want them, let`s add a button to delete a contactModifying the contact template in index.htmlI scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL1Lom2 td- 11rsL0amo /td8 td- 1asL0amo /td4 tdo button c1ass-oLo oLosma11 J c1ass-1cooromovo/J7 0o1oLo0 /button0 /tdI0 /scrJptlines -c will generate a delete" button styled' with Bootstrap. We`ve also added an icon'' to ourbutton on line e, courtesy of Bootstrap.Since we`ve added a column to our item view, let`s keep things in sync by adding a column to thetable template (line e)Modifying the table template in index.htmlI scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL2 thead8 tr4 th-1rsL 0amo/tho th.asL 0amo/th th/th7 /tr0 /thead0 tbodyI0 /tbodyII /scrJpt'http//twitter.github.io/bootstrap/base-css.html=buttons''http//twitter.github.io/bootstrap/base-css.html=iconslvents, Bubbling, and TriggerMethod Displaying a delete buttonTake a look at our page, and you`ll see our delete" buttons. But if you click one of them, nothinghappens (except the row getting highlighted). So let`s add an event listener to our ooLacL view online Modifying the ooLacL view in assets/js/apps/contacts/list/list_view.jsI .1sLooLacL - Mar1oooLLo1Lomv1ouoxLooo({2 Laq0amo Lr,8 Lom1aLo cooLacL11sL1Lom,4o ovooLs { c11c- o1qo11qoL0amo,7 c11c- ooLLoo functJon(){ a1orL(oo1oLo ooLLoo uas c11c-oo), }0 },0I0 o1qo11qoL0amo functJon(o){II thJs$o1Loqq1o1ass(`uaro1oq`),I2 }I8 }),Our alert is properly displayed when we click a delete button, but its row was highlighted as anunwanted side-effect. The reason this happens is that the delete" button element we clicked islocated within the DOM`s Lr element when we click |e |von, we therefore also click |e ro+.And since we defined a listener for c11c- events on the Lr element (line e, above), the correspondinghandler is called.To prevent our row from being highlighted when we click the delete" button, we`ll simply hide"the click event from parent DOM elements with jQuery`s stopPropagation' on line 1'http//api.jquery.com/event.stopPropagation/lvents, Bubbling, and TriggerMethod eModifying the Contact view in assets/js/apps/contacts/list/list_view.jsI .1sLooLacL - Mar1oooLLo1Lomv1ouoxLooo({2 Laq0amo Lr,8 Lom1aLo cooLacL11sL1Lom,4o ovooLs { c11c- o1qo11qoL0amo,7 c11c- ooLLoo oo1oLo11c-oo0 },0I0 o1qo11qoL0amo functJon(o){II thJs$o1Loqq1o1ass(`uaro1oq`),I2 },I8I4 oo1oLo11c-oo functJon(o){Io osLoroaqaL1oo(),I a1orL(oo1oLo ooLLoo uas c11c-oo),I7 }I0 }),When we now click our button, jQuery stops the event from propagating the parent DOM elementsnever get notified about the c11c- event. Mission accomplished!What if l only want topropagation, not it7The basic answer is you won`t. lnstead, you can use a pub/sub mechanism so the parts ofyour app that need to respond will be notified when appropriate. But let`s not get ahead ofourselves, we`ll cover that later.Although our event handling works when clicking the delete" button, we can do much better. As itis, the event will trigger for ony ooLLoo element within our view not really the behavior we want.So let`s add a CSS class to make our selector more specificlvents, Bubbling, and TriggerMethod Adding a class to the contact template in index.htmlI scrJpt Lyo-LoxL/Lom1aLo 1o-cooLacL11sL1Lom2 td- 11rsL0amo /td8 td- 1asL0amo /td4 tdo button c1ass-oLo oLosma11 soo1oLo J c1ass-1cooromovo/J7 0o1oLo0 /button0 /tdI0 /scrJptUsing the CSS selectorI .1sLooLacL - Mar1oooLLo1Lomv1ouoxLooo({2 .. t\c J tco!tc ttr!oatcs84 ovooLs {o c11c- o1qo11qoL0amo, c11c- ooLLoosoo1oLo oo1oLo11c-oo7 },00 .. ctct J!cr 1act!osI0 }),You`ll notice l used a CSS class prefixed by s" it allows me to differentiate betweenthe CSS classes used for styling, and those used as selectors by the javascript functionality.This is particularly useful if you have designers and coders working on the same app,as it prevents app breakage designers removing a class they no longer need won`t breakjavascript functionlity, and coders doing away with unnecessary classes won`t break thepage display.Now that we`re pleased with our event selection, we can delete our contact when the button getsclickedlvents, Bubbling, and TriggerMethod cDeleting the model from the ooLacL view (assets/js/apps/contacts/list/list_view.js)I .1sLooLacL - Mar1oooLLo1Lomv1ouoxLooo({2 .. t\c J tco!tc ttr!oatcs84 ovooLs {o c11c- o1qo11qoL0amo, c11c- ooLLoosoo1oLo oo1oLo11c-oo7 },00 .. !!!t\c J!crI0II oo1oLo11c-oo functJon(o){I2 osLoroaqaL1oo(),I8 thJsmooo1co11ocL1ooromovo(thJsmooo1),I4 }Io }),Since we haven`t yet gotten around to implementing data persistence, our collection (and the modelsit contains) exists only in memory. So deleting" a model is simply a matter of removing it from thecollection on line 1!.Remember the scope we`re in an 1Lomv1ou instance. So within the view, we only have access to themodel that was provided to the view at instantiation. Although we don`t have direct access to thecooLacLs collection, each model keeps a reference to its parent collection within the co11ocL1ooattribute. Therefore, we can access our cooLacLs collection from within our ooLacL view instancewith Lo1smooo1co11ocL1oo.Once we`ve got a reference to the collection, all that`s left to do is call the romovo'` function, providingthe view`s model reference, and Marionette does the rest for us (closing the item view, unbindingevent listeners to avoid zombies', etc.). Done!Well, yes and no it`s functional, but it`s not quite clean. We`re impacting the application`s data bydeleting a contact, and processing data is the controller`s job views just display things. So let`s deleteour model the right way, by delegating that responsibility to our .1sLooLro11or object.What about the highlightName handler7We can leave that function in the view it simply changes the display without affectingdata, which is precisely the view`s role.'`http//backbonejs.org/=Collection-remove'http//lostechies.com/derickbailey/zc11/cv/1/zombies-run-managing-page-transitions-in-backbone-apps/This type of built-in management is exactly what makes Marionette so nice to work with. ln plain Backbone, you`d need to manage these actionson your own.lvents, Bubbling, and TriggerMethod vCommunicating via Eventslet`s trigger an event indicating a contact should be deleted instead of deleting it directly in theviewTriggering an event from the ooLacL view (assets/js/apps/contacts/list/list_view.js)I .1sLooLacL - Mar1oooLLo1Lomv1ouoxLooo({2 .. t\c J tco!tc ttr!oatcs84 ovooLs {o c11c- o1qo11qoL0amo, c11c- ooLLoosoo1oLo oo1oLo11c-oo7 },00 .. !!!t\c J!crI0II oo1oLo11c-oo functJon(o){I2 osLoroaqaL1oo(),I8 thJsLr1qqor(cooLacLoo1oLo, thJsmooo1),I4 }Io }),The view`s Lr1qqor method o