Introduction to backbone presentation
-
Upload
brian-hogg -
Category
Technology
-
view
212 -
download
0
description
Transcript of Introduction to backbone presentation
![Page 1: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/1.jpg)
INTRODUCTION TOBACKBONE.JS WITH
WORDPRESS / Brian Hogg @brianhogg
![Page 2: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/2.jpg)
![Page 3: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/3.jpg)
AGENDAWhy Backbone.jsBasics of Backbone.js / Underscore.jsEnd-to-end example plugin ( )Github
![Page 4: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/4.jpg)
WHO ARE YOU?
![Page 5: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/5.jpg)
WHY BACKBONE?Enforces some structure on your JavaScriptEvents system
![Page 6: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/6.jpg)
WHY NOT JUST JQUERY?PerformanceLeveraging the communityRe-inventing the wheelCode structure (avoid 1000+ lines of jQuery that "just works")
![Page 7: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/7.jpg)
WHAT IS BACKBONE.JS?STRUCTURE (MV*)
Uses jQuery, but only hard requirement is Underscore.js
![Page 8: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/8.jpg)
WHAT ISUNDERSCORE.JS?
UTILITY FUNCTIONS WITH __.each_.templateLots more: http://documentcloud.github.io/underscore/
![Page 9: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/9.jpg)
TEMPLATESvar template = _.template("hello <%= name %>");var html = template({ name: 'Brian' });console.log( html ); // "hello Brian"
var template = _.template("<strong><%- value %></strong>");var html = template({ value: '<script>' });console.log( html ); // "<strong><script></strong>"
![Page 10: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/10.jpg)
ALTERNATIVESEMBER.JS, ANGULAR.JS, ...
Multiple ways of doing similar things. Even in Backbone.JS:
“It's common for folks just getting started to treatthe examples listed on this page as some sort ofgospel truth. In fact, Backbone.js is intended to
be fairly agnostic about many common patternsin client-side code.”
http://backbonejs.org/#FAQ-tim-toady
![Page 11: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/11.jpg)
BACKBONE /UNDERSCORE
INCLUDED IN WORDPRESS SINCE 3.5The "backbone" of the media manager, revisions UI
![Page 12: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/12.jpg)
MODELS“Models are the heart of any JavaScript
application, containing the interactive data aswell as a large part of the logic surrounding it:
conversions, validations, computed properties,and access control. You extend Backbone.Modelwith your domain-specific methods, and Model
provides a basic set of functionality formanaging changes.”
![Page 13: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/13.jpg)
MODEL EXAMPLEvar Post = Backbone.Model.extend({ defaults: { title: "", post_status: "draft" }, initialize: function() { console.log("creating a post"); }});
var post = new Post({ title: "Hello, world", post_status: "draft" });
var title = post.get("title"); // Hello, worldvar post_status = post.get("post_status"); // draft
All models have an id attribute for syncing up with a server
![Page 14: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/14.jpg)
LISTENING FOR CHANGESpost.on("change:title", function(model) { alert("Title changed to: " + model.get("title"));});
Or in the models initialize with:this.on("change:title", this.titleChanged);
![Page 15: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/15.jpg)
VIEWSUsed to turn a model into something you can seeAlways contains a DOM element (the el property), whetherits been added to the viewable page or not
![Page 16: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/16.jpg)
BARE MINIMUM TO USE BACKBONEvar PostView = Backbone.View.extend({ events: { "click .edit": "editPost", "change .post_status": "statusChanged" },
editPost: function(event) { // ... }, statusChanged: function(event) { // ... }});
var postView = new PostView({ el: '#my-form' });
![Page 17: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/17.jpg)
VIEW EXAMPLEvar PostView = Backbone.View.extend({ tagName: "div", // div by default className: "bbpost", // for styling via CSS events: { "click .edit": "editPost", "change .post_status": "statusChanged" },
initialize: { this.listenTo(this.model, "change", this.render); },
render: { // ... }});
![Page 18: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/18.jpg)
RENDERING THE VIEWvar template = _.template($("#tmpl-bbpost").html());var html = template(this.model.toJSON());this.$el.html(html);return this; // for chaining
This uses Underscore.js' _.template, but you can use another!
![Page 19: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/19.jpg)
ACCESSING THE DOM ELEMENTthis.$el
this.$el.html()
this.el
// From within a parent viewvar view = new PostView({ model: post });this.$el.append(view.render().el);
this.$this.$('.title').val()
![Page 20: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/20.jpg)
COLLECTIONSOrdered set of models
var Posts = Backbone.Collection.extend({ model: Post});
var post1 = new Post({ title: "Hello, world" });var post2 = new Post({ title: "Sample page" });
var myPosts = new Posts([ post1, post2 ]);
![Page 21: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/21.jpg)
POPULATING COLLECTIONS FROM THE SERVEROut of the box, Backbone.js supports RESTful APIs throughBackbone.sync(method, model, [options]):
create → POST /collectionread → GET /collection[/id]update → PUT /collection/idpatch → PATCH /collection/iddelete → DELETE /collection/id
![Page 22: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/22.jpg)
What Backbone expects when fetching/reading the collection:
[ { id: 1, title: "Hello, world" }, { ... }]
What this sends:wp_send_json_success( array( 'id': 1, 'title': 'Hello, world' ) );
{ success: true, data: [ { id: 1, title: "Hello, world" } ]}
![Page 23: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/23.jpg)
So, just override .parse() to accommodate:var Posts = Backbone.Collection.extend({ model: Post, url: ajaxurl, // defined for us if we're in /wp-admin parse: function( response ) { return response.data; }});
// Kick things off$(document).ready(function() { posts = new Posts(); postsView = new PostsView({ collection: posts }); posts.fetch({ data: { action: 'bbpost_fetch_posts' } });});
Or can override .sync(), or even .fetch()
![Page 24: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/24.jpg)
Note on calling .fetch() on page load:
“Note that fetch should not be used to populatecollections on page load — all models needed atload time should already be bootstrapped in to
place. fetch is intended for lazily-loading modelsfor interfaces that are not needed immediately:
for example, documents with collections of notesthat may be toggled open and closed.”
http://backbonejs.org/#Collection-fetch
Depends on the situation
![Page 25: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/25.jpg)
ROUTERSUsed for routing your application's URLs when using hash tags
(#)
![Page 26: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/26.jpg)
(CONTRIVED) EXAMPLEMANAGING WORDPRESS POST TITLES AND PUBLISH/DRAFT
STATUS IN AN ADMIN PANELDEMO
![Page 27: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/27.jpg)
DIRECTORY STRUCTUREplugins/ backbone-js-wp-example/ backbone-js-wp-example.php css/ admin.css js/ collections/ posts.js models/ post.js views/ post.js posts.js
![Page 28: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/28.jpg)
MODELS/POST.JSvar bbp = bbp || {};
(function($){ bbp.Post = Backbone.Model.extend({ });})(jQuery);
Could set defaults here, if creating new posts
![Page 29: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/29.jpg)
BACKBONE-JS-WP-EXAMPLE.PHP/*Plugin Name: Backbone.js WP ExamplePlugin URI:Description: Basic Backbone.js Example in WordPress to edit basic Post propertiesVersion: 1.0Author: Brian HoggAuthor URI: http://brianhogg.comLicense: GPL2*/
define( 'BBPOST_VERSION', 1 );
![Page 30: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/30.jpg)
BACKBONE-JS-WP-EXAMPLE.PHPSETTING UP ACTIONS
class BBPostAdmin { public function __construct() { if ( is_admin() ) { add_action( 'wp_ajax_bbpost_fetch_posts', array( &$this, 'ajax_fetch_posts' ) ); add_action( 'wp_ajax_bbpost_save_post', array( &$this, 'ajax_save_post' ) );
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { add_action( 'admin_menu', array( &$this, 'admin_menu' ) ); if ( isset( $_GET['page'] ) and 'bbpostadmin' == $_GET['page'] ) { add_action( 'admin_enqueue_scripts', array( &$this, 'enqueue_scripts' ) ); } } } }
![Page 31: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/31.jpg)
BACKBONE-JS-WP-EXAMPLE.PHPADDING THE MENU
add_menu_page( 'Backbone JS Post Admin Example', 'Backbone JS Post Admin Example', 'add_users'
admin_menu() function
![Page 32: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/32.jpg)
BACKBONE-JS-WP-EXAMPLE.PHPADDING THE SCRIPTS
// Add backbone.js models first, then collections, followed by views$folders = array( 'models', 'collections', 'views' );foreach ( $folders as $folder ) { foreach ( glob( dirname( __FILE__ ) . "/js/$folder/*.js" ) as $filename ) { $basename = basename( $filename ); wp_register_script( "$folder/$basename", plugins_url( "js/$folder/$basename", __FILE__ ), wp_enqueue_script( "$folder/$basename" ); }}
wp_register_style( 'bbpost.admin.css', plugins_url( 'css/admin.css', __FILE__ ), false, ECN_VERSION );wp_enqueue_style( 'bbpost.admin.css' );
enqueue_scripts() function
wp-util gives us the wp.ajax helper function
![Page 33: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/33.jpg)
ADMIN PAGE TEMPLATE<script id="tmpl-bbpost" type="text/html">
</script>
<h1>Backbone.js WordPress Post Admin Example</h1>
<div id="bbposts"></div>
<div class="bbpost"> <h2> </h2> Post title: <input type="text" class="title" value="<%- title %>" />, Status: <select class="post_status"> <option value=""></option> <option value="publish" <% if ( 'publish' == post_status ) { %>SELECTED <option value="draft" <% if ( 'draft' == post_status ) { %>SELECTED </select> <button>Update</button> </div>
<%- title %>
admin_page()
![Page 34: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/34.jpg)
ADMIN PAGE TEMPLATEINDIVIDUAL POST
<div class="bbpost"> <!-- will update when the model updates, automatically --> <h2> </h2> Post title: <input type="text" class="title" value="<%- title %>" />, Status: <select class="post_status"> <option value=""></option> <option value="publish" <% if ( 'publish' == post_status ) { %>SELECTED >Published <option value="draft" <% if ( 'draft' == post_status ) { %>SELECTED >Draft</ </select> <button>Update</button></div>
<%- title %>
<% } %>
![Page 35: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/35.jpg)
VIEWS/POSTS.JSvar bbp = bbp || {};
(function($){ bbp.PostsView = Backbone.View.extend({ el: '#bbposts', // Specifying an already existing element
initialize: function() { this.collection.bind('add', this.addOne, this); },
addOne: function(post) { var view = new bbp.PostView({ model: post }); this.$el.append(view.render().el); } });
$(document).ready(function() { bbp.posts = new bbp.PostsCollection(); bbp.postsView = new bbp.PostsView({ collection: bbp.posts }); bbp.posts.fetch({ data: { action: 'bbpost_fetch_posts' } }); });})(jQuery);
![Page 36: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/36.jpg)
VIEWS/POST.JSvar bbp = bbp || {};
(function($){ bbp.PostView = Backbone.View.extend({ className: 'bbpost',
initialize: function() { this.model.on("change", this.render, this); },
render: function() { var template = _.template($('#tmpl-bbpost').html()); var html = template(this.model.toJSON()); this.$el.html(html); return this; },
events: { 'click button': 'updatePost' },
updatePost: function() { this.model.set('title', this.$('.title').val()); this.model.set('post_status', this.$('.post_status').val()); this.model.save(); } });})(jQuery);
![Page 37: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/37.jpg)
BACKBONE-JS-WP-EXAMPLE.PHPFUNCTION TO SEND THE POST DATA
if ( ! current_user_can( 'edit_published_posts' ) ) wp_send_json_error();
$posts = get_posts( array( 'post_status' => 'any' ));$retval = array();foreach ( $posts as $post ) { $retval[] = array( 'id' => $post->ID, 'title' => $post->post_title, 'post_status' => $post->post_status, );}
wp_send_json_success( $retval );
ajax_fetch_posts()
![Page 38: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/38.jpg)
COLLECTIONS/POSTS.JSvar bbp = bbp || {};
(function($){ bbp.PostsCollection = Backbone.Collection.extend({ model: bbp.Post, url: ajaxurl, parse: function ( response ) { // This will be undefined if success: false return response.data; } });})(jQuery);
![Page 39: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/39.jpg)
SAVINGOVERRIDE SAVE() IN MODELS/POST.JS
var bbp = bbp || {};
(function($){ bbp.Post = Backbone.Model.extend({ save: function( attributes, options ) { options = options || {}; options.data = _.extend( options.data || {}, { action: 'bbpost_save_post', data: this.toJSON() }); var deferred = wp.ajax.send( options ); deferred.done( function() { alert('done'); }); deferred.fail( function() { alert('failed'); }); } });})(jQuery);
![Page 40: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/40.jpg)
BACKBONE-JS-WP-EXAMPLE.PHPSAVING A POST TITLE/STATUS
if ( ! $post = get_post( (int) $_POST['data']['id'] ) ) wp_send_json_error();
if ( ! current_user_can( 'edit_post', $post->ID ) ) wp_send_json_error();
if ( wp_update_post( array( 'ID' => $post->ID, 'post_title' => $_POST['data']['title'], 'post_status' => $_POST['data']['post_status'], ) ) == $post->ID ) wp_send_json_success();else wp_send_json_error();
ajax_save_post() function
![Page 41: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/41.jpg)
Extra work to set up initially, but worth it later on!
![Page 42: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/42.jpg)
WP-BACKBONESpecial versions of Backbone.View (wp.Backbone.View)
revisions.view.Frame = wp.Backbone.View.extend({ className: 'revisions', template: wp.template('revisions-frame'), // ...});
Handling of SubViewstemplates use <# #> instead of <% %> (as PHP can see <% %>as code: see for details)See revisions.js for an example
trac
![Page 43: Introduction to backbone presentation](https://reader033.fdocuments.net/reader033/viewer/2022052909/55983c131a28aba4398b45f3/html5/thumbnails/43.jpg)
RESOURCEShttps://github.com/brianhogg/backbone-js-wp-example
http://backbonejs.org/
http://backbonetutorials.com/
https://github.com/addyosmani/backbone-fundamentals
http://kadamwhite.github.io/talks/2014/backbone-wordpress-wpsessions
WordPress revisions.js