Slide 1

Slide 1 text

Leif Singer | http://leif.me | @lsinger NOV 24th 2011 LIGHT-WEIGHT MVC FOR JAVASCRIPT

Slide 2

Slide 2 text

FLOWCHART 2 MVC ME BACKBONE.JS

Slide 3

Slide 3 text

FLOWCHART 3 BACKBONE.JS APPLICATION STRUCTURE CONCEPTS EXAMPLE

Slide 4

Slide 4 text

LEIF SINGER Software Engineering Group, Leibniz Universität Hannover –Teaching: Projects, Seminars –Research: Supporting SE using Social Software 4

Slide 5

Slide 5 text

LEIF SINGER Software Engineering Group, Leibniz Universität Hannover –Teaching: Projects, Seminars –Research: Supporting SE using Social Software 4 Web Development since 1996 –private, start-up, employee, freelancer –HTML, JavaScript, Perl, CSS, PHP, Java, Groovy, ... –WebObjects, CakePHP, jQuery, Cappuccino, Grails, Play!, ...

Slide 6

Slide 6 text

WHAT IS MVC?

Slide 7

Slide 7 text

WHAT IS MVC? DESIGN PATTERN

Slide 8

Slide 8 text

WHAT IS MVC? DESIGN PATTERN TRYGVE REENSKAUG

Slide 9

Slide 9 text

WHAT IS MVC? DESIGN PATTERN TRYGVE REENSKAUG 1979, XEROX PARC

Slide 10

Slide 10 text

WHAT IS MVC? DESIGN PATTERN TRYGVE REENSKAUG 1979, XEROX PARC DECOUPLES YOUR CODE INTO MODEL VIEW CONTROLLER

Slide 11

Slide 11 text

6 MODEL MVC

Slide 12

Slide 12 text

6 MODEL VIEW MVC

Slide 13

Slide 13 text

6 MODEL VIEW READ MVC

Slide 14

Slide 14 text

6 MODEL VIEW READ CHANGE EVENTS MVC

Slide 15

Slide 15 text

6 MODEL VIEW READ USER EVENTS CHANGE EVENTS MVC

Slide 16

Slide 16 text

6 MODEL VIEW CONTROLLER READ USER EVENTS CHANGE EVENTS MVC

Slide 17

Slide 17 text

6 MODEL VIEW CONTROLLER READ CHANGE USER EVENTS CHANGE EVENTS MVC

Slide 18

Slide 18 text

6 MODEL VIEW CONTROLLER READ CHANGE SELECT USER EVENTS CHANGE EVENTS MVC

Slide 19

Slide 19 text

6 MODEL VIEW CONTROLLER READ CHANGE SELECT USER EVENTS CHANGE EVENTS MVC GREAT BENEFITS: • MODEL INDEPENDENT FROM CONTROLLER & VIEW • VIEW KNOWS ONLY THE MODEL IT DISPLAYS • CONTROLLER IS GLUE • ... STRUCTURE!

Slide 20

Slide 20 text

... AND ALONG CAME THE WEB.

Slide 21

Slide 21 text

8 BROWSER WEB SERVER REQUEST GET /file.html RESPONSE 200 OK

Slide 22

Slide 22 text

8 BROWSER WEB SERVER REQUEST GET /file.html RESPONSE 200 OK SERVER FORGETS CLIENT.

Slide 23

Slide 23 text

8 BROWSER WEB SERVER REQUEST GET /file.html RESPONSE 200 OK THE WEB’S ARCHITECTURE IS A SUCCESS! STATELESS: JUST ADD SERVERS PROXIES, CACHING UNIFORM INTERFACE EASY TO INTEGRATE NEW CLIENTS & SERVERS SAFE, IDEMPOTENT GET SERVER FORGETS CLIENT.

Slide 24

Slide 24 text

8 BROWSER WEB SERVER REQUEST GET /file.html RESPONSE 200 OK THE WEB’S ARCHITECTURE IS A SUCCESS! STATELESS: JUST ADD SERVERS PROXIES, CACHING UNIFORM INTERFACE EASY TO INTEGRATE NEW CLIENTS & SERVERS SAFE, IDEMPOTENT GET SERVER FORGETS CLIENT. BUT: OBSERVERS? USER EVENTS? CHANGE EVENTS? VIEW? MODEL!? CONTROLLER!?! AN ADAPTATION OF MVC IS NEEDED.

Slide 25

Slide 25 text

9 MVC MODEL 2 / “WEB MVC” BROWSER WEB APPLICATION

Slide 26

Slide 26 text

9 MVC MODEL 2 / “WEB MVC” BROWSER WEB APPLICATION FRONTCONTROLLER OR ROUTER

Slide 27

Slide 27 text

9 MVC MODEL 2 / “WEB MVC” BROWSER WEB APPLICATION FRONTCONTROLLER OR ROUTER CONTROLLER

Slide 28

Slide 28 text

9 MVC MODEL 2 / “WEB MVC” BROWSER WEB APPLICATION FRONTCONTROLLER OR ROUTER CONTROLLER MODEL STORAGE

Slide 29

Slide 29 text

9 MVC MODEL 2 / “WEB MVC” BROWSER WEB APPLICATION FRONTCONTROLLER OR ROUTER CONTROLLER MODEL STORAGE

Slide 30

Slide 30 text

9 MVC MODEL 2 / “WEB MVC” BROWSER WEB APPLICATION FRONTCONTROLLER OR ROUTER CONTROLLER VIEW MODEL STORAGE

Slide 31

Slide 31 text

OMG NO ... AJAX!?!

Slide 32

Slide 32 text

11 BROWSER WEB SERVER REQUEST GET /file.html RESPONSE 200 OK SEQUENCE SHORTENED :)

Slide 33

Slide 33 text

11 BROWSER WEB SERVER REQUEST GET /file.html RESPONSE 200 OK JSON DATA P A G E FR A G M EN T SEQUENCE SHORTENED :)

Slide 34

Slide 34 text

11 BROWSER WEB SERVER REQUEST GET /file.html RESPONSE 200 OK JSON DATA P A G E FR A G M EN T SEQUENCE SHORTENED :) HORRIBLE MESS!

Slide 35

Slide 35 text

11 BROWSER WEB SERVER REQUEST GET /file.html RESPONSE 200 OK JSON DATA P A G E FR A G M EN T SEQUENCE SHORTENED :) HORRIBLE MESS! MVC FOR JAVASCRIPT APPLICATIONS?

Slide 36

Slide 36 text

11 BROWSER WEB SERVER REQUEST GET /file.html RESPONSE 200 OK JSON DATA P A G E FR A G M EN T SEQUENCE SHORTENED :) HORRIBLE MESS! MVC FOR JAVASCRIPT APPLICATIONS? YES!

Slide 37

Slide 37 text

SHOW US BACKBONE ALREADY!

Slide 38

Slide 38 text

13 BACKBONE.JS IS “MVC FOR JAVASCRIPT-HEAVY APPLICATIONS” CREATED BY DOCUMENTCLOUD.ORG HTTP://DOCUMENTCLOUD.GITHUB.COM/BACKBONE/

Slide 39

Slide 39 text

13 LINKEDIN 37SIGNALS FOURSQUARE SOUNDCLOUD GROUPON PANDORA FLOW AUDIOVROOM SALESFORCE DO TRAJECTORY CLOUDAPP BATTLEFIELD PLAY4FREE BLOSSOM.IO BITTORRENT BACKBONE.JS IS “MVC FOR JAVASCRIPT-HEAVY APPLICATIONS” CREATED BY DOCUMENTCLOUD.ORG HTTP://DOCUMENTCLOUD.GITHUB.COM/BACKBONE/

Slide 40

Slide 40 text

14 WHAT DO WE NEED FOR MVC AGAIN?

Slide 41

Slide 41 text

15 MODEL VIEW CONTROLLER READ CHANGE SELECT USER EVENTS CHANGE EVENTS

Slide 42

Slide 42 text

15 MODEL VIEW CONTROLLER READ CHANGE SELECT USER EVENTS CHANGE EVENTS BACKBONE.MODEL BACKBONE.COLLECTION

Slide 43

Slide 43 text

15 MODEL VIEW CONTROLLER READ CHANGE SELECT USER EVENTS CHANGE EVENTS BACKBONE.MODEL BACKBONE.COLLECTION TEMPLATES HTML

Slide 44

Slide 44 text

15 MODEL VIEW CONTROLLER READ CHANGE SELECT USER EVENTS CHANGE EVENTS BACKBONE.MODEL BACKBONE.COLLECTION BACKBONE.VIEW BACKBONE.ROUTER TEMPLATES HTML

Slide 45

Slide 45 text

15 MODEL VIEW CONTROLLER READ CHANGE SELECT USER EVENTS CHANGE EVENTS BACKBONE.MODEL BACKBONE.COLLECTION BACKBONE.EVENTS BACKBONE.EVENTS BACKBONE.VIEW BACKBONE.ROUTER TEMPLATES HTML

Slide 46

Slide 46 text

15 MODEL VIEW CONTROLLER READ CHANGE SELECT USER EVENTS CHANGE EVENTS BACKBONE.MODEL BACKBONE.COLLECTION BACKBONE.EVENTS BACKBONE.EVENTS STORAGE BACKBONE.SYNC BACKBONE.VIEW BACKBONE.ROUTER TEMPLATES HTML

Slide 47

Slide 47 text

16 OUR DOMAIN OBJECTS THE “THINGS” OUR APPLICATION IS ABOUT BACKBONE.MODEL MyApp.User = Backbone.Model.extend({});

Slide 48

Slide 48 text

17 OUR DOMAIN OBJECTS THE “THINGS” OUR APPLICATION IS ABOUT BACKBONE.MODEL MyApp.User = Backbone.Model.extend({ defaults: function() { return { username: "anonymous", thumbnail: "default.png" }; } });

Slide 49

Slide 49 text

18 OUR DOMAIN OBJECTS THE “THINGS” OUR APPLICATION IS ABOUT BACKBONE.MODEL MyApp.User = Backbone.Model.extend({ defaults: function() { return { username: "anonymous", thumbnail: "default.png" }; }, hasUsername: function() { return this.get("username") !== "anonymous"; } });

Slide 50

Slide 50 text

19 COLLECTIONS OF OUR DOMAIN OBJECTS SORT THEM, FILTER THEM, ADD, REMOVE, SYNC, ... BACKBONE.COLLECTION MyApp.UserList = Backbone.Collection.extend({}); MyApp.Users = new MyApp.UserList;

Slide 51

Slide 51 text

20 COLLECTIONS OF OUR DOMAIN OBJECTS SORT THEM, FILTER THEM, ADD, REMOVE, SYNC, ... BACKBONE.COLLECTION MyApp.UserList = Backbone.Collection.extend({ model: MyApp.User, url: "/users" }); MyApp.Users = new MyApp.UserList;

Slide 52

Slide 52 text

21 COLLECTIONS OF OUR DOMAIN OBJECTS SORT THEM, FILTER THEM, ADD, REMOVE, SYNC, ... BACKBONE.COLLECTION MyApp.UserList = Backbone.Collection.extend({ model: MyApp.User, url: "/users", withUsername: function() { return this.filter(function(user) { return user.hasUsername(); }); }, comparator: function(user) { return user.get("username"); } }); MyApp.Users = new MyApp.UserList;

Slide 53

Slide 53 text

22 COLLECTIONS OF OUR DOMAIN OBJECTS NEAT FUNCTIONS FROM UNDERSCORE.JS! BACKBONE.COLLECTION // each: calls function for each element collection.each(function(element) {element.save();});

Slide 54

Slide 54 text

22 COLLECTIONS OF OUR DOMAIN OBJECTS NEAT FUNCTIONS FROM UNDERSCORE.JS! BACKBONE.COLLECTION // each: calls function for each element collection.each(function(element) {element.save();}); // filter: all those elements passing the test var goodOnes = collection.filter(function(element) {element.isGood});

Slide 55

Slide 55 text

22 COLLECTIONS OF OUR DOMAIN OBJECTS NEAT FUNCTIONS FROM UNDERSCORE.JS! BACKBONE.COLLECTION // each: calls function for each element collection.each(function(element) {element.save();}); // filter: all those elements passing the test var goodOnes = collection.filter(function(element) {element.isGood}); // reject: all those elements *failing* the test var badOnes = collection.reject(function(element) {element.isGood});

Slide 56

Slide 56 text

22 COLLECTIONS OF OUR DOMAIN OBJECTS NEAT FUNCTIONS FROM UNDERSCORE.JS! BACKBONE.COLLECTION // each: calls function for each element collection.each(function(element) {element.save();}); // filter: all those elements passing the test var goodOnes = collection.filter(function(element) {element.isGood}); // reject: all those elements *failing* the test var badOnes = collection.reject(function(element) {element.isGood}); // find: returns first match var mm = collection.find(function(element) {element.username === "mmuster"});

Slide 57

Slide 57 text

23 STORAGE BACKBONE.SYNC MANAGES PERSISTENCE FOR OUR MODELS DEFAULT: RESTFUL* HTTP INTERFACE REPLACEABLE! E.G. WITH LOCALSTORAGE * WELL, KINDA, SORTA. REST IS MORE THAN CRUD.

Slide 58

Slide 58 text

23 STORAGE BACKBONE.SYNC MANAGES PERSISTENCE FOR OUR MODELS DEFAULT: RESTFUL* HTTP INTERFACE REPLACEABLE! E.G. WITH LOCALSTORAGE * WELL, KINDA, SORTA. REST IS MORE THAN CRUD. var user = new MyApp.User({ username: "lsinger" }); // "create" event => POST /users user.save(); // "update" event => PUT /users/17 user.save({thumbnail: "lsinger.png"}); // "destroy" event => DELETE /users/17 user.destroy();

Slide 59

Slide 59 text

24 STORAGE BACKBONE.SYNC USER VIEW CONTROLLER MODEL SERVER BUY! SUBMIT() SAVE() POST /ORDERS

Slide 60

Slide 60 text

24 STORAGE BACKBONE.SYNC USER VIEW CONTROLLER MODEL SERVER BUY! SUBMIT() SAVE() POST /ORDERS 200 OK TRUE SUCCESS.SHOW() SUCCESS!

Slide 61

Slide 61 text

25 STATIC APPLICATION SKELETON INSERTION POINTS FOR TEMPLATES HTML

Profile

Slide 62

Slide 62 text

26 DISPLAYS MODEL OBJECTS DEFAULT: UNDERSCORE’S TEMPLATE ENGINE REPLACEABLE WITH MUSTACHE, HAML-JS, ... TEMPLATES <div class="user"> <div class="thumbnail"> <img src="<%= thumbnail %>" title="<%= username %>"/> </div> <span class="username"> <% if (username) { %> <%= username %> <% } else { %> anonymous <% } %> </span> </div>

Slide 63

Slide 63 text

27 ACTUALLY, IT’S THE CONTROLLER GLUES TOGETHER VIEWS AND MODELS VIA EVENTS INTERPRETS VIEW EVENTS (SUBMIT MEANS BUY) BACKBONE.VIEW MyApp.UserView = Backbone.View.extend({});

Slide 64

Slide 64 text

28 BACKBONE.VIEW MyApp.UserView = Backbone.View.extend({ el: $("#user-details"), template: _.template($("#user-template").html()) }); ACTUALLY, IT’S THE CONTROLLER GLUES TOGETHER VIEWS AND MODELS VIA EVENTS INTERPRETS VIEW EVENTS (SUBMIT MEANS BUY)

Slide 65

Slide 65 text

29 BACKBONE.VIEW MyApp.UserView = Backbone.View.extend({ el: $("#user-details"), template: _.template($("#user-template").html()), events: { "click div.thumbnail" : "zoomImage" }, zoomImage: function(e) { // e: event object /* ... zoom image here ... */ } }); ACTUALLY, IT’S THE CONTROLLER GLUES TOGETHER VIEWS AND MODELS VIA EVENTS INTERPRETS VIEW EVENTS (SUBMIT MEANS BUY)

Slide 66

Slide 66 text

30 BACKBONE.VIEW MyApp.UserView = Backbone.View.extend({ el: $("#user-details"), template: _.template($("#user-template").html()), events: { "click div.thumbnail" : "zoomImage" }, zoomImage: function(e) { // e: event object /* ... zoom image here ... */ }, initialize: function() { this.model.bind('change', this.render, this); } }); ACTUALLY, IT’S THE CONTROLLER GLUES TOGETHER VIEWS AND MODELS VIA EVENTS INTERPRETS VIEW EVENTS (SUBMIT MEANS BUY)

Slide 67

Slide 67 text

31 BACKBONE.VIEW MyApp.UserView = Backbone.View.extend({ el: $("#user-details"), template: _.template($("#user-template").html()), events: { "click div.thumbnail" : "zoomImage" }, zoomImage: function(e) { // e: event object /* ... zoom image here ... */ }, initialize: function() { this.model.bind('change', this.render, this); }, render: function() { $(this.el).html(this.template(this.model.toJSON())); return this; // allow chaining } }); ACTUALLY, IT’S THE CONTROLLER GLUES TOGETHER VIEWS AND MODELS VIA EVENTS INTERPRETS VIEW EVENTS (SUBMIT MEANS BUY)

Slide 68

Slide 68 text

32 A FRONTCONTROLLER MAPS URLS TO APPLICATION STATE STATE BECOMES BOOKMARKABLE! HISTORY API WITH HASHBANG FALLBACK BACKBONE.ROUTER MyApp.Router = Backbone.Router.extend({ routes: { "user/:username": "profile", "user/:username/posts": "posts" } });

Slide 69

Slide 69 text

33 A FRONTCONTROLLER MAPS URLS TO APPLICATION STATE STATE BECOMES BOOKMARKABLE! HISTORY API WITH HASHBANG FALLBACK BACKBONE.ROUTER MyApp.Router = Backbone.Router.extend({ routes: { "user/:username": "profile", "user/:username/posts": "posts" } }); MyApp.Router.bind("route:profile", function(username) { // recreate application state here }); MyApp.Router.bind("route:posts", function(username) { // recreate application state here });

Slide 70

Slide 70 text

34 USED THROUGHOUT BACKBONE TO CONNECT THINGS BACKBONE.EVENTS // observable emits "something:happened" events var observable = {}; _.extend(observable, Backbone.Events); observable.change = function() { observable.trigger("something:happened", "I changed!"); };

Slide 71

Slide 71 text

34 USED THROUGHOUT BACKBONE TO CONNECT THINGS BACKBONE.EVENTS // observable emits "something:happened" events var observable = {}; _.extend(observable, Backbone.Events); observable.change = function() { observable.trigger("something:happened", "I changed!"); }; // somewhere else, a listener wants to listen var listener = function(msg) {console.log("Something happened: " + msg);}; observable.bind("something:happened", listener);

Slide 72

Slide 72 text

34 USED THROUGHOUT BACKBONE TO CONNECT THINGS BACKBONE.EVENTS // observable emits "something:happened" events var observable = {}; _.extend(observable, Backbone.Events); observable.change = function() { observable.trigger("something:happened", "I changed!"); }; // somewhere else, a listener wants to listen var listener = function(msg) {console.log("Something happened: " + msg);}; observable.bind("something:happened", listener); // somewhere else still, something actually happens observable.change();

Slide 73

Slide 73 text

34 USED THROUGHOUT BACKBONE TO CONNECT THINGS BACKBONE.EVENTS // observable emits "something:happened" events var observable = {}; _.extend(observable, Backbone.Events); observable.change = function() { observable.trigger("something:happened", "I changed!"); }; // somewhere else, a listener wants to listen var listener = function(msg) {console.log("Something happened: " + msg);}; observable.bind("something:happened", listener); // somewhere else still, something actually happens observable.change();

Slide 74

Slide 74 text

34 USED THROUGHOUT BACKBONE TO CONNECT THINGS BACKBONE.EVENTS // observable emits "something:happened" events var observable = {}; _.extend(observable, Backbone.Events); observable.change = function() { observable.trigger("something:happened", "I changed!"); }; // somewhere else, a listener wants to listen var listener = function(msg) {console.log("Something happened: " + msg);}; observable.bind("something:happened", listener); // somewhere else still, something actually happens observable.change();

Slide 75

Slide 75 text

35 // use of events in a Backbone.View's initialize: initialize: function() { this.model.bind('change', this.render, this); this.model.bind('destroy', this.remove, this); } BACKBONE.EVENTS USED THROUGHOUT BACKBONE TO CONNECT THINGS

Slide 76

Slide 76 text

36

Slide 77

Slide 77 text

37

Slide 78

Slide 78 text

38

Slide 79

Slide 79 text

39

Slide 80

Slide 80 text

40

Slide 81

Slide 81 text

41

Slide 82

Slide 82 text

WHAT IS A TODO? 42 TodoApp.Todo = Backbone.Model.extend({ defaults: function() { return { done: false, text: "", order: TodoApp.Todos.nextOrder() }; }, toggle: function() { this.save({done: !this.get("done")}); } });

Slide 83

Slide 83 text

WHAT ABOUT MANY TODOS? 43 TodoApp.TodoList = Backbone.Collection.extend({ model: TodoApp.Todo, localStorage: new Store("todos"), done: function() { return this.filter(function(todo){ return todo.get('done'); }); }, remaining: function() { return this.without.apply(this, this.done()); }, nextOrder: function() { if (!this.length) return 1; return this.last().get('order') + 1; }, comparator: function(todo) { return todo.get('order'); } }); TodoApp.Todos = new TodoApp.TodoList;

Slide 84

Slide 84 text

WHAT SHOULD A TODO LOOK LIKE? 44 <div class="todo <%= done ? 'done' : '' %>"> <div class="display"> <input class="check" type="checkbox" <%= done ? 'checked="checked"' : '' %> /> <div class="todo-text"></div> <span class="todo-destroy"></span> </div> <div class="edit"> <input class="todo-input" type="text" value="" /> </div> </div>

Slide 85

Slide 85 text

DISPLAY STATISTICS & CLEAR BUTTON 45 <% if (total) { %> <span class="todo-count"> <span class="number"><%= remaining %></span> <span class="word"><%= remaining == 1 ? 'item' : 'items' %></span> left. </span> <% } %> <% if (done) { %> <span class="todo-clear"> <a href="#"> Clear <span class="number-done"><%= done %></span> completed <span class="word-done"><%= done == 1 ? 'item' : 'items' %></span> </a> </span> <% } %>

Slide 86

Slide 86 text

PUT IT ALL INTO A STATIC SKELETON 46

Todos

    Slide 87

    Slide 87 text

    47

    Slide 88

    Slide 88 text

    47 NO BEHAVIOR YET.

    Slide 89

    Slide 89 text

    THE TODO CONTROLLER 48 TodoApp.TodoView = Backbone.View.extend({ tagName: "li", template: _.template($('#item-template').html()), events: { "click .check" : "toggleDone", "dblclick div.todo-text" : "edit", "click span.todo-destroy" : "clear", "keypress .todo-input" : "updateOnEnter" }, initialize: function() { this.model.bind('change', this.render, this); this.model.bind('destroy', this.remove, this); }, render: function() { $(this.el).html(this.template(this.model.toJSON())); this.setText(); return this; }, setText: function() { var text = this.model.get('text'); this.$('.todo-text').text(text); this.input = this.$('.todo-input'); this.input.bind('blur', _.bind(this.close, this)).val(text); }, /* continued ... */

    Slide 90

    Slide 90 text

    EVENT CALLBACKS FOR THE TODO CONTROLLER 49 toggleDone: function() { this.model.toggle(); }, edit: function() { $(this.el).addClass("editing"); this.input.focus(); }, close: function() { this.model.save({text: this.input.val()}); $(this.el).removeClass("editing"); }, updateOnEnter: function(e) { if (e.keyCode == 13) this.close(); }, remove: function() { $(this.el).remove(); }, clear: function() { this.model.destroy(); }

    Slide 91

    Slide 91 text

    THE APPLICATION CONTROLLER 50 TodoApp.AppView = Backbone.View.extend({ el: $("#todoapp"), statsTemplate: _.template($('#stats-template').html()), events: { "keypress #new-todo": "createOnEnter", "click .todo-clear a": "clearCompleted" }, initialize: function() { this.input = this.$("#new-todo"); TodoApp.Todos.bind('add', this.addOne, this); TodoApp.Todos.bind('reset', this.addAll, this); TodoApp.Todos.bind('all', this.render, this); TodoApp.Todos.fetch(); }, render: function() { this.$('#todo-stats').html(this.statsTemplate({ total: TodoApp.Todos.length, done: TodoApp.Todos.done().length, remaining: TodoApp.Todos.remaining().length })); }, /* continued ... */

    Slide 92

    Slide 92 text

    EVENT CALLBACKS FOR THE APPLICATION CONTROLLER 51 addOne: function(todo) { var view = new TodoApp.TodoView({model: todo}); this.$("#todo-list").append(view.render().el); }, addAll: function() { // first, clear the existing views this.$("#todo-list").empty(); TodoApp.Todos.each(this.addOne); }, createOnEnter: function(e) { var text = this.input.val(); if (!text || e.keyCode != 13) return; TodoApp.Todos.create({text: text}); this.input.val(''); }, clearCompleted: function() { _.each(TodoApp.Todos.done(), function(todo){ todo.destroy(); }); return false; }

    Slide 93

    Slide 93 text

    52 HTTP://LOCALHOST:9000/TODO DEMO.

    Slide 94

    Slide 94 text

    53 FINALLY! WE NOW HAVE ALL THE MVC FRAMEWORKS WE NEED ...

    Slide 95

    Slide 95 text

    REALTIME!?!?

    Slide 96

    Slide 96 text

    REALTIME & BACKBONE.JS 55 MADE FOR “REST” INTERFACES COLLECTIONS ALWAYS FETCH ALL ITEMS CAN BE MODIFIED FOR USE WITH SOCKET.IO + NODE.JS JUGGERNAUT + NODE.JS (SPINE.JS!) ... NO TECH-NEUTRAL SOLUTION THERE YET.

    Slide 97

    Slide 97 text

    REALTIME & BACKBONE.JS 55 MADE FOR “REST” INTERFACES COLLECTIONS ALWAYS FETCH ALL ITEMS CAN BE MODIFIED FOR USE WITH SOCKET.IO + NODE.JS JUGGERNAUT + NODE.JS (SPINE.JS!) ... NO TECH-NEUTRAL SOLUTION THERE YET. CONVENTIONS & PATTERNS STILL IN FLUX

    Slide 98

    Slide 98 text

    56 HTTP://TODOS.HANNOVERJS.DE/ BUT: A DIRTY LITTLE HACK ...

    Slide 99

    Slide 99 text

    56 HTTP://TODOS.HANNOVERJS.DE/ BUT: A DIRTY LITTLE HACK ... TOO MUCH TRAFFIC EDITING IMPOSSIBLE VIEW GETS REPLACED BY UPDATES NO CONFLICT HANDLING

    Slide 100

    Slide 100 text

    57 SO, WHAT ABOUT MVC & REALTIME?

    Slide 101

    Slide 101 text

    58 THE SPECTRUM THAT IS THE WEB * INDEED, SEVERAL OF THE FRAMEWORKS LISTED CAN BE USED FOR REALTIME, E.G. SPINE + JUGGERNAUT. HOWEVER, THESE SOLUTIONS TYPICALLY DEPEND ON CERTAIN SERVER-TECHNOLOGIES, SUCH AS NODE.JS. I DON’T SEE A TECH-NEUTRAL PATTERN YET – OR RATHER, I SEE MANY COMPETING ONES. TIME WILL TELL WHICH ONE(S) WILL PREVAIL.

    Slide 102

    Slide 102 text

    58 THE SPECTRUM THAT IS THE WEB STATIC PAGES ENRICHED SOME AJAX DESKTOP-LIKE REALTIME* JS APPS ? * INDEED, SEVERAL OF THE FRAMEWORKS LISTED CAN BE USED FOR REALTIME, E.G. SPINE + JUGGERNAUT. HOWEVER, THESE SOLUTIONS TYPICALLY DEPEND ON CERTAIN SERVER-TECHNOLOGIES, SUCH AS NODE.JS. I DON’T SEE A TECH-NEUTRAL PATTERN YET – OR RATHER, I SEE MANY COMPETING ONES. TIME WILL TELL WHICH ONE(S) WILL PREVAIL.

    Slide 103

    Slide 103 text

    58 THE SPECTRUM THAT IS THE WEB STATIC PAGES ENRICHED SOME AJAX DESKTOP-LIKE REALTIME* BACKBONE.JS ANGULAR SPINE ... CAPPUCCINO SPROUTCORE ... JS APPS ? JQUERY UI ... ? JQUERY PROTOTYPE ... * INDEED, SEVERAL OF THE FRAMEWORKS LISTED CAN BE USED FOR REALTIME, E.G. SPINE + JUGGERNAUT. HOWEVER, THESE SOLUTIONS TYPICALLY DEPEND ON CERTAIN SERVER-TECHNOLOGIES, SUCH AS NODE.JS. I DON’T SEE A TECH-NEUTRAL PATTERN YET – OR RATHER, I SEE MANY COMPETING ONES. TIME WILL TELL WHICH ONE(S) WILL PREVAIL.

    Slide 104

    Slide 104 text

    59

    Slide 105

    Slide 105 text

    60

    Slide 106

    Slide 106 text

    61

    Slide 107

    Slide 107 text

    ADVERTISEMENT! 62

    Slide 108

    Slide 108 text

    ADVERTISEMENT! 62 LOOKING FOR COMPANIES WITH SOFTWARE DEVELOPERS! TAKE PART IN RESEARCH! HOW TO CREATE SOFTWARE FASTER & BETTER? TALK TO ME || HTTP://LEIF.ME

    Slide 109

    Slide 109 text

    CREDIT WHERE CREDIT IS DUE 63 • Backbone.JS logo: http://documentcloud.github.com/backbone/ • MVC gang: http://youtube.com/watch?v=91C7ax0UAAc • spider web: http://www.flickr.com/photos/zzathras777/1546040168/ • server: http://www.iconshock.com/ • HTML, JS, CSS icons: http://www.drewwilson.com/ • The Absolute Silence: http://www.flickr.com/photos/fabbriciuse/438451967/ • Facepalm: http://www.flickr.com/photos/santiagogprg/5023648200/ • Colorful World: http://mediablade.deviantart.com/art/Colorful-World-01-89864194 • Todo List Application by Jérôme Gravel-Niquet: http://documentcloud.github.com/backbone/ examples/todos/index.html