init a project
yo backbone # generates your application base and build workflow
yo backbone:model blog
yo backbone:collection blog
yo backbone:router blog
yo backbone:view blog
Controllers are an intermediary between models and views which are classically responsible for two tasks:
In Backbone, controller logic is shared between Backbone.View and Backbone.Router
underscore templates
_.templateSettings = { interpolate : /\{\{(.+?)\}\}/g };
easyer server side interaction
Backbone.emulateHTTP = true; Backbone.emulateJSON = true;
basic html
<!DOCTYPE html> <html> <head> <script src="http://code.jquery.com/jquery-1.7.2.min.js" type="text/javascript" language="JavaScript" ></script> <script src="http://underscorejs.org/underscore-min.js" type="text/javascript" language="JavaScript" ></script> <script src="http://backbonejs.org/backbone-min.js" type="text/javascript" language="JavaScript" ></script> <script src="$app.js" type="text/javascript" language="JavaScript" ></script> </head> <body> <!-- templates --> <script type="text/template" id="stats-template"> <% if (done) { %> <a id="clear-completed" class="btn ">Clear <%= done %> completed <%= done == 1 ? 'item' : 'items' %></a> <% } %> <div class="todo-count"><b><%= remaining %></b> <%= remaining == 1 ? 'item' : 'items' %> left</div> </script> </body> </html>
window.__app__ = { Models: {}, Collections: {}, Views: {}, Routers: {}, init: function () { // app init } }; // app init event $(document).ready(function () { __app__.init(); }); //-- router ---------------------------------------- __app__.Routers = __app__.Routers || {}; (function () { __app__.Routers.R = Backbone.Router.extend({ routes: { "": "homeAction" }, initialize: function(){}, homeAction: function(){ // init views app.homeView = new app.views.HomeView({ el: $('#homeView') }); //app.homeView.render(); //app.homeView.delegateEvents(); } }); })();
//-- model ---------------------------------------- __app__.Models = __app__.Models || {}; (function () { __app__.Models.Cart = Backbone.Model.extend({ url: '', //urlRoot: '/cart',//url a cui inviare/legegre i dati initialize: function() { }, defaults: { }, validate: function(attrs, options) { }, parse: function(response, options) { return response; } // BB assumes you are interacting with a RESTful API but allows you to override one method, // Backbone.sync(), if not. You tell your model where the resource is on the server (the URL) // and then you can just call save(). }); })(); // uso save: //user.save(userDetails, { // success: function (user) { // console.log(user.toJSON()); // } //}); //-- collection ---------------------------------------- __app__.Collections = __app__.Collections || {}; (function () { __app__.Collections.CartItems = Backbone.Collection.extend({ model: __app__.Models.CartItems }); })();
uso dei Model/Collection
var Item = Backbone.Model.extend({ defaults: { 'field': "Not specified", }, initialize: function(){ } }); var ItemCollection = Backbone.Collection.extend({ model: Song }); var item_list = new ItemCollection([ new Item({ field: "aa" }), new Item({ field: "aa" }), ]);
//-- view ----------------------------------------------- // dispatching events that originate from the UI and propagate Model events __app__.Views = __app__.Views || {}; (function () { __app__.Views.Cart = Backbone.View.extend({ tagName: 'div',// usati da BB per puntare a this.$el id: 'cartView', initialize: function () { // collegamento con altri model e sub-view // binding sulle modifiche al model this.listenTo(this.model, 'change', this.render); // prima di initialize viene fatta _ensureElement() // this.setElement( this.el ); // appena dopo initilize scatta la delegateEvents(), // quindi il dom e this.$el deve essere presente this.render(); }, // mappa evento UI => sub selector => this.method // delega su elementi contenuti nel id corrente events: { "click .toggle": "onToggleClick", //"dblclick .view": "onViewDblclick", //"keypress .edit": "onEditEnter", //"blur .edit": "onEditBlur" }, //NOTA: fondamentale ridefinirla render: function () { var data = this.model.attributes; var html = template_func(data); this.$('#CartView').html(html); //this.delegateEvents();// a seconda del contesto può essere necessario // subviews: preferibile configurarle per renderle manualmente jit //this.collection.each(function(m){ // var tmpView = new subView({ model: m }); // this.$el.append(tmpView.render().el); //}, this); }, //-- altri gestori di eventi -------------------------- onEditEnter: function(){ // aggiorna il model in risposta a input utente this.model.set({name:$("#name").val()}); } }); })(); // uso: // var person = new Backbone.Model({name:''}); // messageView = new MessageView({el: $('#message-container'), model: person });
// inefficient rendering var el_list = $('#list'); var dataset = []; // array of 1000 objects for (var i = 0; i < dataset.length; i++) { var view = new ItemView({model: dataset[i]}); el_list.append(view.render().el); }
Instead of rendering each individual module on the page, you can decide to load all the HTML up into some type of string, array or detached DOM node and then insert them in your views into the page all at once. This leads to touching the DOM less and, in turn, the less times the browser has to repaint itself. Implementation: Render all of your HTML into a string, array, or detached DOM node that will be inserted into the page at a later time.
// batch rendering views var el_items = $('#items'); var el_wrapper = el_items.parent(); el_items.detach(); // this detaches the container element from the DOM var dataset = data; // array of 1000 objects for (var i = 0; i < dataset.length; i++) { var myView = new ItemView({model: dataset[i]}); el_list.append( myView.render().el ); } // put container element into the DOM, which dumps all of the views into the page at once. el_wrapper.append(el_list);
TS backbone https://github.com/tastejs/todomvc/tree/gh-pages/examples/typescript-backbone
module Views { export class HomeView extends Backbone.View { constructor( opt: any ) { // TS constructor, init ts properties super(opt);// BB chiamerà this.initialize(opt); } initialize(opt:any) { // BB contructior, listen to models... } render() { var html = '<div class="content">test render</div> '; this.$el.html(html); return this; } events() { return { 'click .content': 'onOpen', }; } onOpen(event:any) { console.log('onOpen'); } } }
router:
module Mobile { export class Router extends Backbone.Router { public routes:Hash = { '': 'homeAction', //'*actions': 'homeAction', //catch all route 'home': 'homeAction', }; constructor(options?: Backbone.RouterOptions) { super(options); // routes va inizializzato prima di richiamre super, che inizierà la gestione della url // vedi come TS compila il costruttore // call _bindRoutes() here function to bind your routes (<any>this)._bindRoutes(); } public initialize():void { } protected homeAction():void { var el:JQuery = Views.Utils.ensurePage('homeView'); var V = Views.Utils.traceView(new Views.HomeView({ el: el[0] }); V.render().delegateEvents(); } } }