/index.html
HTML | 483 lines | 389 code | 88 blank | 6 comment | 0 complexity | e9d707b7ea94a9709ccf0354362c3666 MD5 | raw file
- <!doctype html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <title>Backbone — overview</title>
- <meta name="description" content="A framework for easily creating beautiful presentations using HTML">
- <meta name="author" content="Hakim El Hattab">
- <meta name="apple-mobile-web-app-capable" content="yes" />
- <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
- <link rel="stylesheet" href="css/reveal.css">
- <link rel="stylesheet" href="css/theme/default.css" id="theme">
- <!-- For syntax highlighting -->
- <link rel="stylesheet" href="lib/css/zenburn.css">
- <!-- If the query includes 'print-pdf', use the PDF print sheet -->
- <script>
- document.write( '<link rel="stylesheet" href="css/print/' + ( window.location.search.match( /print-pdf/gi ) ? 'pdf' : 'paper' ) + '.css" type="text/css" media="print">' );
- </script>
- <!--[if lt IE 9]>
- <script src="lib/js/html5shiv.js"></script>
- <![endif]-->
- </head>
- <body>
- <div class="reveal">
- <!-- Any section element inside of this container is displayed as a slide -->
- <div class="slides">
- <section>
- <h1>Backbone</h1>
- <h3>Building SPA. Overview.</h3>
- <p>
- <small>April 2013. Created for RIA (d) Competency Center</small>
- </p>
- </section>
- <section>
- <h2>What is Backbone</h2>
- <p>
- Gives structure to web applications with key-value binding and custom events, collections, views and connects to existing API over a RESTful JSON interface.
- </p>
- <aside class="notes">
- Oh hey, these are some notes. They'll be hidden in your presentation, but you can see them if you open the speaker notes window (hit 's' on your keyboard).
- </aside>
- </section>
- <section>
- <h2>Rest API server</h2>
- <img src="/img/resource-url-graph-1.0.png" alt="">
- </section>
- <section>
- <section>
- <h2>Events</h2>
- <pre><code>var object = {};
- _.extend(object, Backbone.Events);
- object.on("alert", function(msg) {
- alert("Triggered " + msg);
- });
- object.trigger("alert", "an event");</code></pre>
- </section>
- <section>
- <h2>Events</h2>
- <pre><code>book.on({
- "change:title": titleView.update,
- "change:author": authorPane.update,
- "destroy": bookView.remove
- });</code></pre>
- </section>
- </section>
- <section>
- <section>
- <h2>Models</h2>
- <p>
- <ul>
- <li>Data container</li>
- <li>Validation of data</li>
- <li>Conversion</li>
- <li>Computed properties</li>
- <li>Access control</li>
- </ul>
-
- </p>
- </section>
- <section>
- <h2>Models</h2>
- <pre><code contenteditable>
- app.Todo = Backbone.Model.extend({
- // Default attributes for the todo
- // and ensure that each todo created has `title` and `completed` keys.
- defaults: {
- title: '',
- completed: false
- },
- // Toggle the `completed` state of this todo item.
- toggle: function () {
- this.save({
- completed: !this.get('completed')
- });
- }
- });
- </code></pre>
- </section>
- <section>
- <h2>Model methods</h2>
- <ul>
- <li>get/ set — <small><code>note.get("title")</code></small> </li>
- <li>fetch / save / validate / destroy</li>
- <li>url — <small><code>/documents/7/notes/101</code></small></li>
- <li>parse</li>
- <li>clone</li>
- </ul>
- </section>
- <section>
- <h2>Model validation</h2>
- <pre><code>
- var Chapter = Backbone.Model.extend({
- validate: function(attrs, options) {
- if (attrs.end < attrs.start) {
- return "can't end before it starts";
- }
- }
- });
- var one = new Chapter({
- title : "Chapter One: The Beginning"
- });
- one.on("invalid", function(model, error) {
- alert(model.get("title") + " " + error);
- });
- one.save({
- start: 15,
- end: 10
- });
- </code></pre>
- </section>
- </section>
- <section>
- <section>
- <h2>Collections</h2>
- <p>Ordered sets of models
-
- </p>
- <p>An event that is triggered on a model in a collection will also be triggered on the collection</p>
- </section>
- <section>
- <h2>Collections</h2>
- <pre><code>var TodoList = Backbone.Collection.extend({
- model: app.Todo,
- // Save all of the todo items under the `"todos"` namespace.
- localStorage: new Backbone.LocalStorage('todos-backbone'),
- // Filter down the list of all todo items that are finished.
- completed: function () {
- return this.filter(function (todo) {
- return todo.get('completed');
- });
- },
- // Filter down the list to only todo items that are still not finished.
- remaining: function () {
- return this.without.apply(this, this.completed());
- },
- // We keep the Todos in sequential order, despite being saved by unordered
- // GUID in the database. This generates the next order number for new items.
- nextOrder: function () {
- if (!this.length) {
- return 1;
- }
- return this.last().get('order') + 1;
- },
- // Todos are sorted by their original insertion order.
- comparator: function (todo) {
- return todo.get('order');
- }
- });</code></pre>
- </section>
- <section>
- <h2>Collection methods</h2>
- <ul>
- <li>Underscore Methods: forEach/ map/ reduce ...</li>
- <li>add/ shift / pop / push / pluck / find...</li>
- <li>comparator</li>
- <li>fetch</li>
- </ul>
- </section>
- </section>
- <section>
- <section>
- <h2>Backbone.sync</h2>
- <p>Function called to read or save a model to the server.</p>
- <p>By default uses jQuery.ajax. Can be configured to use Web Sockets, XML transport or Local Storage.</p>
- </section>
- <section>
- <h2>Backbone.sync</h2>
- <pre><code>Backbone.sync(method, model, [options])</code></pre>
- <ul>
- <li><b>create → POST </b><tt>/collection</tt></li>
- <li><b>read → GET </b><tt>/collection[/id]</tt></li>
- <li><b>update → PUT </b><tt>/collection/id</tt></li>
- <li><b>delete → DELETE </b><tt>/collection/id</tt></li>
- </ul>
- </section>
- </section>
- <section>
- <section>
- <h2>Views</h2>
- <pre><code>// The DOM element for a todo item...
- app.TodoView = Backbone.View.extend({
- //... is a list tag.
- tagName: 'li',
- // Cache the template function for a single item.
- template: _.template($('#item-template').html()),
- // The DOM events specific to an item.
- events: {
- 'click .toggle': 'toggleCompleted',
- 'dblclick label': 'edit'
- },
- // The TodoView listens for changes to its model, re-rendering.
- initialize: function () {
- this.listenTo(this.model, 'change', this.render);
- },
- // Re-render the titles of the todo item.
- render: function () {
- this.$el.html(this.template(this.model.toJSON()));
- return this;
- },
- completeTodo: function(){
- this.model.save({
- 'completed': true
- });
- },
- editList: function() {
- return this.listForm(new EditListView({ model: bTask.views.activeListMenuItem.model }));
- },,...</code></pre>
- </section>
- </section>
- <section>
- <h2>Routes</h2>
- <pre><code>var Workspace = Backbone.Router.extend({
- routes: {
- '*filter': 'setFilter'
- },
- setFilter: function (param) {
- // Set the current filter to be used
- app.TodoFilter = param || '';
- // Trigger a collection filter event, causing hiding/unhiding
- // of Todo view items
- app.Todos.trigger('filter');
- }
- });
- app.TodoRouter = new Workspace();
- Backbone.history.start();</code></pre>
- </section>
- <section>
- <section>
- <h2>Testing </h2>
- <pre><code>suite('Lists', function() {
- var spyCreate = sinon.spy(gapi.client.tasks.tasklists, 'insert');
- setup(function() {
- spyCreate.reset();
- });
- test('Creating a list', function() {
- var $el = bTask.views.app.$el
- , listName = 'Example list';
- // Show the add list form
- $el.find('#add-list-button').click();
- // Fill out a value for the new list's title
- $el.find('#list_title').val(listName);
- $el.find('#list_title').parents('form').first().submit();
- // Make sure the spy has seen a call for a list being created
- assert.equal(1, spyCreate.callCount);
- // Ensure the expected UI element has been added
- assert.equal(listName, $('.list-menu-item:last').text().trim());
- });
-
- });</code></pre>
- </section>
- </section>
- <section>
- <section>
- <h2>Backbone common pitfalls: memory leaks</h2>
- <pre><code>var SomeModelView = Backbone.View.extend({
- initialize: function() {
- this.model.on('change', this.render, this);
- },
- render: function() {
- // render a template
- }
- });</code></pre>
- <p>Use</p>
- <pre><code>initialize: function() {
- this.listenTo(this.model, 'change', this.render);
- }</code></pre>
- </section>
- <section>
- <h2>Backbone common pitfalls: multiple DOM reflows</h2>
- <pre><code>render: function() {
- var self = this;
- this.$el.empty();
- // render each subview, appending to our root element
- _.each(this._views, function(subview) {
- self.$el.append(subview.render().el);
- });
- }</code></pre>
- <p>Use</p>
- <pre><code>render: function() {
- this.$el.empty();
- var container = document.createDocumentFragment();
- // render each subview, appending to our root element
- _.each(this._views, function(subview) {
- container.appendChild(subview.render().el)
- });
- this.$el.append(container);
- }</code></pre>
- </section>
- <section>
- <h2>Backbone common pitfalls: unnecessary XHR requests on page load</h2>
- <pre><code>
- initialize: function () {
- app.Todos.fetch();
- }
- </code></pre>
- <p>Use</p>
- <pre><code>
- var appInitialData = 'server_generated_json';
- ...
- initialize: function () {
- app.Todos.set(appInitialData);
- }
- </code></pre>
- </section>
- <section>
- <h2>Backbone common pitfalls: Non-optimistic AJAX</h2>
- <pre><code>saveName: function(e) {
- e.preventDefault();
- // get the new name from the input field
- var changedName = this.$('.name-input').val();
- // save it on the model
- this.model.save({name: changedName}, {
- success: function(model, response, options) {
- // render changes to the model
- },
- error: function(model, xhr, options) {
- // render an error message
- }
- });
- }</code></pre>
- <p>Use</p>
- <pre><code>saveName: function(e) {
- e.preventDefault();
- // get the new name from the input field
- var changedName = this.$('.name-input').val();
- // render changes to the model
- ...
- // save it on the model
- this.model.save({name: changedName}, {
- success: function(model, response, options) {
-
- },
- error: function(model, xhr, options) {
- // Notify of an error
- }
- });
- }</code></pre>
- </section>
- </section>
-
- <section>
- <h2>Articles and books</h2>
- <ul>
- <li><a href="http://info.apigee.com/Portals/62317/docs/web%20api.pdf">Rest API best practices</a></li>
- <li><a href="http://ozkatz.github.com/avoiding-common-backbonejs-pitfalls.html?tagref=js#gsc.tab=0">Avoiding Common Backbone.js Pitfalls</a></li>
- <li><a href="http://dailyjs.com/2013/02/07/backbone-tutorial-11/">Backbone tutorial from DailyJS</a></li>
-
- </ul>
- </section>
-
- <section>
- <h1>THE END</h1>
- </section>
- </div>
- </div>
- <script src="lib/js/head.min.js"></script>
- <script src="js/reveal.js"></script>
- <script>
- // Full list of configuration options available here:
- // https://github.com/hakimel/reveal.js#configuration
- Reveal.initialize({
- controls: true,
- progress: true,
- history: true,
- center: true,
- theme: Reveal.getQueryHash().theme , // available themes are in /css/theme
- transition: Reveal.getQueryHash().transition || 'linear', // default/cube/page/concave/zoom/linear/fade/none
- // Optional libraries used to extend on reveal.js
- dependencies: [
- { src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
- { src: 'plugin/markdown/showdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
- { src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
- { src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
- { src: 'plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
- { src: 'plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
- // { src: 'plugin/search/search.js', async: true, condition: function() { return !!document.body.classList; } }
- // { src: 'plugin/remotes/remotes.js', async: true, condition: function() { return !!document.body.classList; } }
- ]
- });
- </script>
- </body>
- </html>