KEMBAR78
Writing HTML5 Web Apps using Backbone.js and GAE | PPTX
Writing HTML5 Web Apps

          Google App Engine

             Backbone.js

              Require.js

                jQuery



           Ron Reiter © 2012
Agenda
 Why do you need to learn how to program HTML5 web
  apps?

 A walkthrough over the To-Do list anatomy
   https://github.com/ronreiter/webapp-boilerplate
Why?
 Web Apps = Software as a Service
   Cross OS/platform/browser
   Cuts costs on deployment and maintenance
   Scales easily
      Google App Engine, Amazon, Heroku, etc.

 Mobile Apps
   Cross device development cuts development costs
      WebView
      PhoneGap
Brief Introduction
 Google App Engine - Solid, scalable server framework
   Platform as a Service

 Backbone.js - Proven MVC framework
   LinkedIn mobile, Foursquare, Do.com, Groupon, Posterous,
    Basecamp mobile, Kicksend, etc...

 Require.js - Modular JavaScript Loader
   Module dependency management
   JavaScript minification & bundling

 jQuery - DOM Manipulation Framework
   Creating dynamic content and replacing Flash
The To-Do List
Web App Architecture

             Front End
            Backbone.js




                      REST API


            Back End
         Google App Engine
Back-End
Dataset
 We want to create a Todo list item table.

 Start by adding a Google App Engine model


# the Todo model.
class Todo(db.Model):
 content = db.StringProperty()
 done = db.BooleanProperty()
 order = db.IntegerProperty()
Request Handler
 Serves all web requests

 We implement a main handler and REST API

def main():
 application = webapp.WSGIApplication([
  # index.html
  ('/', MainHandler),


  # REST interface
  ('/todos', TodoListHandler),
  ('/todos/(d+)', TodoItemHandler),
 ], debug=True)
 util.run_wsgi_app(application)
Main Request Handler
 When we access http://www.todolist.com, the app is
  downloaded to our computer and starts to run.

class MainHandler(webapp.RequestHandler):
 def get(self):
   self.response.out.write(
      template.render("index.html", {}))
REST API Standard
 REST API is used to let clients control datasets, using four
  CRUD operations:
    Create a new item – using HTTP POST requests
    Read a list of items – using HTTP GET requests
    Update a single item – using HTTP PUT requests
    Delete a single item – using HTTP DELETE requests

 Similar to SQL, but this is a customized interface and not a
  way to access a database

 REST API uses XML or JSON serialization (Javascript Object
  Notation) to encode and decode objects

 We’ll use JSON
REST API – GET (get all tasks)
class TodoListHandler (webapp.RequestHandler):
 def get(self):
  # serialize all Todos,
  # include the ID in the response
  todos = []


  for todo in Todo.all():
   todos.append({
     "id" : todo.key().id(),
     "content" : todo.content,
     "done" : todo.done,
     "order" : todo.order,
   })


   # send them to the client as JSON
   self.response.out.write(simplejson.dumps(todos))
REST API – POST (add a new task)
class TodoListHandler (webapp.RequestHandler):
 def post(self):
  data = simplejson.loads(self.request.body) # load JSON data of the object


  todo = Todo(
   content = data["content"],
   done = data["done"],
   order = data["order"],
  ).put() # create the todo item


  # send it back, and include the new ID.
  self.response.out.write(simplejson.dumps({
   "id" : todo.id(),
   "content" : data["content"],
   "done" : data["done"],
   "order" : data["order"],
  }))
REST API – PUT (update a task)
class TodoItemHandler (webapp.RequestHandler):
 def put(self, id):
  data = simplejson.loads(self.request.body) # load the updated model


  todo = Todo.get_by_id(int(id)) # get it model using the ID from the request path
  todo.content = data["content"]
  todo.done = data["done"]
  todo.order = data["order"]
  todo.put() # update all fields and save to the DB


  # send it back using the updated values
  self.response.out.write(simplejson.dumps({
   "id" : id,
   "content" : todo.content,
   "done" : todo.done,
   "order" : todo.order,
  }))
REST API – DELETE (delete a task)
class TodoItemHandler (webapp.RequestHandler):

 def delete(self, id):



  # find the requested model and delete it.

  todo = Todo.get_by_id(int(id))

  todo.delete()
Front-End
Backbone.js Architecture – MVC
   Server Model                     Database

               Backbone REST Sync


    Model                                 View
 Backbone.Model                         HTML + CSS

                             DOM Manipulation
                             With jQuery and
                             templating


                        Controller
                        Backbone.View           View Events
Model Events
Backbone.js Architecture – REST Sync



Collection Operations   Collection      Model Operations

      GET /tasks                          PUT /tasks/38
      POST /tasks        View   Model     DELETE /tasks/38
                                          PUT /tasks/39
                         View   Model     DELETE /tasks/39
                                          PUT /tasks/40
                         View   Model     DELETE /tasks/40
                                          PUT /tasks/41
                         View   Model     DELETE /tasks/41
Web App Directory Structure
 index.html – Main entry point
    css
      todos.css – Defines the style
    js
      libs
          require.js, jQuery, Backbone, Underscore
      models
          todo.js – The todo item model
      collections
          todos.js – The todo item collection
      views
          todos.js – The todo item view
          App.js – The app view
      templates
          stats.html
          todo.html – The todo item template
      main.js – Require.js entry point
index.html
 Loads the stylesheet

<link

  rel="stylesheet"

  href="css/todos.css”/>

 Loads the main.js script
<script
  data-main="js/main"
  src="js/libs/require/require.js">
</script>
main.js
 Configures paths and known libraries

 text is used for require.js text loading (for templates)


require.config({
 paths: {
      jquery: 'libs/jquery/jquery-min',
      underscore: 'libs/underscore/underscore-min',
      backbone: 'libs/backbone/backbone-optamd3-min',
      text: 'libs/require/text'
 }
});
main.js – cont.
 Load the app view (views/app.js)

 Notice there is no need to add the JS extension

 Require.js supplies us with a function to run Javascript
  code only after certain modules have been loaded.

 This allows us to create a dependency model, and a new
  way to write Javascript modules.


require(['views/app'], function(AppView){
 var app_view = new AppView;
});
views/app.js – The AppView
 Backbone's "View" is actually a "View Controller". The view
  itself is the template combined with CSS.

 Creating a new view either means
   creating a new DOM element using JavaScript/jQuery or
    templating
   Using an existing one in the DOM

 Since there is only one app, we’ll use an existing element
  for the AppView.

 However, task views are more dynamic, and they will
  create new DOM elements.
views/app.js – The AppView (cont.)
 The define function allows us to depend on
  libraries, template files and other modules we wrote.

 Every dependency in the list corresponds to an argument
   of the function to execute once all modules are loaded.
define([
 'jquery’, 'underscore', 'backbone',
 'collections/todos’, 'views/todos',
 'text!templates/stats.html'
 ], function($, _, Backbone,
Todos, TodoView, statsTemplate) {
   var AppView = Backbone.View.extend({ ...
views/app.js – The AppView (cont.)
 The "View" captures and delegates events on DOM
  elements


events: {
 "keypress #new-todo": "createOnEnter",
 "click .todo-clear a": "clearCompleted”
},
views/app.js – The AppView (cont.)
 We add some handlers on the Todos collection to get
  notified when it's updated.

 Then, we fetch the Todos collection from the server.

 Once the data is loaded, addAll will be executed.


initialize: function() {
 Todos.bind('add',         this.addOne);
 Todos.bind('reset', this.addAll);


 Todos.fetch();
},
collections/todos.js – Todo Collection
       Backbone Collections are model arrays which synchronize with the server.

       The AppView listens for changes on this collection, and can add new models to it.

define([
 'underscore', 'backbone', 'models/todo’
], function(_, Backbone, Todo){
 var TodosCollection = Backbone.Collection.extend({
    model: Todo,
    url: '/todos',
    done: function() {
        return this.filter(function(todo){
         return todo.get('done');
        });
    }
 });
models/todo.js – Todo Model
 Holds the Todo item data

 Defines the default values and methods related to the data

 The "define" function needs to return the model class. When
  "model/todo" will be required, it will be received.


define(['underscore', 'backbone'], function(_, Backbone) {
 var TodoModel = Backbone.Model.extend({
      defaults: { content: "empty todo...”, done: false, order: 0 }
 });
 return TodoModel;
});
views/todos.js – Todo View
 Bind the view to the model

 Render function uses the model data to render the template


define(['jquery', 'underscore', 'backbone’, 'models/todo',
 'text!templates/todos.html'
 ], function($, _, Backbone, Todo, todosTemplate){
 var TodoView = Backbone.View.extend({
  model: Todo,
  template: _.template(todosTemplate),
  initialize: function() {
   this.model.bind('change', this.render);
   this.model.bind('destroy', this.remove);
  },
  render: function() {
   $(this.el).html(this.template(this.model.toJSON()));
       ...
views/todos.js – Todo View
(cont.)
 Manipulate the view's model according to triggered events


events: {
    "click .check" : "toggleDone",
    ...
}


// Toggle the "done" state of the model.
toggleDone: function() {
    this.model.save({done : !this.model.get("done")});
},
templates/todos.html
 Template files are used to build the views either:
   Once (and then update using jQuery)
   On every update (if you're lazy)

 Use <%- ... -> for escaping HTML

<div class="todo <%= done ? 'done' : '' %>">
 <div class="display">
  <input class="check"
   type="checkbox" <%= done ? 'checked="checked"' : '' %> />
  <div class="todo-content"><%- content %></div>
  <span class="todo-destroy"></span>
 </div>
 <div class="edit">
  <input class="todo-input" type="text" value="<%- content %>" />
 </div>
</div>
Questions?

Writing HTML5 Web Apps using Backbone.js and GAE

  • 1.
    Writing HTML5 WebApps Google App Engine Backbone.js Require.js jQuery Ron Reiter © 2012
  • 2.
    Agenda  Why doyou need to learn how to program HTML5 web apps?  A walkthrough over the To-Do list anatomy  https://github.com/ronreiter/webapp-boilerplate
  • 3.
    Why?  Web Apps= Software as a Service  Cross OS/platform/browser  Cuts costs on deployment and maintenance  Scales easily  Google App Engine, Amazon, Heroku, etc.  Mobile Apps  Cross device development cuts development costs  WebView  PhoneGap
  • 4.
    Brief Introduction  GoogleApp Engine - Solid, scalable server framework  Platform as a Service  Backbone.js - Proven MVC framework  LinkedIn mobile, Foursquare, Do.com, Groupon, Posterous, Basecamp mobile, Kicksend, etc...  Require.js - Modular JavaScript Loader  Module dependency management  JavaScript minification & bundling  jQuery - DOM Manipulation Framework  Creating dynamic content and replacing Flash
  • 5.
  • 6.
    Web App Architecture Front End Backbone.js REST API Back End Google App Engine
  • 7.
  • 8.
    Dataset  We wantto create a Todo list item table.  Start by adding a Google App Engine model # the Todo model. class Todo(db.Model): content = db.StringProperty() done = db.BooleanProperty() order = db.IntegerProperty()
  • 9.
    Request Handler  Servesall web requests  We implement a main handler and REST API def main(): application = webapp.WSGIApplication([ # index.html ('/', MainHandler), # REST interface ('/todos', TodoListHandler), ('/todos/(d+)', TodoItemHandler), ], debug=True) util.run_wsgi_app(application)
  • 10.
    Main Request Handler When we access http://www.todolist.com, the app is downloaded to our computer and starts to run. class MainHandler(webapp.RequestHandler): def get(self): self.response.out.write( template.render("index.html", {}))
  • 11.
    REST API Standard REST API is used to let clients control datasets, using four CRUD operations:  Create a new item – using HTTP POST requests  Read a list of items – using HTTP GET requests  Update a single item – using HTTP PUT requests  Delete a single item – using HTTP DELETE requests  Similar to SQL, but this is a customized interface and not a way to access a database  REST API uses XML or JSON serialization (Javascript Object Notation) to encode and decode objects  We’ll use JSON
  • 12.
    REST API –GET (get all tasks) class TodoListHandler (webapp.RequestHandler): def get(self): # serialize all Todos, # include the ID in the response todos = [] for todo in Todo.all(): todos.append({ "id" : todo.key().id(), "content" : todo.content, "done" : todo.done, "order" : todo.order, }) # send them to the client as JSON self.response.out.write(simplejson.dumps(todos))
  • 13.
    REST API –POST (add a new task) class TodoListHandler (webapp.RequestHandler): def post(self): data = simplejson.loads(self.request.body) # load JSON data of the object todo = Todo( content = data["content"], done = data["done"], order = data["order"], ).put() # create the todo item # send it back, and include the new ID. self.response.out.write(simplejson.dumps({ "id" : todo.id(), "content" : data["content"], "done" : data["done"], "order" : data["order"], }))
  • 14.
    REST API –PUT (update a task) class TodoItemHandler (webapp.RequestHandler): def put(self, id): data = simplejson.loads(self.request.body) # load the updated model todo = Todo.get_by_id(int(id)) # get it model using the ID from the request path todo.content = data["content"] todo.done = data["done"] todo.order = data["order"] todo.put() # update all fields and save to the DB # send it back using the updated values self.response.out.write(simplejson.dumps({ "id" : id, "content" : todo.content, "done" : todo.done, "order" : todo.order, }))
  • 15.
    REST API –DELETE (delete a task) class TodoItemHandler (webapp.RequestHandler): def delete(self, id): # find the requested model and delete it. todo = Todo.get_by_id(int(id)) todo.delete()
  • 16.
  • 17.
    Backbone.js Architecture –MVC Server Model Database Backbone REST Sync Model View Backbone.Model HTML + CSS DOM Manipulation With jQuery and templating Controller Backbone.View View Events Model Events
  • 18.
    Backbone.js Architecture –REST Sync Collection Operations Collection Model Operations GET /tasks PUT /tasks/38 POST /tasks View Model DELETE /tasks/38 PUT /tasks/39 View Model DELETE /tasks/39 PUT /tasks/40 View Model DELETE /tasks/40 PUT /tasks/41 View Model DELETE /tasks/41
  • 19.
    Web App DirectoryStructure  index.html – Main entry point  css  todos.css – Defines the style  js  libs  require.js, jQuery, Backbone, Underscore  models  todo.js – The todo item model  collections  todos.js – The todo item collection  views  todos.js – The todo item view  App.js – The app view  templates  stats.html  todo.html – The todo item template  main.js – Require.js entry point
  • 20.
    index.html  Loads thestylesheet <link rel="stylesheet" href="css/todos.css”/>  Loads the main.js script <script data-main="js/main" src="js/libs/require/require.js"> </script>
  • 21.
    main.js  Configures pathsand known libraries  text is used for require.js text loading (for templates) require.config({ paths: { jquery: 'libs/jquery/jquery-min', underscore: 'libs/underscore/underscore-min', backbone: 'libs/backbone/backbone-optamd3-min', text: 'libs/require/text' } });
  • 22.
    main.js – cont. Load the app view (views/app.js)  Notice there is no need to add the JS extension  Require.js supplies us with a function to run Javascript code only after certain modules have been loaded.  This allows us to create a dependency model, and a new way to write Javascript modules. require(['views/app'], function(AppView){ var app_view = new AppView; });
  • 23.
    views/app.js – TheAppView  Backbone's "View" is actually a "View Controller". The view itself is the template combined with CSS.  Creating a new view either means  creating a new DOM element using JavaScript/jQuery or templating  Using an existing one in the DOM  Since there is only one app, we’ll use an existing element for the AppView.  However, task views are more dynamic, and they will create new DOM elements.
  • 24.
    views/app.js – TheAppView (cont.)  The define function allows us to depend on libraries, template files and other modules we wrote.  Every dependency in the list corresponds to an argument of the function to execute once all modules are loaded. define([ 'jquery’, 'underscore', 'backbone', 'collections/todos’, 'views/todos', 'text!templates/stats.html' ], function($, _, Backbone, Todos, TodoView, statsTemplate) { var AppView = Backbone.View.extend({ ...
  • 25.
    views/app.js – TheAppView (cont.)  The "View" captures and delegates events on DOM elements events: { "keypress #new-todo": "createOnEnter", "click .todo-clear a": "clearCompleted” },
  • 26.
    views/app.js – TheAppView (cont.)  We add some handlers on the Todos collection to get notified when it's updated.  Then, we fetch the Todos collection from the server.  Once the data is loaded, addAll will be executed. initialize: function() { Todos.bind('add', this.addOne); Todos.bind('reset', this.addAll); Todos.fetch(); },
  • 27.
    collections/todos.js – TodoCollection  Backbone Collections are model arrays which synchronize with the server.  The AppView listens for changes on this collection, and can add new models to it. define([ 'underscore', 'backbone', 'models/todo’ ], function(_, Backbone, Todo){ var TodosCollection = Backbone.Collection.extend({ model: Todo, url: '/todos', done: function() { return this.filter(function(todo){ return todo.get('done'); }); } });
  • 28.
    models/todo.js – TodoModel  Holds the Todo item data  Defines the default values and methods related to the data  The "define" function needs to return the model class. When "model/todo" will be required, it will be received. define(['underscore', 'backbone'], function(_, Backbone) { var TodoModel = Backbone.Model.extend({ defaults: { content: "empty todo...”, done: false, order: 0 } }); return TodoModel; });
  • 29.
    views/todos.js – TodoView  Bind the view to the model  Render function uses the model data to render the template define(['jquery', 'underscore', 'backbone’, 'models/todo', 'text!templates/todos.html' ], function($, _, Backbone, Todo, todosTemplate){ var TodoView = Backbone.View.extend({ model: Todo, template: _.template(todosTemplate), initialize: function() { this.model.bind('change', this.render); this.model.bind('destroy', this.remove); }, render: function() { $(this.el).html(this.template(this.model.toJSON())); ...
  • 30.
    views/todos.js – TodoView (cont.)  Manipulate the view's model according to triggered events events: { "click .check" : "toggleDone", ... } // Toggle the "done" state of the model. toggleDone: function() { this.model.save({done : !this.model.get("done")}); },
  • 31.
    templates/todos.html  Template filesare used to build the views either:  Once (and then update using jQuery)  On every update (if you're lazy)  Use <%- ... -> for escaping HTML <div class="todo <%= done ? 'done' : '' %>"> <div class="display"> <input class="check" type="checkbox" <%= done ? 'checked="checked"' : '' %> /> <div class="todo-content"><%- content %></div> <span class="todo-destroy"></span> </div> <div class="edit"> <input class="todo-input" type="text" value="<%- content %>" /> </div> </div>
  • 32.