Client-side MVC with Backbone.js (reloaded)

8,661 views

Published on

- Why Backbone
- Architecture
- Real World
- Tips & Tricks
- Extras

Published in: Technology

Client-side MVC with Backbone.js (reloaded)

  1. 1. Client-side MVCwith Backbone.js
  2. 2. iglooigloolab.com michele.berto.li @iloveigloo @MicheleBertoli
  3. 3. Moniga Del Garda
  4. 4. Lago di Garda jQuery HTML5 UPLOADER JOBBERONE igloolab.com/jquery-html5-uploader jobberone.com SHARP SQUAREigloolab.com/sharpsquare KOALA POMODORO WEBAPP koooala.com pomodorowebapp.com
  5. 5. Agenda
  6. 6. Why Backbone.js 06:00 minArchitecture 14:00 minReal World 05:00 minTips & Tricks 06:00 minExtras 04:00 minQuestions NaN
  7. 7. WhyBackbone.js
  8. 8. Why Backbone.jsFrom server-side to client-side
  9. 9. Why Backbone.jsFrom server-side to client-sideWe need efficient tools
  10. 10. Why Backbone.jsjQuery is cool but…
  11. 11. Why Backbone.jsjQuery is cool but…We have to store object informations intothe DOM var list = ""; $.each(data, function (index, value) { list += "<li id="item-" + value.Id + "">" + value.Name + "</li>"; }); $("ul").append(list);
  12. 12. Why Backbone.jsjQuery is cool but…We have to store object informations intothe DOM var list = ""; $.each(data, function (index, value) { list += "<li id="item-" + value.Id + "">" + value.Name + "</li>"; }); $("ul").append(list);
  13. 13. Why Backbone.jsjQuery is cool but…jQuery callback hell $.getJSON("/Items", function (data) { var list = ""; $.each(data, function (index, value) { list += "<li id="item-" + value.Id + "">" + value.Name + "</li>"; }); $("ul").append(list); $("li").click(function () { var $this = $(this); var id = $this.attr("id").replace("item-", ""); $.post("/Items", { id: id }, function () { $this.fadeOut(function () { $this.remove(); }); }); }); });
  14. 14. Why Backbone.jsjQuery is cool but…jQuery callback hell $.getJSON("/Items", function (data) { var list = ""; $.each(data, function (index, value) { list += "<li id="item-" + value.Id + "">" + value.Name + "</li>"; }); $("ul").append(list); $("li").click(function () { var $this = $(this); var id = $this.attr("id").replace("item-", ""); $.post("/Items", { id: id }, function () { $this.fadeOut(function () { $this.remove(); }); }); }); });
  15. 15. Why Backbone.js“Its all too easy to create JavaScriptapplications that end up as tangled piles ofjQuery selectors and callbacks.”
  16. 16. Why Backbone.jsSo, what do we need? • Abstraction. • Decoupling UI from Data. • No more callbacks.
  17. 17. Why Backbone.jsSo, what do we need? (More practically)• A RESTful service based data layer.• Events (to keep UI and data up-to-date).• A template engine.• A solid routing system.• All the above things wrapped into a lightweight JavaScript framework.
  18. 18. Why Backbone.js It exists and it’s called: Backbone.js
  19. 19. Architecture
  20. 20. Architecture Oct 13th, 2010 Jeremy Ashkenas
  21. 21. Architecturehttp://documentcloud.github.com/backbonehttps://github.com/documentcloud/backbone@documentcloud#documentcloud on IRChttps://groups.google.com/forum/#!forum/backbonejs
  22. 22. ArchitectureBackbone.js gives structure to webapplications by providing models with key-value binding and custom events,collections with a rich API of enumerablefunctions, views with declarative eventhandling, and connects it all to your existingAPI over a RESTful JSON interface.
  23. 23. ArchitectureBackbone.js gives structure to webapplications by providing models with key-value binding and custom events,collections with a rich API of enumerablefunctions, views with declarative eventhandling, and connects it all to your existingAPI over a RESTful JSON interface.
  24. 24. ArchitectureBackbone.js gives structure to webapplications by providing models with key-value binding and custom events,collections with a rich API of enumerablefunctions, views with declarative eventhandling, and connects it all to your existingAPI over a RESTful JSON interface.
  25. 25. ArchitectureBackbone.js gives structure to webapplications by providing models with key-value binding and custom events,collections with a rich API of enumerablefunctions, views with declarative eventhandling, and connects it all to your existingAPI over a RESTful JSON interface.
  26. 26. ArchitectureBackbone.js gives structure to webapplications by providing models with key-value binding and custom events,collections with a rich API of enumerablefunctions, views with declarative eventhandling, and connects it all to your existingAPI over a RESTful JSON interface.
  27. 27. ArchitectureBackbone.js gives structure to webapplications by providing models with key-value binding and custom events,collections with a rich API of enumerablefunctions, views with declarative eventhandling, and connects it all to your existingAPI over a RESTful JSON interface.
  28. 28. ArchitectureDependencies:• jQuery or Zepto• Underscore.js• Json2.js
  29. 29. ArchitectureMVCModel / CollectionTemplate (View)View (Controller)Router
  30. 30. ArchitectureMVCModel / CollectionTemplate (View)View (Controller)Router
  31. 31. ArchitectureMVCModel / CollectionTemplate (View)View (Controller)Router
  32. 32. ArchitectureMVCModel / CollectionTemplate (View)View (Controller)Router
  33. 33. ArchitectureMVCModel / CollectionTemplate (View)View (Controller)Router
  34. 34. Model• Representing data (auto-generated).• Handling persistence.• Throws events.• Reusable.
  35. 35. ArchitectureModel / Collection - View - Template - Router - UtilitiesModel• Fetch HTTP GET /url• Save (new) HTTP POST /url• Save HTTP PUT /url/id• Destroy HTTP DELETE /url/id
  36. 36. ArchitectureModel / Collection - View - Template - Router - Utilities var Item = Backbone.Model.extend({ idAttribute: “Id”, urlRoot: “/Items” });
  37. 37. ArchitectureModel / Collection - View - Template - Router - Utilities var item = new Item(); item.set({ Name: “Igloo” }); // trigger change item.save(); // trigger sync
  38. 38. ArchitectureModel / Collection - View - Template - Router - UtilitiesModel• extend • toJSON • changedAttributes• constructor / initialize • fetch • previous• get • save • previousAttributes• set • destroy• escape • validate• has • isValid• unset • url• clear • urlRoot• id • parse• idAttribute • clone• cid • isNew• attributes • change• defaults • hasChanged
  39. 39. Collection• A list of models.• Underscore methods.
  40. 40. ArchitectureModel / Collection - View - Template - Router - Utilities var Items = Backbone.Collection.extend({ model: Item, url: "/Items" });
  41. 41. ArchitectureModel / Collection - View - Template - Router - Utilities var items = new Items(); items.fetch(); // trigger reset
  42. 42. ArchitectureModel / Collection - View - Template - Router - Utilities items.comparator = function(item) { return item.get("Name"); };
  43. 43. ArchitectureModel / Collection - View - Template - Router - UtilitiesCollection• extend • getByCid • etch• model • at • eset• constructor / initialize • length • create• models • comparator• toJSON • sort• add • pluck• remove • url• get • parse
  44. 44. ArchitectureModel / Collection - View - Template - Router - UtilitiesCollection • sortBy • groupBy• forEach (each) • sortedIndex• map • shuffle• reduce (foldl, inject) • toArray• reduceRight (foldr) • size• find (detect) • first• filter (select) • initial• reject • rest• every (all) • last• some (any) • without• include • indexOf• invoke • lastIndexOf• max • isEmpty• min • chain
  45. 45. View• Manipulates the DOM.• Delegates DOM events.• Has a Model / Collection.
  46. 46. ArchitectureModel / Collection - View - Template - Router - Utilities View View (Collection) View (Model)
  47. 47. ArchitectureModel / Collection - View - Template - Router - Utilities var ListView = Backbone.View.extend({ el: $("ul"), initialize: function () { this.collection.bind("reset", this.render, this); }, render: function () { this.collection.each(this.addItem, this); return this; }, addItem: function (item) { var itemView = new ItemView({ var ItemView = Backbone.View.extend({ model: item tagName: "li", }); render: function () { this.$el.append(itemView.el); this.$el.text(this.model.get("Name")); itemView.render(); return this; } } }); });
  48. 48. ArchitectureModel / Collection - View - Template - Router - Utilities var ListView = Backbone.View.extend({ el: $("ul"), initialize: function () { this.collection.bind("reset", this.render, this); }, render: function () { this.collection.each(this.addItem, this); return this; }, addItem: function (item) { var itemView = new ItemView({ var ItemView = Backbone.View.extend({ model: item tagName: "li", }); render: function () { this.$el.append(itemView.el); this.$el.text(this.model.get("Name")); itemView.render(); return this; } } }); });
  49. 49. ArchitectureModel / Collection - View - Template - Router - Utilities var ListView = Backbone.View.extend({ el: $("ul"), initialize: function () { this.collection.bind("reset", this.render, this); }, render: function () { this.collection.each(this.addItem, this); return this; }, addItem: function (item) { var itemView = new ItemView({ var ItemView = Backbone.View.extend({ model: item tagName: "li", }); render: function () { this.$el.append(itemView.el); this.$el.text(this.model.get("Name")); itemView.render(); return this; } } }); });
  50. 50. ArchitectureModel / Collection - View - Template - Router - Utilities var ListView = Backbone.View.extend({ el: $("ul"), initialize: function () { this.collection.bind("reset", this.render, this); }, render: function () { this.collection.each(this.addItem, this); return this; }, addItem: function (item) { var itemView = new ItemView({ var ItemView = Backbone.View.extend({ model: item tagName: "li", }); render: function () { this.$el.append(itemView.el); this.$el.text(this.model.get("Name")); itemView.render(); return this; } } }); });
  51. 51. ArchitectureModel / Collection - View - Template - Router - Utilities var ListView = Backbone.View.extend({ el: $("ul"), initialize: function () { this.collection.bind("reset", this.render, this); }, render: function () { this.collection.each(this.addItem, this); return this; }, addItem: function (item) { var itemView = new ItemView({ var ItemView = Backbone.View.extend({ model: item tagName: "li", }); render: function () { this.$el.append(itemView.el); this.$el.text(this.model.get("Name")); itemView.render(); return this; } } }); });
  52. 52. ArchitectureModel / Collection - View - Template - Router - Utilities var ListView = Backbone.View.extend({ el: $("ul"), initialize: function () { this.collection.bind("reset", this.render, this); }, render: function () { this.collection.each(this.addItem, this); return this; }, addItem: function (item) { var itemView = new ItemView({ var ItemView = Backbone.View.extend({ model: item tagName: "li", }); render: function () { this.$el.append(itemView.el); this.$el.text(this.model.get("Name")); itemView.render(); return this; } } }); });
  53. 53. ArchitectureModel / Collection - View - Template - Router - Utilities var items = new Items(); var listView = new ListView({ collection: items }); items.fetch();
  54. 54. ArchitectureModel / Collection - View - Template - Router - UtilitiesView • $ (jQuery or Zepto) • extend • render • constructor / initialize • remove • el • make • $el • delegateEvents • setElement • undelegateEvents • attributes
  55. 55. Template (Underscore.js)Compiles JavaScript templates into functionsthat can be evaluated for rendering.• Mustache• jQuery-tmpl
  56. 56. ArchitectureModel / Collection - View - Template - Router - Utilities <script type="text/template" id="item-template"> <li> <%= Name %> </li> </script>
  57. 57. ArchitectureModel / Collection - View - Template - Router - Utilities var ItemView = Backbone.View.extend({ … template: _.template($("#item-template").html()), ... render: function () { this.$el.html(this.template(this.model.toJSON())); return this; } … });
  58. 58. Router• Maps urls to function.• Enable history / bookmarking.
  59. 59. ArchitectureModel / Collection - View - Template - Router - Utilities var AppRouter = Backbone.Router.extend({ routes: { "": "init" }, init: function () { … } });
  60. 60. ArchitectureModel / Collection - View - Template - Router - Utilities window.AppRouter = Backbone.Router.extend({ routes: { "": "loadInvoices", "/add": "addInvoice", "/show/:id": "showInvoice", "/edit/:id": "editInvoice“ }, loadInvoices: function () { … }, addInvoice: function () { … }, showInvoice: function (id) { … }, editInvoice: function (id) { … } });
  61. 61. ArchitectureModel / Collection - View - Template - Router - UtilitiesRouter• extend• routes• constructor / initialize• route• navigate
  62. 62. Utilities• History• Sync• Utility
  63. 63. Architecture Model /Collection Data Router View Source Template
  64. 64. RealWorld
  65. 65. Real WorldPolar management• Smart invoicing web applicationTechnologies• .NET RESTful Web Services / MS SQL• Backbone.js
  66. 66. Real World Polar management
  67. 67. Real World
  68. 68. Real World
  69. 69. Real WorldPolar management window.AppRouter = Backbone.Router.extend({ routes: { … "/modifica/:id": "editInvoice“ }, editInvoice: function (id) { … } });
  70. 70. Real WorldPolar management window.AppRouter = Backbone.Router.extend({ routes: { … "/modifica/:id": "editInvoice“ }, editInvoice: function (id) { … } });
  71. 71. Real WorldKoala• Social media analyticsTechnologies• .NET RESTful Web Services / RavenDB• Backbone.js• Highcharts.js
  72. 72. Real World
  73. 73. Real World
  74. 74. Real WorldKoala window.Logs = Backbone.Collection.extend({ model: Log, url: "/Data", comparator: function (log) { return log.get("Date"); }, sum: function (field) { return this.reduce(function (memo, log) { return memo + log.get(field); }, 0); } });
  75. 75. Real WorldKoala window.Logs = Backbone.Collection.extend({ model: Log, url: "/Data", comparator: function (log) { return log.get("Date"); }, sum: function (field) { return this.reduce(function (memo, log) { return memo + log.get(field); }, 0); } });
  76. 76. Real WorldKoala window.Logs = Backbone.Collection.extend({ model: Log, url: "/Data", comparator: function (log) { return log.get("Date"); }, sum: function (field) { return this.reduce(function (memo, log) { return memo + log.get(field); }, 0); } });
  77. 77. Real WorldCammi• Custom newsletter engineTechnologies• .NET RESTful Web Services / MS SQL• Backbone.js
  78. 78. Real WorldCammi
  79. 79. Real WorldCammi
  80. 80. Real WorldCammi Load Load Groups Fetch Load User Fetch Load Load Companies
  81. 81. Real World Linkedin
  82. 82. Real World Linkedin
  83. 83. Real World WunderKit
  84. 84. Real World Groupon
  85. 85. Real World Basecamp
  86. 86. 3Tips &Tricks
  87. 87. Tips & TricksidAttribute idAttribute: “id” // CouchDB idAttribute: “_id” // .NET idAttribute: “Id”
  88. 88. Tips & Tricks Related Models
  89. 89. Tips & TricksRelated Models var Invoice = Backbone.Model.extend({ idAttribute: “Id” }); var Invoices = Backbone.Collection.extend({ model: Invoice, url: "/Invoices" });
  90. 90. Tips & Tricks Related Models
  91. 91. Tips & Tricks Related Models
  92. 92. Tips & TricksRelated Models var InvoiceDetail = Backbone.Model.extend({ idAttribute: “Id” }); var InvoiceDetails = Backbone.Collection.extend({ model: InvoiceDetail, url: "/InvoiceDetails“ });
  93. 93. Tips & TricksRelated Models var Invoice = Backbone.Model.extend({ idAttribute: "Id", initialize: function () { this.setInvoiceDetails(); }, setInvoiceDetails: function () { this.set({ InvoiceDetails: new InvoiceDetails(this.get("InvoiceDetails")) }); } });
  94. 94. Tips & Tricks Related Models
  95. 95. Tips & Tricks Related Models
  96. 96. Tips & TricksRelated Models var Invoice = Backbone.Model.extend({ idAttribute: "Id", initialize: function () { this.setInvoiceDetails(); this.bind("sync", this.setInvoiceDetails); }, setInvoiceDetails: function () { this.set({ InvoiceDetails: new InvoiceDetails(this.get("InvoiceDetails")) }); } });
  97. 97. Extras
  98. 98. ExtrasPlugins• Backbone-Nested• Backbone.Memento• Backbone.Validations• Backbone.localStorage• backbone.couchdb.js• …https://github.com/documentcloud/backbone/wiki/Extensions%2C-Plugins%2C-Resources
  99. 99. ExtrasTDD - Jasmine describe("Todo", function() { it("Should have a title", function() { var todo = new Todo(); expect(todo.get("title")).toBeDefined(); }); });
  100. 100. ExtrasBackbone is anti-SEOhttp://www.spiffyui.org#!csshttp://www.spiffyui.org?_escaped_fragment_=csshttp://coding.smashingmagazine.com/2011/09/27/searchable-dynamic-content-with-ajax-crawling/
  101. 101. Extras• http://sproutcore.com (Apple/iCloud)• http://knockoutjs.com• http://emberjs.com• http://batmanjs.org (Shopify)
  102. 102. ExtrasCheat Sheet• http://www.igloolab.com/downloads/backbone-cheatsheet.pdf
  103. 103. Backbone.js+• Lightweight• Powerful• Code is clean (and maintainable)-• Too verbose (for small applications)
  104. 104. 3 Lago di GardaQuestions ? Grazie www.igloolab.com @iloveigloo

×