Road to mobile w/ Sinatra, jQuery Mobile, Spine.js and Mustache


Published on

Ruby is powerful server-side language with great collection of libraries and frameworks but to create a full mobile offering, Ruby developers need to become masters of many a craft. In this talk we'll walk through the design and development of a full stack HTML5 mobile application using Sinatra to create a robust RESTful API, Spine.js to bring MVC order to the client and jQuery Mobile to style and structure the application for the mobile world.

Published in: Technology, Business

Road to mobile w/ Sinatra, jQuery Mobile, Spine.js and Mustache

  1. 1. The Road toMobile Web Development with jqm, spine.mvc, sinatra and mustache By Brian Sam-Bodden 1
  2. 2. WHAT I HAVE FOR YOU...•A possible path to mobile web applications: • Sinatra + Mustache for a Simpler Server-Side • jQuery Mobile for Out-of-the-box Mobile • Spine.js for MVC goodness on the Client-Side • Where to start? Front-to-Back or Back-to-Front? 2 2
  4. 4. MOBILE WEB AGENT COMPUTING COMES OF AGE“...the future of computing is mobile... businesses should have their best developers working on their mobile applications” Google’s Eric Schmidt Interview on TechCrunch, April 2010 4 4
  5. 5. MOBILE WEB SOME STATISTICS• 20%: decline of home PC usage since 2008 (1)• 74%: increase of smart phones sold from 2010 to 2011(2)• 261%: increase in smart tablets sold from 2010 to 2011(3)• $9 billion: predicted US mobile shopping sales in 2011 (4)• 10.8%: people who used a mobile device to visit a retailer’s site on Cyber Monday (up from 3.9% in 2010) (4) 5 5
  6. 6. MOBILE WEB MOVE OVER PCS“Manufacturers shipped more smartphones than personal computers in the fourth quarter of 2010... crowning mobile devices as thecomputing platform of choice. Financial Times Article, February 2011 6 6
  7. 7. MOBILE WEB SEEN IN UNUSUAL PLACES• In a Mall Kiosk in Ft. Lauderdale, Florida: 7 7
  8. 8. 8
  9. 9. HTML5 WHAT YOU NEED TO KNOWBig Picture: Canvas, Video, Geolocation and Offline Web Apps 9 9
  10. 10. HTML5 WHAT YOU NEED TO KNOWBig Picture: IE Still Sucks! Who owns a windows phone anyways? :-) 10 10
  11. 11. HTML5 WHAT YOU NEED TO KNOW• Simplified header and doctype: <!DOCTYPE html>• Script tag doesn’t need type attribute• Many more semantic tags added like header, nav, section, article, aside, footer, details, summary, address, figure, output, time, pubdate, nav, first, last, next, prev, menu, command, mark, strong, progress, meter and many, many more• Data attributes (data-*)• Media Tags 11 11
  12. 12. HTML5 WHAT YOU NEED TO KNOW• Native GeoLocation API for Mobile Browsers• 2D Graphics with Canvas• Many new form input types• Datalist• Markup-driven form validation• Local Storage, Web Sockets, Web Workers 12 12
  14. 14. WEB OR NATIVE? MAKING AN INFORM DECISION• Number of Mobile Web Apps have quickly surpassed their native counterparts 14 14
  15. 15. WEB OR NATIVE? MAKING AN INFORM DECISION Taptu predicts that "theMobile Touch Web will grow...and will approach the quality ..of [Native] Apps across all the app categories except for games." From “Mobile App or Browser-Based Site? Report Says The Browser Will Win on Mobile” February 2010, 15 15
  16. 16. WEB OR NATIVE? MAKING AN INFORM DECISION Factor Native Web # of target More Devices == More Projects, Inconsistencies between One codebase (with small tweaks) to rule devices products them all distribution Application Stores Processes/Charge Upfront :-) Instant time to market Slow! Faster for simpler applications developer skills Specialized UI developer skills: iOS, Android, etc. HTML/JavaScript/CSS + Frameworks Audio/Video/ 2D and 3D graphics more accessible from native HTML 5 Video / Canvas coming along, multimedia APIs WebGL future uncertain(1) Touch Gestures / Accelerometer / Gyroscope / Camera / Geo-device integration location / File System / System Alerts more/only accessible Hacks abound to make some of these work from native APIs gamers, selective downloaders (only download if app provides anybody with a browser that it is inclined to audience significant advantages of others) and the “only if I can have an use it! icon for it” crowd 16 16
  17. 17. WEB OR NATIVE? MAKING AN INFORM DECISION• If your application core relies on 3D, File System, Camera, Mobile Security, System Alerts, Marketplace, Performance go Native• Ifyour application success hinges on ease of deployment and distribution, deeply linked pages, social media and constant updates/changes then go Web• Factors that are improving and/or are close to match their native counterparts include audio, video, 2D graphics, input and gestures, accelerometer and gyroscope, geolocation and native-like application launcher 17 17
  18. 18. WEB OR NATIVE? MAKING AN INFORM DECISION ... and there is always the hybrid approach! it for the Web, convert it to Native 18 18
  20. 20. APPROACH WHERE TO START?• Server-side developers gravitate to fleshing out the API first• Client-side developers start with the look and feel• After trying both I’ve decided that it is best to start at both ends and meet in the middle :-) 20 20
  22. 22. SINATRA A LIGHTWEIGHT SERVER SIDE ALTERNATIVE• Why? • Rails might be too heavy for our purposes • You will/might need to support native clients • API-driven and JSON is the payload 22 22
  23. 23. SINATRA A LIGHTWEIGHT SERVER SIDE ALTERNATIVE• Multiple mini-apps in one process... module Comida # # The Web App map / do # run Comida::ComidaWebApp class ComidaWebApp < Sinatra::Base end ... end map /api do run Comida::ComidaApi # end # The API # class ComidaApi < Sinatra::Base ... end end 23 23
  24. 24. MUSTACHE LOGIC-LESS TEMPLATES •I wanted simple templates that I could render on the client and on the server • No Ruby in my views, no markup in my Ruby! 24 24
  25. 25. SINATRA W/ MUSTACHE A LIGHTWEIGHT SERVER SIDE ALTERNATIVE• Classy with logic less templates... 25 25
  26. 26. SINATRA W/ MUSTACHE A LIGHTWEIGHT SERVER SIDE ALTERNATIVE• Render a mustache template (with a layout too). {{> search_page}} {{> search_results_page}} <script type="text/javascript" src="javascripts/search.js"></script> template/search.mustacheclass ComidaWebApp < Sinatra::Base register Mustache::Sinatra <section data-role="page" id="search_results"> require ./views/layout <header data-role="header"> <h1>Resturants</h1> get / do <nav data-role="navbar"> mustache :search <ul> end <li><a href="#home" class="ui-btn-active">Search</a></li> <li><a href="#menu">Menus</a></li> <li><a href="#order">Order</a></li> </ul> </nav> </header> <div data-role="content" id="content_main"> <form action="/api/menus.json" method="get" data-ajax="false" id="restaurant_selection_form"> <div id="restaurants_found"></div> <button type="submit" data-theme="a">Submit</button> </form> </div> </section><!-- /page --> template/search_result_page.mustache 26 26
  27. 27. SINATRA A LIGHTWEIGHT SERVER SIDE ALTERNATIVE• Simple API with Sinatra... get /search.json do response = {} response[:restaurants] = restaurants content_type :json response.to_json end• Let’s explore the sample’s app API with IRB and CURL 27 27
  29. 29. JQUERY MOBILE INTRODUCTION•Alightweight markup-driven User Interface (UI) framework for mobile web applications• Buildon JavaScript and making extensive use of the jQuery JavaScript Library (about 12K minified)• Promotes the use of clean, semantic HTML that gets enhanced progressively and degrades gracefully if needed• Supports a large variety of hardware and device features• Supports Accessible Rich Internet Applications (WAI-ARIA)• Theme-able following the ThemeRoller philosophy of jQuery UI 29 29
  30. 30. JQUERY MOBILE SETTING YOUR DEVELOPMENT ENVIRONMENT• Tostart on your path to web development for mobile devices you’ll need: • Editor: An editor capable of dealing with HTML, CSS and JavaScript and potentially with your server-side language/ platform/framework of choice • Emulation/Simulation: A way to emulate the different devices and resolutions that your application/website wants to target • Debugging: For more complex applications the ability to debug, trace and analyze JavaScript code 30 30
  32. 32. JQUERY MOBILE EMULATION CHOICES• The Mobile Web Development cycle involves coding, previewing often on a regular desktop/laptop web browser and interspersed testing on a particular device emulator or on the target device itself* (particularly to test the feel of any gesture based interaction, device orientation changes and other features that can only be experienced on the device itself)• Thesimplest way to test is to run a local Web Server on your development machine and access the application over a WIFI network 32 32
  33. 33. JQUERY MOBILE THE ANDROID EMULATOR• The Android SDK ( includes a device emulator that can support many Android Virtual Devices (AVDs). 33 33
  34. 34. JQUERY MOBILE THE ANDROID EMULATOR• The iOS Simulator ( is tucked away in Apple’s free iPhone Software Development Kit The iOS simulator can be found under /Developer/Platforms/iPhoneSimulator.platform/Developer/Applications and it is aptly named “iOS Simulator” 34 34
  36. 36. JQUERY MOBILE EMULATING A DEVICE• Let’s open the example_1.html page in Safari (5.1.2 shown below) at 1024x768: jQuery Mobileapplications can also be used on desktop, laptops and tablets part_1/example_1.html 36 36
  37. 37. JQUERY MOBILE EMULATING A DEVICE• In Safari (5.1.2) at 640x960 (iPhone 4 resolution): The iPhone, iPad and iPods use a mobile version of Safari so desktop Safari at iPhone/ iPad resolutions is a perfect browser for rapid development part_1/example_1.html 37 37
  38. 38. JQUERY MOBILE EMULATING A DEVICE• On the Android Emulator: part_1/example_1.html 38 38
  39. 39. JQUERY MOBILE EMULATING A DEVICE• On the iOS Emulator: part_1/example_1.html 39 39
  40. 40. JQUERY MOBILE EMULATING A DEVICE• On the iPhone 4: part_1/example_1.html 40 40
  41. 41. JQUERY MOBILE EMULATING A DEVICE• On the iPad part_1/example_1.html 41 41
  42. 42. JQUERY MOBILE EMULATING A DEVICE • The basic document contains a single Page with a Title and a Body showing some simple content • jQuery Mobile Documents can contain one or more mobile pages as well explore later inpart_1/example_1.html the course 42 42
  43. 43. JQUERY MOBILE GETTING STARTED• The HTML document source is shown below: <!DOCTYPE html> <html> <head> <title>Browser Page Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="" /> <script type="text/javascript" src=""></script> <script type="text/javascript" src=""></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Page Title</h1> </div><!-- /header --> <div data-role="content"> <p>This is the content</p> </div><!-- /content --> </div><!-- /page --> part_1/example_1.html </body> </html> 43 43
  44. 44. JQUERY MOBILE GETTING STARTED<body><div data-role="page"> • The body of the document <div data-role="header"> consists of several div elements <h1>Page Title</h1> </div><!-- /header --> • The div are decorated with <div data-role="content"> <p>This is the content</p> HTML5 data-role attributes </div><!-- /content --> • The outer div has a role of page</div><!-- /page --> and contains two stacked inner</body></html> divs with the roles header and content part_1/example_1.html 44 44
  45. 45. JQUERY MOBILE EMULATING A DEVICE• The link tag applies the jQuery Mobile CSS stylesheet to the document• Commenting out the CSS reveals the simplicity of the underlying markup <link rel="stylesheet" href="" /> part_1/example_1.html 45 45
  47. 47. MULTI-PAGE DOCS A DOCUMENT WITH A COUPLE OF PAGES<div data-role="page" id="home"> <div data-role="header"> <h1>Home</h1> </div><!-- /header --> <div data-role="content"> <p>This is the home page</p> </div><!-- /content --> <div data-role="footer" data-position="fixed"> <h4>The Footer</h4> </div><!-- /footer --></div><!-- /page --><div data-role="page" id="other"> <div data-role="header"> <h1>Other</h1> </div><!-- /header --> <div data-role="content"> <p>This is another page</p> </div><!-- /content --> <div data-role="footer" data-position="fixed"> <h4>The Footer</h4> </div><!-- /footer --> part_1/example_2.html</div><!-- /page --> 47 47
  48. 48. MULTI-PAGE DOCS LOCATION HASH BASED NAVIGATION• HTML5 provides the window.location.hash which is exploited by jQuery Mobile to provide navigation to individual pages within a multi-page document • Adding #other to the URL will navigate to the “other” page using the default transition (slide)http://.../part_1/example_2.html http://.../part_1/example_2.html#other 48 48
  49. 49. MULTI-PAGE DOCS LINKING PAGES• Let’s fill add navigation links to the other page from the home page and vice-versa:<div data-role="page" id="home"> <div data-role="page" id="other"> <div data-role="header"> <div data-role="header"> <h1>Home</h1> <h1>Other</h1> </div><!-- /header --> </div><!-- /header --> <div data-role="content"> <div data-role="content"> <p>This is the home page</p> <p>This is another page</p> <p>Check out this <a href="#other">other</a> page</p> <p>Take me <a href="#home">back!</a></p> </div><!-- /content --> </div><!-- /content --> <div data-role="footer" data-position="fixed"> <div data-role="footer" data-position="fixed"> <h4>The Footer</h4> <h4>The Footer</h4> </div><!-- /footer --> </div><!-- /footer --></div><!-- /page --> </div><!-- /page --> part_1/example_2.html 49 49
  50. 50. MULTI-PAGE DOCS BACK LINKS•Ageneric way to create a link to the previous page (withoutadding a new entry to the browser history) is to use the data-rel= “back” attribute as shown below: <div data-role="page" id="other"> <div data-role="header"> <h1>Other</h1> </div><!-- /header --> <div data-role="content"> <p>This is another page</p> <p>Take me <a href="#home" data-rel="back">back!</a></p> </div><!-- /content --> <div data-role="footer" data-position="fixed"> <h4>The Footer</h4> </div><!-- /footer --> </div><!-- /page --> part_1/example_2.html 50 50
  51. 51. MULTI-PAGE DOCS A DOCUMENT WITH A COUPLE OF PAGES• We can now navigate from #home to #other and back: part_1/example_2.html 51 51
  52. 52. PAGE TRANSITIONS ANIMATION BASED NAVIGATION• Sofar we have seen the default ‘slide’ transition when navigating from page to page• jQuery Mobile provides several transitions that we can apply via the data-transition attribute• Let’s modify the link to the “other” page to use the “flip” transition animation <div data-role="content"> <p>This is the home page</p> <p>Check out this <a href="#other" data-transition="flip">other</a> page</p> </div><!-- /content --> part_1/example_2.html 52 52
  53. 53. PAGE TRANSITIONS ANIMATION BASED NAVIGATION• The ‘flip’ transition animation in action: part_1/example_2.html 53 53
  54. 54. BUTTONS STYLIZED BUTTONS• jQuery Mobile provides a “button” data-role attribute that can be applied to a link to turn it into a nicely styled button• Let’s add a back button link to our “other” page <div data-role="page" id="other"> <div data-role="header"> <a href="#home" data-role="button" data-rel="back" data-icon="back" >Back</a> <h1>Other</h1> </div><!-- /header --> part_1/example_2.html 54 54
  55. 55. BUTTONS STYLIZED BUTTONS• The newly added back button: 55 55
  56. 56. LIST VIEWS STYLING ORDERED OR UNORDERED LISTS• jQuery Mobile provides a <div data-role="page" id="other"> ... “listview” data-role <div data-role="content"> <h3>Unordered List</h3> attribute that can turn an <ul data-role="listview"> <li>Apples</li> ordered or unordered list <li>Oranges</li> <li>Peaches</li> into a nicely styled native </ul> <h3>Ordered List</h3> looking list <ol data-role="listview"> <li>Woke up</li> <li>Fell out of bed</li>• Let’smodify the “other” <li>Dragged a comb across my head</li> </ol> page to show a couple of </div><!-- /content --> ... lists </div><!-- /page --> part_1/example_2.html 56 56
  57. 57. LIST VIEWS STYLING ORDERED OR UNORDERED LISTS• The styled lists on the ‘other’ page: 57 57
  58. 58. DEMO 1.0 LAUNCHING THE RESTAURANT MOBILE SITE• The beginnings of a mobile website for a restaurant• On the home page we want to display the restaurant’s name and a logo alongside some welcome text and a button link to a “menu” page• On the menu page we will display a list of menu items and a back button to the home page 58 58
  60. 60. INITIALIZATION USING THE JQUERY PLUGIN PATTERN WITH JQUERY MOBILE(function($) { var methods = { initPageOne : function(options) { }, initPageTwo : function(options) { }, initAllPages : function(options) { $().initApp("initPageOne"); $().initApp("initPageTwo"); } } $.fn.initApp = function(method) { // Method calling logic if ( methods[method] ) { return methods[ method ].apply( this, arguments, 1 )); } else if ( typeof method === object || ! method ) { return methods.initAllPages.apply( this, arguments ); } else { $.error( Method + method + does not exist ); } }})(jQuery); 60 60
  61. 61. INITIALIZATION USING THE JQUERY PLUGIN PATTERN WITH JQUERY MOBILE• Finally we can initialize the application by calling the initApp function from within a document ready handler function: <script> $(document).ready(function() { $().initApp(); }) </script> 61 61
  64. 64. SPINE.JS MVC FOR JAVASCRIPT• Spine.jsis a small library provides a micro-MVC framework for your JavaScript applications• Itallow you to create a separation between the model (business JavaScript code) and the view (which renders the DOM)• When models change their associated views are re-rendered without tightly coupling them to the DOM• Spine.js keeps state/model in a single space, model changes propagate automatically to the views with very little glue code 64 64
  66. 66. JQUERY SHOPPING CART DRAG AND DROP SHOPPING CART• Let’s walk through the code of a jQuery powered shopping cart from the ground up • The markup consists of two lists styled to appear side-by-side and an element showing the total amount of the items in the shopping cart • Each retail item will be represented by a div containing an image (drag handle), encode the item price in the div • As items are dragged into the cart, use an effect to alert the user of the cart total amount changes • The non-visual JS code uses the prototype pattern to separate the UI interactions from the business interactions • As items are dropped into the cart, add controls to the items to increase the quantity 66 66
  67. 67. JQUERY SHOPPING CART DRAG AND DROP SHOPPING CART• The jQuery powered Shopping Cart project structure is shown below: 67 67
  68. 68. JQUERY SHOPPING CART DRAG AND DROP SHOPPING CART• jQuery Shopping Cart in action: 68 68
  69. 69. JQUERY SHOPPING CART DRAG AND DROP SHOPPING CART• At first glance the implementation of the shopping cart seems to work as advertised and even seems well thought- out. That is, until we start asking the hard questions.• Shortcoming of the jQuery Shopping Cart: • From the usability point of view, the first thing that jumps to mind is, what happens when the user clicks the refresh button? • Since everything is just being kept in memory the answer is that it simply goes away 69 69
  70. 70. JQUERY SHOPPING CART DRAG AND DROP SHOPPING CART• Shortcoming of the jQuery Shopping Cart (cont.): • For anything more complex we would end up with an unmanageable mess of UI callbacks all of which are currently living in the global JavaScript scope. • Another problem glaring problem is the coupling of the concepts of the shopping cart and the items in the shopping cart. • The items are simple JavaScript objects with no behavior, their reflection on the UI is controlled by the decorateForCart function 70 70
  71. 71. SPINE.JS MVC FOR JAVASCRIPT• Spine.js is partly based on Backbone’s API yet Spine’s take on the MVC pattern is slightly different•I used Spine.js to refactor the jQuery Shopping Cart• Problems I wanted to fix on the shopping cart solution: • Using the back button or the refresh button loses the carts contents • UI callbacks and manual event handling and triggering can quickly get out of hand 71 71
  72. 72. SPINE.JS MVC FOR JAVASCRIPT• Models: InSpine, models are created using the setup method of Spine.Model, which takes the name of the model and an array of properties// Create the Item model.var Item = Spine.Model.sub();Item.configure("Item", "name", "pid", "price", "quantity"); part_2/examples/jquery-spine-shopping-cart/app/models/item.js 72 72
  73. 73. SPINE.JS MVC FOR JAVASCRIPT• Tomake the model persists between page reloads we extend the Item with the Spine.Model.Local module // Persist model between page reloads. Item.extend(Spine.Model.Local); part_2/examples/jquery-spine-shopping-cart/app/models/item.js• Theextend method adds class properties to the model. We now have an object that can be created, saved and retrieved from the browser local storage. 73 73
  74. 74. SPINE.JS MVC FOR JAVASCRIPT// Instance methodsItem.include({ // • To add behavior to our total: function() { return (this.price * this.quantity); model we use the }, // include method which adds instance properties increase: function(quantity) { quantity = (typeof(quantity) != undefined) ? quantity : 1; this.quantity = this.quantity + quantity;; }, // • The four methods that we need for our Item decrease: function(quantity) { quantity = (typeof(quantity) != undefined) ? quantity : 1; if (this.quantity >= quantity) { } this.quantity = this.quantity - quantity; model; increase, else { this.quantity = 0; decrease, total and label }; }, // label: function() { return ( + " - $" + this.price); }}); part_2/examples/jquery-spine-shopping-cart/app/models/item.js 74 74
  75. 75. SPINE.JS MVC FOR JAVASCRIPT• To instantiate an Item we use the create method which takes an object literal for the parameters. A new model can be persisted using the save method. When a model is saved it is assigned an identifier that can be retrieved via the id property.var item = new Item({name: "Product 1", pid: "0001" , price: 100.0, quantity: 1});;alert("Just saved Item with id => " +; 75 75
  76. 76. SPINE.JS MVC FOR JAVASCRIPT• Controllers: Controllersin Spine are a combination of a traditional MVC controller and a view. Therefore controllers are in charge of rendering and manipulating one or more models in the context of controller’s functionality• Our first Spine controller will deal with the rendering and manipulation of an individual Item. The CartItem controller will deal with user interface events to increase and decrease the quantity of a Item while keeping the user abreast of the changes. 76 76
  77. 77. SPINE.JS MVC FOR JAVASCRIPT• Spine controllers like the CartItem are created using the create method of Spine.Controller, which takes an object literal that a wide variety of properties jQuery(function($){ window.CartItem = Spine.Controller.sub({ init: function(){ var cartItem = this; this.item.bind("quantityChanged", function() { cartItem.updateQty() }); $(#item_ + + .add).live(click, function(e) { cartItem.add(); e.preventDefault(); }); $(#item_ + + .remove).live(click, function(e) { cartItem.remove(); e.preventDefault(); }); }, part_2/examples/jquery-spine-shopping-cart/app/controllers/cart_item.js 77 77
  78. 78. SPINE.JS MVC FOR JAVASCRIPT• ... cont. render: function(){ this.el = $.mustache($("#cartItem").html(), this.item); return this; }, // event handlers add: function(e) { this.item.increase(); }, remove: function(e) { this.item.decrease(); }, // ui methods updateQty: function() { $(#item_ + + #qty) .text(this.item.quantity) .effect("highlight", {}, 1500); } }); }) part_2/examples/jquery-spine-shopping-cart/app/controllers/cart_item.js 78 78
  79. 79. SPINE.JS MVC FOR JAVASCRIPT• The cartItem template is a Mustache.js Template that enables the creation of markup templates containing binding expressions. The mustache method clones the template contents and replaces the binding expressions ({{exp}}) with the values of the object passed, in our case the controller’s enclosed Item model. <!-- Mustache :-{)~ Template for CartItem --> <script type="text/x-mustache-tmpl" id="cartItem"> <li class="product ui-state-default" id="item_{{pid}}" price="{{price}}"> {{label}} (<span id="qty">{{quantity}}</span>) <a href="#" class="add">+</a> <a href="#" class="remove">-</a> </li> </script> part_2/examples/jquery-spine-shopping-cart/shopping_cart.html 79 79
  80. 80. SPINE.JS MVC FOR JAVASCRIPT• Totest our controller we need to instantiate an Item model and use it to instantiate the controller. We can then render the controller on the DOM of an HTML page var item = new Item({name: "Product 1", pid: "0001" , price: 100.0, quantity: 1}); var view = new CartItem({item: item}); $("#item").html(view.render().el); part_2/examples/jquery-spine-shopping-cart/tests/cart_item_test.html 80 80
  81. 81. SPINE.JS MVC FOR JAVASCRIPTjQuery(function($){ • The ShoppingCart window.ShoppingCart = Spine.Controller.sub({ el: $("#theCart"), controller which will manage init: function() { var cart = this; this.items = {}; a collection of Item models. $.each(Item.all(), function(){ cart.addItem(this); }); this.el.droppable({ accept: .product, drop: this.proxy(this.drop) }); $(#dump, this.el).live(click, function() { cart.clear(); }); Internally the }, // removes all items from the cart clear: function() { $.each(this.items, function(){ this.destroy(); }); this.items = {}; this.updateCartTotal(); ShoppingCart keeps the }, total: function() { items dropped in the items var sum = 0.0; $.each(this.items, function(){ sum +=; }); property • The clear, total, isEmpty return sum; }, isEmpty: function() { }, return this.itemsCount() == 0; and itemsCount methods itemsCount: function() { var size = 0; var items = this.items; fulfill the business $.each(items, function(){ if (items.hasOwnProperty(this)) size++; }); return size; functionality of the cart }, ... part_2/examples/jquery-spine-shopping-cart/app/controllers/shopping_cart.js 81 81
  82. 82. SPINE.JS MVC FOR JAVASCRIPT• The drop method handles drop events; it either creates a new item or increases the quantity of an existing item. It creates an Item model that is then rendered using the CartItem controller ... drop: function(ev, ui) { var item_dropped = ui.draggable; var pid = item_dropped.attr(id); var price = item_dropped.attr(price); var name = item_dropped.attr(name); if (this.items.hasOwnProperty(pid)) { this.items[pid].increase(); } else { var item = Item.create({name: name, pid: pid, price: price, quantity: 1}); this.addItem(item); $(".items").append(CartItem.init({item: item}).render().el); } }, part_2/examples/jquery-spine-shopping-cart/app/controllers/shopping_cart.js 82 82
  83. 83. SPINE.JS MVC FOR JAVASCRIPT• The render method render the #shoppingCart template, decorates the #dump button and loops through the contained Items creating a CartItem for each and rendering them in the .items ... render: function() { this.el.html($.mustache($("#shoppingCart").html(), {})); $(#dump).button(); $.each(this.items, function(){ $(".items").append(CartItem.init({item: this}).render().el); }); this.updateCartTotal(); }, part_2/examples/jquery-spine-shopping-cart/app/controllers/shopping_cart.js 83 83
  84. 84. SPINE.JS MVC FOR JAVASCRIPT• The removeItem, updateCartTotal, removeIfQuantityZero and addItem deal with responding to UI events and updating the UI ... removeItem: function(item) { $(#item_ +"puff", {}, "slow", function(){ $(this).remove(); }); }, updateCartTotal: function() { $(#total).text("highlight", {}, 1500); }, removeIfQuantityZero: function(item) { if (item.quantity == 0) { this.removeItem(item); delete this.items[]; item.destroy(); } }, addItem: function(item) { this.items[] = item; item.bind("quantityChanged", this.proxy(this.updateCartTotal)); item.bind("quantityChanged", this.proxy(this.removeIfQuantityZero)); item.bind("quantityChanged", function() { }); item.bind("destroy", this.proxy(this.removeItem));; this.updateCartTotal(); } part_2/examples/jquery-spine-shopping-cart/app/controllers/shopping_cart.js 84 84
  85. 85. SPINE.JS MVC FOR JAVASCRIPT• Finally to kick everything in motion the file application.js file begins by fetching any previously stored Item records, making the sample products draggable, creating a cart and rendering it. jQuery(function($){ Item.fetch(); $(".product").draggable({ helper: clone, opacity: "0.5" }); var cart = new ShoppingCart(); cart.render(); }); part_4/examples/jquery-spine-shopping-cart/app/application.js 85 85
  86. 86. RESOURCES 86
  87. 87. RESOURCES• Sinatra:• jQuery Mobile:• Spine.js:• Example Code: • • • 87 87