Download - Building Bridges, Connecting Communities
![Page 1: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/1.jpg)
Building Bridges, Connecting Communities
VADIM MIRGORODFront-end, 05/22/2013
Using Backbone.js withDrupal 7 and 8
![Page 2: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/2.jpg)
Vadim Mirgorod
• Lead developer in Trellon
• Writing Backbone.js CookBook for PACKT
• Email: [email protected]
• Web: http://vmirgorod.name
• Twitter: @dealancer#2
![Page 3: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/3.jpg)
Remember the web development in 90s?
#3
![Page 4: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/4.jpg)
1995: JavaScript
#4
![Page 5: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/5.jpg)
2000: XMLHttpRequest
#5
![Page 6: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/6.jpg)
2006: jQuery
#6
![Page 7: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/7.jpg)
2013:
?#7
![Page 8: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/8.jpg)
What's new in JS?
• HTML5:– Local Storage– pushState
• JS templating engines:– Mustache.js– Twig.js
• Representative State Transfer (REST)
#8
![Page 9: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/9.jpg)
JavaScript client evolution
#9
![Page 10: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/10.jpg)
Complexity
#10
![Page 11: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/11.jpg)
Thin to thick transition
#11
![Page 12: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/12.jpg)
Performance
#12
![Page 13: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/13.jpg)
Problems!
![Page 14: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/14.jpg)
Right now typical AJAX code looks like this$(document).ready(function() {
$("#getData").click( function() {
$.getJSON("artistsRemote.cfc?method=getArtists&returnformat=json",
function(data) {
$("#artistsContent").empty();
$("#artistsTemplate").tmpl( data ).appendTo("#artistsContent");
var nowIs = new Date().toLocaleString();
$('#lastLoad').html( nowIs );
});
});
});
#14
![Page 15: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/15.jpg)
AJAX in Drupal
Have you seen any JS?
#15
![Page 16: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/16.jpg)
#16
![Page 17: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/17.jpg)
Let's do things properly!
#17
![Page 18: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/18.jpg)
Meet...
#18
![Page 19: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/19.jpg)
#19
![Page 20: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/20.jpg)
Backbone.js
• URL: http://backbonejs.org/
• Created by Jeremy Ashkenas in 2010, an author of CoffeeScript
• Based on Underscore.js: http://backbonejs.org/
• Requires jQuery or Zepto
#20
![Page 21: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/21.jpg)
Backbone.js features
• Minimalistic
• Modular
• Perfect OOP design
• Over 100 available extensions:
https://github.com/documentcloud/backbone/wiki/Extensions,-Plugins,-Resources
• Community
#21
![Page 22: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/22.jpg)
Backbone vs...
• Knockout
• AngularJS
• CanJS
• Spine
• Ember.js
• many others
#22
![Page 23: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/23.jpg)
Backbone vs...
#23
![Page 24: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/24.jpg)
Who uses Backbone.js?• Groupon Now!
• Foursquare
• LinkedIn Mobile
• Airbnb
#24
![Page 25: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/25.jpg)
Let's learn how to backbone!
#25
![Page 26: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/26.jpg)
Main concepts
• Model
• Collection
• View
• Template
• Router
• History
• Events
#26
![Page 27: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/27.jpg)
MVC: Backbone:
http://www.jboss.org/jdf/examples/ticket-monster/tutorial/UserFrontEnd/
#27
![Page 28: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/28.jpg)
DEMO!TODO APP
#28
![Page 29: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/29.jpg)
Easy example
![Page 30: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/30.jpg)
Define the model and the collection // Define new model.
var InvoiceItemModel = Backbone.Model.extend({
calculateAmount: function() {
return this.get('price') * this.get('quantity');
}
});
// Define new collection object.
var InvoiceItemCollection = Backbone.Collection.extend({
model: InvoiceItemModel
});
#30
![Page 31: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/31.jpg)
Define the view to render the model var InvoiceItemView = Backbone.View.extend({
// Define element tag name.
tagName: 'tr',
// Define template.
template: _.template($('#item-row-template').html()),
// Render the view.
render: function() {
var data = this.model.toJSON();
data.amount = this.model.calculateAmount();
$(this.el).html(this.template(data));
return this;
},
});#31
![Page 32: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/32.jpg)
Define the view to render the collection
var InvoiceItemListView = Backbone.View.extend({
tagName: 'table',
template: _.template($('#item-table-template').html()),
// Render the view.
render: function() {
$(this.el).html(this.template());
_.each(this.collection.models, function(model, key) { this.append(model); }, this);
return this;
},
// Add an invoice item row to the table.
append: function(model) {
$(this.el).append(new InvoiceItemView({ model: model }).render().el);
}
});#32
![Page 33: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/33.jpg)
Add templates into index.html <script type="text/html" class="template" id="item-table-
template">
<tr>
<th>Quantity</th>
<th>Description</th>
<th>Price</th>
<th>Amount</th>
</tr>
</script>
<script type="text/html" class="template" id="item-row-template">
<td><%= quantity %></td>
<td><%= description %></td>
<td><%= price %></td>
<td><%= amount %></td>
</script>#33
![Page 34: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/34.jpg)
Create collection and show the view var invoiceItemCollection = new InvoiceItemCollection([
{ description: 'Wooden Toy House', price: 22, quantity: 3 },
{ description: 'Farm Animal Set', price: 17, quantity: 1 },
]);
$('body').html(new InvoiceItemListView({
collection: invoiceItemCollection }).render().el
);
#34
![Page 35: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/35.jpg)
Some cool thingsTwo way binding
Model to view binding
LayoutsTemplatesRouter
Forms
![Page 36: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/36.jpg)
Model to view binding
var InvoiceItemView = Backbone.View.extend({
// ...
initialize: function() {
this.listenTo(this.model, 'destroy', this.destroy, this);
this.listenTo(this.model, 'change', this.render, this);
},
destroy: function() { this.remove(); }
});
var InvoiceItemListView = Backbone.View.extend({
// ...
initialize: function() {
this.listenTo(this.collection, 'add', this.append, this);
}
});#36
![Page 37: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/37.jpg)
Forms
// Backbone-forms extension.
var UserModel = Backbone.Model.extend({
schema: {
title: { type: 'Select', options: ['Mr', 'Mrs', 'Ms'] },
name: 'Text',
email: { validators: ['required', 'email'] },
password: 'Password',
birthday: 'Date',
}
});
userModel = new BuyerModel();
$('body').append(new Backbone.Form({ model: this.user }).form.render().el);#37
![Page 38: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/38.jpg)
Two-way binding
// Backbone.stickit extension.
var InvoiceItemFormView = Backbone.View.extend({
className: 'invoice-item-form-view',
bindings: {
'#description': 'description',
'#price': 'price',
'#quantity': 'quantity'
},
render: function() {
var html = '<label>Description:</label><input type="text" id="description"></input><br>' +
'<label>Price:</label><input type="text" id="price"></input><br>' +
'<label>Quantity:</label><input type="text" id="quantity"></input><br>';
$(this.el).html(html);
// Here binding occurs.
this.stickit();
return this;
}#38
![Page 39: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/39.jpg)
Forms
// Backbone-forms extension.
var UserModel = Backbone.Model.extend({
schema: {
title: { type: 'Select', options: ['Mr', 'Mrs', 'Ms'] },
name: 'Text',
email: { validators: ['required', 'email'] },
password: 'Password',
birthday: 'Date',
}
});
userModel = new BuyerModel();
$('body').append(new Backbone.Form({ model: this.user }).form.render().el);#39
![Page 40: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/40.jpg)
Router
var Workspace = Backbone.Router.extend({
routes: {
// Default path.
'': 'invoiceList',
// Usage of static path.
'invoice': 'invoiceList',
// Usage of fragment parameter.
'invoice/:id': 'invoicePage',
// Usage of fragment parameters.
'help/:topic/page:page': 'helpPage',
// Usage of splat parameter.
'download/*path': 'downloadPage'
},
});
#40
![Page 41: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/41.jpg)
Other cool things...
in Backbone.js Cookbook
![Page 42: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/42.jpg)
![Page 43: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/43.jpg)
• Bootstrapping:– Technique we saw above– Do it yourself
• Representational State Transfer:– Services module– RESTful webservices module
• Backbone.js module
Backbone and Drupal 7
#43
![Page 44: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/44.jpg)
REST
#44
![Page 45: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/45.jpg)
REST in Backbonevar PostModel = Backbone.Model.extend({
// Override id attribute.
idAttribute: '_id',
// Define URL root to access model resource. Otherwise use
// url() method to provide full path to the model resource.
urlRoot: function() { return 'http://example.com/posts/'; }
});
var PostCollection = Backbone.Collection.extend({
model: PostModel,
// Define path to the collection resource.
url: function() { return 'http://example.com/posts/'; }
});
#45
![Page 46: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/46.jpg)
REST in Backbone.js// Fetches data into a model.
model.fetch();
// Saves a model.
model.save();
// Destroys a model.
model.destroy();
// Fetches data into a collection.
collection.fetch();
// Adds models to a collection.
collection.add(models);
// Removes specific models from collection.
collection.remove(models);
#46
![Page 47: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/47.jpg)
Backbone module
• URL: http://drupal.org/project/backbone
• Provides models and collections for Drupal entities via REST:
– Node: Node model– All node: NodeIndex collection– Arbitrary view: NodeView collection
• Works with both Services and RESTful Web Services modules.
#47
![Page 48: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/48.jpg)
Backbone module
// Create new NodeView collection.
var viewCollection = new Drupal.Backbone.Collections.NodeView();
// Set Drupal View name.
viewCollection.viewName = 'backbone_example';
// Fetch data from the collection.
viewCollection.fetch({success: function() {
console.log(viewCollection.toJSON());
});
#48
![Page 49: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/49.jpg)
Backbone mdl roadmap• Support for bootstrapping
• Better views support
• In-place content editing
• Drag and Drop
• D8 version?
#49
![Page 50: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/50.jpg)
http://www.flickr.com/photos/gabblebee/3977912731/
![Page 51: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/51.jpg)
Backbone and Drupal 8• It is in core!
• Used for In-place editing issue:http://drupal.org/node/1824500
• Used for layouts issue:http://drupal.org/node/1841584
• Used for toolbar issue:http://drupal.org/node/1860434
• META issue: http://drupal.org/node/1858368
#51
![Page 52: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/52.jpg)
DEMO!
![Page 53: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/53.jpg)
One more thing!
• Web services initiative– REST in core– Storage controllers
• Twig– Templating engine– Twig in core (Twig sandbox)– Works both for PHP and JS
#53
![Page 54: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/54.jpg)
One more thing!
#54
Twig templatesStorage controllersAccess controllers
Render controllersForm controllers
DBBrowser
![Page 55: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/55.jpg)
One more thing!
#55
Backbone app
Twig templatesStorage controllersAccess controllers
Render controllersForm controllers
DB
REST
Browser
![Page 56: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/56.jpg)
One more thing!
#56
Backbone app
Twig templatesStorage controllersAccess controllers
Render controllersForm controllers
DB
REST
Browser
Mobile
![Page 57: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/57.jpg)
One more thing!
#57
Backbone app
Twig templates
Storage controllersAccess controllers
DB
REST
Mobile app built with PhoneGap or Trigger.io
![Page 58: Building Bridges, Connecting Communities](https://reader035.vdocuments.site/reader035/viewer/2022062410/56815b11550346895dc8baed/html5/thumbnails/58.jpg)
Building Bridges, Connecting Communities
Evaluate this session at: portland2013.drupal.org/node/1578.
Thank you!
What did you think?