32
Writing HTML5 Web Apps Google App Engine Backbone.js Require.js jQuery Ron Reiter © 2012

Writing HTML5 Web Apps using Backbone.js and GAE

Embed Size (px)

DESCRIPTION

A walkthrough of how to write a complete HTML5 web app (both front end and back end) using Google App Engine (Python), Backbone.js, Require.js, underscore.js and jQuery.

Citation preview

Page 1: Writing HTML5 Web Apps using Backbone.js and GAE

Writing HTML5 Web Apps

Google App Engine

Backbone.js

Require.js

jQuery

Ron Reiter © 2012

Page 2: Writing HTML5 Web Apps using Backbone.js and GAE

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

Page 3: Writing HTML5 Web Apps using Backbone.js and GAE

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

Page 4: Writing HTML5 Web Apps using Backbone.js and GAE

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

Page 5: Writing HTML5 Web Apps using Backbone.js and GAE

The To-Do List

Page 6: Writing HTML5 Web Apps using Backbone.js and GAE

Web App Architecture

Front EndBackbone.js

Back EndGoogle App Engine

REST API

Page 7: Writing HTML5 Web Apps using Backbone.js and GAE

Back-End

Page 8: Writing HTML5 Web Apps using Backbone.js and GAE

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()

Page 9: Writing HTML5 Web Apps using Backbone.js and GAE

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)

Page 10: Writing HTML5 Web Apps using Backbone.js and GAE

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", {}))

Page 11: Writing HTML5 Web Apps using Backbone.js and GAE

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

Page 12: Writing HTML5 Web Apps using Backbone.js and GAE

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))

Page 13: Writing HTML5 Web Apps using Backbone.js and GAE

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"],

}))

Page 14: Writing HTML5 Web Apps using Backbone.js and GAE

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,

  }))

Page 15: Writing HTML5 Web Apps using Backbone.js and GAE

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()

Page 16: Writing HTML5 Web Apps using Backbone.js and GAE

Front-End

Page 17: Writing HTML5 Web Apps using Backbone.js and GAE

Backbone.js Architecture – MVC

ViewHTML + CSS

ControllerBackbone.View

ModelBackbone.Model

DOM ManipulationWith jQuery andtemplating

View Events

Backbone REST Sync

Server Model Database

Model Events

Page 18: Writing HTML5 Web Apps using Backbone.js and GAE

Backbone.js Architecture – REST Sync

ModelView

ModelView

ModelView

ModelView

Collection

PUT /tasks/41DELETE /tasks/41

PUT /tasks/39DELETE /tasks/39

PUT /tasks/40DELETE /tasks/40

PUT /tasks/38DELETE /tasks/38

GET /tasksPOST /tasks

Collection OperationsModel Operations

Page 19: Writing HTML5 Web Apps using Backbone.js and GAE

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

Page 20: Writing HTML5 Web Apps using Backbone.js and GAE

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> 

Page 21: Writing HTML5 Web Apps using Backbone.js and GAE

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'

  }

});

Page 22: Writing HTML5 Web Apps using Backbone.js and GAE

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;

});

Page 23: Writing HTML5 Web Apps using Backbone.js and GAE

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.

Page 24: Writing HTML5 Web Apps using Backbone.js and GAE

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({ ...

Page 25: Writing HTML5 Web Apps using Backbone.js and GAE

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”

},

Page 26: Writing HTML5 Web Apps using Backbone.js and GAE

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();

},

Page 27: Writing HTML5 Web Apps using Backbone.js and GAE

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');

});

}

});

Page 28: Writing HTML5 Web Apps using Backbone.js and GAE

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;

});

Page 29: Writing HTML5 Web Apps using Backbone.js and GAE

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()));...

Page 30: Writing HTML5 Web Apps using Backbone.js and GAE

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")});

},

Page 31: Writing HTML5 Web Apps using Backbone.js and GAE

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>

Page 32: Writing HTML5 Web Apps using Backbone.js and GAE

Questions?