vanjs backbone-powerpoint
DESCRIPTION
TRANSCRIPT
![Page 1: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/1.jpg)
Backbone in Multipage Apps
Michael Yagudaev@yagudaev
July 2013
![Page 2: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/2.jpg)
Outline About Me
Why Backbone?
Pain Points with Backbone
Design Patterns/Best Practices
Marionette.js
![Page 3: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/3.jpg)
About Me (@yagudaev)
Co-founder of 0idle.com – an online marketplace for event organizers to find the perfect venue.
Built 0idle using Rails + Backbone.js
Entrepreneur and Rails Developer
Worked with Node.js
Started Winnipeg.js User Group
Consulting/Freelance work
![Page 4: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/4.jpg)
Why Backbone.js? Simple
Flexible – use only the parts you need
Easy to integrate into existing code
Provides structure to your app
Proven
Well Documented (for the most part )
Good for hybrid apps
![Page 5: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/5.jpg)
5
A Pain in the Back... Due to its un-opinionated approach, backbone
can be a real pain in the a**.
No clear guidelines
Lots of boilerplate code
Does not provide helpers to solve common problems
Easy to get memory leaks by not being careful when using events (zombie views)
![Page 6: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/6.jpg)
Underline Principle for this talk
In any web system, the server should have the final say
Therefore, lets start developing server-side code first
Server-side code is easier to test (simple request/response)
Client-side functionality is to be considered as an added bonus in agile software development
You can do without backbone when you first start a project (KISS)
Assumption: a team of one
![Page 7: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/7.jpg)
7
Design PatternsLets start simple and work our way up...
![Page 8: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/8.jpg)
Scoping Your Selectors Problem: Overly generic jQuery selectors can
cause unexpected behavior when adding a new feature to a particular area of an application.
Example:
$(‘.btn-add’).click(addNewReply);
// Will conflict with:
$(‘.btn-add’).click(addNewMessage);
Solution: Use a backbone View
![Page 9: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/9.jpg)
var MessageView = Backbone.View.exend({ el: $('#messages-page'), events: { 'click .btn-add': 'addMessage' }, addMessage: function(ev) { $target = $(ev.currentTarget) // code to add message }}); var RepliesView = Backbone.View.exend({ el: $('#replies-page'), events: { 'click .btn-add': 'addReply' }, addMessage: function(ev) { $target = $(ev.currentTarget) // code to add message }}); $(function() { repliesView = new RepliesView(); messagesView = new MessagesView();});
![Page 10: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/10.jpg)
File Structure Problem: Your one javascript file becomes long and
hard to maintain. You need a better way to separate concerns.
Solution: Break down project into folders based on object types in backbone with a main.js file that acts as the entry point of the application and defines a namespace.
Notes: you will need to use a make or a make like solution to stitch the files together (e.g. Rails asset pipeline or h5bp build tool).
Note 2: Keep it simple. Avoid using an AMD loader like RequireJS at this stage.
![Page 11: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/11.jpg)
|____application.js -- manifest file (can have more than one)|____collections/|____lib/|____main.js|____models/|____templates/|____views/| |____messages_view.js| |____replies_view.js|____vendor/| |____backbone.js| |____jquery.js| |____underscore.js
File Structure (folders)
![Page 12: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/12.jpg)
File Structure (manifest)In Rails:
//= require jquery//= require underscore//= require backbone//= require main//= require_directory ./models//= require_directory ./lib//= require_directory ./collections//= require_directory ./views
![Page 13: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/13.jpg)
File Structure (files)window.APP_NAME = { Models: {}, Collections: {}, Views: {}, Lib: {} };
main.js -
views/messages_view.js -
APP_NAME.Views.MessagesView = Backbone.View.extend({...});
![Page 14: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/14.jpg)
Template
![Page 15: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/15.jpg)
Templates Problem: You need to dynamically generate
html content, but do not want pollute your js code with html markup.
Example: a dynamic file uploader allowing the user to upload any number of files.
Solution: place your html inside a script tag and use jQuery to extract the content of the template and then render it to the page. Alternatively you can use JST to give each template a separate file.
![Page 16: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/16.jpg)
16
Templates<script id="photo-thumbnail-template" type="text/template"> <div class="thumbnail"> <img src="{{image_url}}" /> {{title}} </div></script>
$thumbnail = $(Mustache.to_html($("#photo-thumbnail- template").html(), photo))$thumbnail.appendTo('.photos-preview.thumbnails')
![Page 17: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/17.jpg)
17
Template Sharing
![Page 18: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/18.jpg)
Template Sharing Problem: You have a template you want
rendered both on the client and server.
Example: you have a photo uploader that lets the user upload multiple photos and see photos that were already uploaded.
Solution: refactor the template into a mustache template and provide access to it from both the client and the server.
Limitation: cannot use helper methods (unless you are using Node.js)
![Page 19: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/19.jpg)
19
Template Sharing//..<%- @photos.each do |photo| -> <%= render 'photo_item', mustache: photo %><%- end %> //.. <script type="text/template" id="photo-item-template"> <%= render 'photo_item' %></script>
![Page 20: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/20.jpg)
Client-side View Injection
![Page 21: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/21.jpg)
Client-side View Injection
Problem: Similar to Template Sharing, but you are interested in re-using server-side helpers and do not care about filling in information in the template.
Example: a survey application which displays existing questions and allows to dynamically add new questions.
Solution: pre-render a partial somewhere in the DOM and to make it accessible to the client side code.
![Page 22: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/22.jpg)
22
Client-side View Injection
// ...addSpace: function() { var html = this.$('.btnAdd').data('view'); $('body').append(html);}// ...
<a href="#" class="btnAdd" data-view="<%= render 'space_card' %>"> Add Space</a>
![Page 23: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/23.jpg)
View Helpers Problem: You want to change the format in
which your information is displayed in the view, but the logic will be too complicated to be added directly in the view.
Example: Format a date.
Solution: Define a view helper to handle this functionality.
![Page 24: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/24.jpg)
24
// app/javascripts/helpers/application_helper.js
function formatDate(date) {
moment(date).format("MMM Do YY");
}
// if using handlebars
Handlebars.registerHelper("formatDate", formatDate);
// Usage (in the templates):
{{formatDate date}}
![Page 25: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/25.jpg)
Bootstrap Data Problem: You need to share data between the
client-side code and the server code. At the same time you would like to avoid incurring the cost of another HTTP request.
Example: You want to check if a user is logged in before you allow them to IM other users.
Solution: Use server-side processing to initialize your model(s).
![Page 26: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/26.jpg)
26
<script>(function() { var user; // preprocessed file to bootstrap variables from ruby to javascript window.ZI = { Config: {}, Models: {}, Collections: {}, Views: {}, Lib: {}, currentUser: function() { var user_data = <%=raw current_user ? current_user.to_json : 'null' %>; if (user_data) return user = user || new ZI.Models.User(user_data); return null; } }; // ... after the model has been loaded ... console.log(ZI.currentUser() === null); // not logged in console.log(ZI.currentUser() !== null); // logged in})();</script>
![Page 27: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/27.jpg)
27
Bootstrap Data (e.g. 2)
var photos = new Backbone.Collection; photos.reset(<%= @photos.to_json %>);
![Page 28: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/28.jpg)
Mixin Problem: You have code that is common
between several views or models, but it does not make sense to move code into a parent class.
Example: Code that allows you to open a message dialog and can be opened from several different views.
Solution: Use a mixin to include the common code in the target views or models.
![Page 29: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/29.jpg)
29
ZI.Mixins.Navigation = { openMessageDialog: function(ev) { ev.preventDefault(); return $('#message-modal').modal(); }}; App.Views.VenuesView = Backbone.View.extend( _.extend({}, App.Mixins.Navigation, { //..})); App.Views.MessagesView = Backbone.View.extend( _.extend({}, App.Mixins.Navigation, { //...}));
![Page 30: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/30.jpg)
30
![Page 31: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/31.jpg)
Parent-Child (Sub Views) Views
Problem: You have a view that needs to communicate with another view and can be thought of as logically containing that view.
Example: Updating a dropdown after a user creates a new item through a modal dialog.
Solution: Create a reference to the child view from the parent view and listen on events fired by the child view.
![Page 32: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/32.jpg)
32
ZI.Views.NewVenueModalView = Backbone.View.extend({ el: $('#new-venue-modal'), events: { 'click .btn-primary': 'save' }, initialize: function() { return this.formView = new ZI.Views.VenueFormView(); }, save: function() { var _this = this; return this.formView.save({ success: function() { _this.trigger('save', _this.formView.model); return _this.close(); }, error: function() { return _this.trigger('error', arguments); } }); }, open: function() { return this.$el.modal(); }, close: function() { return this.$el.modal('hide'); }});// singleton pattern ZI.Views.NewVenueModalView.getInstance = function() { return this.instance != null ? this.instance : this.instance = new this;};
Child View
![Page 33: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/33.jpg)
33
Parent View
var openNewVenueDialog = function(e, data) { var new_venue_modal_view = ZI.Views.NewVenueModalView.getInstance(); new_venue_modal_view.on('save', function(model) { $('#space_venue_id').append("<option>" + (model.get('name')) + "</ option>"); $('#space_venue_id').val(model.get('id')); }); new_venue_modal_view.open();};
![Page 34: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/34.jpg)
34
Two-Way Binding
![Page 35: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/35.jpg)
Two-Way Bindings Problem: You need to dynamically and
automatically update a UI element when the underling data changes.
Example: Recalculate and display the total amount in a shopping cart if the quantity of any of the items changes.
Solution: Use a two-way binding plugin for backbone called backbone.stickit.
![Page 36: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/36.jpg)
36
ZI.Views.EventDetailsBookView = Backbone.View.extend({ el: $('#event-details-booking-page'), model: new Booking(), bindings: { '.total-price': { observe: ['start_date', 'start_time', 'end_date', 'end_time'], onGet: function(values) { return '$' + this.calculateHoursBooked(values) * this.hourly_price; } }, '#booking_start_date': 'start_date', '#booking_end_date': 'end_date', '#booking_start_time': 'start_time', '#booking_end_time': 'end_time' }, initialize: function() { this.hourly_price = this.$el.data('hourly-price'); return this.stickit(); }, calculateHoursBooked: function(values) {//... }});
![Page 37: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/37.jpg)
Marionette.js Provides architectural infrastructure for
backbone.
View Management Layouts
Regions
Specialized View Types
Memory management
Messaging
Application - controllers, modules, etc
![Page 38: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/38.jpg)
38
QUESTIONS
![Page 39: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/39.jpg)
References Railscasts -
http://railscasts.com/episodes/196-nested-model-form-revised
Backbone Patterns: http://ricostacruz.com/backbone-patterns/
Backbone.js - http://backbonejs.org/
Marionette - http://marionettejs.com/
Backbone.Stickit - http://nytimes.github.io/backbone.stickit/
![Page 40: Vanjs backbone-powerpoint](https://reader033.vdocuments.net/reader033/viewer/2022051611/54b74f3d4a795900518b4664/html5/thumbnails/40.jpg)
40
References Handlebars - http://handlebarsjs.com/
Mustache - http://mustache.github.io/