4. Challenges
Statefulness
Browser Vs. Server
HTML
POST key values vs. heirarchical data
Avoid full page updates
❝Can it be as easy to use as an iPad app?❞
5. Server's Role
Load the application:
Static HTML, images, stylesheets
JavaScript
Source/Sink of data
JSON is the easy way!
Ties in with NoSQL
In-place page updates
6. What's new here?
Isn't this just Ajax?
Core structure vs. optional enhancements
Isn't this just jQuery?
jQuery is great w/ elements, events, effects
More structure is needed
12. Caution: CoffeeScript
CoffeeScript
➠ ❝… a little language that compiles into JavaScript❞
Concise and readable
Optional parenthesis
Implicit returns
Concise function definitions
Fits nicely on slides!
20. context and this
this is a side-effect of method invocation:
anObject.aMethod() ➠ var fn = anObject["aMethod"];
fn.call(anObject)
Sets this for new stack frame
DOM and JQuery manipulate this
➠ Usually the DOM element that triggered event
this not relevant to HOFs
Functions, parameters, local scope
21. Backbone.Events
on(), off(), trigger() return this
trigger()
➠ arguments passed to listeners
Event name "all"
➠ Listener sees all events,
first parameter is event name
22. off([event], [callback], [context])
Removes matching listeners
event ➠ event to remove, or null for all
callback ➠ callback function to match
context ➠ context to match
off() ➠ remove all listeners
off("gnip") ➠ remove all 'gnip' listeners
29. Backbone.Model
id
idAttribute
cid
extend()
get()
set()
escape()
fetch()
save()
destroy()
defaults()
Quiz
Round Question
enableSave() : boolean
enableSave() : boolean enableSave() : boolean
_id
title kind text
location title answer
created questions value
rounds
30. Models and Attributes
Models contain attributes … data from server
Nothing is pre-defined
One attribute uniquely identifies the Model
idAttribute property defines this
idAttribute is "_id" for MongoDB
id property shadows the id attribute
cid property ➠ temporary unique id before saved to
server
37. Changing Attributes
quiz.set "title", "New Title" attribute key and value
➠ …
quiz.attributes
➠ {"title": "New Title"}
quiz.set location: "New Location" keys and values
➠ …
quiz.attributes
➠ {"location": "New Location",
"title":"New Title"}
41. Backbone Views
Are Controllers not Views
Create the UI for the element
Handle model events, update DOM
Handle DOM events, update model
Trigger own events
42. View.extend(properties, [class properties])
Properties are added to Standard properties:
the View
model
Defaults:
collection
tagName ➠ "div"
el
id
attributes
className
tagName
43. View and Element
@el is CoffeeScript for this.el
@el ➠ the element for this View
passed as an option to the constructor
or created from tagName, className, id, and
attributes options
Initially detached
@render or @initialize inserts it into DOM
44. Constructor
new MyView([options])
Merges options into @options
Creates @el if not passed as an option
Passes all constructor arguments to @initialize
Delegates events to @el
45. Event Delegation
Automatically dispatch events from inside @el
QuizTableRowView = View.extend
tagName: "tr"
initialize: -> …
event name and events:
"click .x-delete": "deleteDialog"
selector
"click .x-edit": "editQuiz"
render: -> …
method name
deleteDialog: -> …
editQuiz: -> …
.x-verb: Personal style
46. @render vs. @initialize()
Default @render implementation is: return this
Goal: minimize DOM reflow/recalc
Sub-views attach their @el inside container's
detached @el
Top-most @el attached once
Also OK to attach @el inside @initialize
47. Uh … attach?
QuizEditorView = FormView.extend
className: "tab-pane"
initialize: ->
…
Text
@$el.attr("id", tabId)
.html(readTemplate "QuizEditorView")
.appendTo("#top-level-tabs > .tab-content")
…
Detached @el attached to DOM
48. Elements and jQuery
@$el ➠ jQuery reference to the element
➠ @$el.html "<div>This View's Content</div>"
$ ➠ Equivalent to @$el.find
setElement(element, delegate)
Sets view's @el
Undelegates events from old @el
Delegates events to new @el
53. Using ConfirmDialog
deleteDialog: ->
title = @model.escape "title"
dialog = new ConfirmDialog
title: "Really delete Quiz?"
body: "<p>Deletion of quiz <strong>#{title}</strong>
is immediate and can not be undone.</p>"
label: "Delete Quiz"
buttonClass: "btn-danger"
dialog.on "confirm", => @model.destroy()
If the user clicks Delete Quiz, then
destroy model
54. ConfirmDialog = View.extend
className: "modal fade in"
initialize: ->
@$el.html fromMustacheTemplate "ConfirmDialog",
title: @options.title
body: @options.body
label: @options.label or "Confirm"
@$(".x-confirm").addClass @options.buttonClass or "btn-primary"
$("body").append(@$el) Update body of @el from template
@$el.modal().on "hidden", => Modify the class of the button
@remove()
doConfirm: ->
@trigger "confirm"
events:
"click .x-confirm": "doConfirm"
55. ConfirmDialog = View.extend
className: "modal fade in"
initialize: ->
@$el.html fromMustacheTemplate "ConfirmDialog",
title: @options.title
body: @options.body
label: @options.label or "Confirm"
@$(".x-confirm").addClass @options.buttonClass or "btn-primary"
$("body").append(@$el) Insert elements into the DOM
@$el.modal().on "hidden", =>
@remove()
doConfirm: ->
@trigger "confirm"
events:
"click .x-confirm": "doConfirm"
56. ConfirmDialog = View.extend
className: "modal fade in"
initialize: ->
@$el.html fromMustacheTemplate "ConfirmDialog",
title: @options.title
body: @options.body
label: @options.label or "Confirm"
@$(".x-confirm").addClass @options.buttonClass or "btn-primary"
$("body").append(@$el)
@$el.modal().on "hidden", =>
@remove()
Remove the element from the DOM
doConfirm: -> after hide animation completes
@trigger "confirm"
events:
"click .x-confirm": "doConfirm"
57. ConfirmDialog = View.extend
className: "modal fade in"
initialize: ->
@$el.html fromMustacheTemplate "ConfirmDialog",
title: @options.title
body: @options.body
label: @options.label or "Confirm"
@$(".x-confirm").addClass @options.buttonClass or "btn-primary"
$("body").append(@$el)
@$el.modal().on "hidden", =>
@remove()
doConfirm: -> Delegate a listener to the main button
@trigger "confirm"
events:
"click .x-confirm": "doConfirm"
59. QuizFieldsEditorView
QuizFieldsEditorView = FormView.extend
initialize: ->
@$el.html readTemplate "QuizFieldsEditorView"
@linkField name for name in ["title", "location"]
script#QuizFieldsEditorView(type="text/template")
.control-group.x-title
label Quiz Title
.controls
input.span4(type="text", required)
span.help-inline Title or theme for the Quiz
.control-group.x-location
label Location
input.span4(type="text")
span.help-inline Location where Quiz will take place
62. Collection
Contains Models
Has its own URL for queries & updates
May represent a subset of the data
Fires own events
Forwards events from Models
Can create new Model instances
63. Collection Access
Implements Underscore collection methods (pluck, map, etc.)
get(id) ➠ Get by unique id
getByCid(cid) ➠ Get by temporary client id
at(index) ➠ Get by index in collection
push(model) ➠ Add to end of collection
unshift(model) ➠ Add to start of collection
pop() ➠ Remove and return last model
shift() ➠ Remove and return first model
length ➠ Count of models in collection
64. Collection Events
add ➠ Model added to Collection
remove ➠ Model removed from Collection
reset ➠ Collection's entire contents updated
change ➠ Model's attributes have changed
destroy ➠ Model is destroyed (deleted)
67. QuizTableView
Alert visible when the QuizList is empty
.alert
strong.
No Quizzes have been created yet ... feel free to start creating some!
.limit-height
table.table.table-bordered.table-striped.table-condensed
thead
tr
th Title
th.span3 Location
th.span3 Created
th.span3
tbody QuizTableRowView added as children
.well
button.btn.btn-primary.x-create-new Create New Quiz
button.btn.x-create-test-data(data-loading-text="Loading ...").
Create Test Quizzes
68. QuizTableView
QuizTableView = View.extend
initialize: ->
@quizzes = new QuizList
@$el.html readTemplate "QuizTableView"
@$(".alert, table").hide()
@quizzes.on "reset", @addAll, this
@quizzes.on "add", @addOne, this
@quizzes.on "destroy", @render, this
@quizzes.fetch()
@$(".x-create-test-data").popover
title: "For Testing"
content: "Creates many Quizzes with random text, for testing purposes.
This will be removed in the final application."
…
69. QuizTableView.render()
render: ->
if @quizzes.length is 0
@$(".alert").show()
@$("table").hide()
else
@$(".alert").hide()
@$("table").show()
this
70. QuizTableView – Adding Models
@quizzes.on "reset", @addAll, this
@quizzes.on "add", @addOne, this
addOne: (quiz, collection, options) ->
view = new QuizTableRowView
model: quiz
collection: @quizzes
# Special case for inserting at index 0, which happens when a new quiz
# is added in the UI.
fname = if options? and options.index is 0 then "prepend" else "append"
@$("tbody")[fname] view.render().el
addAll: (quizzes) ->
@$("tbody").empty()
quizzes.each (quiz) => @addOne quiz
@render()
73. Quiz
enableSave() : boolean
_id
title
location
created 0..n
rounds Round
enableSave() : boolean
kind
title 0..n
questions Question
enableSave() : boolean
text
answer
value
74. ❝Backbone doesn't include
direct support for nested
models and collections or
"has many" associations
because there are a number
of good patterns for modeling
structured data on the client
side, and Backbone should
provide the foundation for
implementing any of them.❞