📜 ⬆️ ⬇️

Optimizing work with templates in Backbone

I, like many others, started my acquaintance with the Backbone javascript framework with the todo-tutorial , on the basis of which the framework was used further in my projects.

But tutorials end, and working days begin.


I think many people know such a piece of code (from the above tutorial):
')
window.AppView = Backbone.View.extend({ // Instead of generating a new element, bind to the existing skeleton of // the App already present in the HTML. el: $("#todoapp"), // Our template for the line of statistics at the bottom of the app. statsTemplate: _.template($('#stats-template').html()), ... 


Let's see more:


Of course, for small applications there are no questions. And if the application is large and contains dozens of templates?
Why load and initialize all templates at once? We may not need most of them.

Loading templates



It would be nice to load templates only when we need them and cache them.

Based on this, we will write the bootloader:
  Core.Template = { cache: {}, //     pending: {}, //  callback-,       load: function(url, callback) { callback = callback || function() {}; if (this.cache[url]) { //   ,   callback callback(this.cache[url]); return; } //  callback   if (this.pending[url]) { this.pending[url].push(callback); return; } this.pending[url] = [callback]; jQuery.ajax({ //  url : url, dataType: 'text', complete: function(resp) { var cache = this.cache[url] = _.template(resp.responseText); //      _.each(this.pending[url], function(cb) { //   cb(cache); }); delete this.pending[url]; //   }.bind(this), error: function() { throw new Error("Could not load " + url); } }); } }; 


Downloading the template by ajax, we have an additional opportunity to cache it using the browser.
The queue is made to ensure that the loader does not load the template for each type of model from our collection, but did it once and passed the template ready for work to each type.

I hope that comments on the code are enough to understand how everything works.
Next, we need to teach our views to work with templates in new ways.

Base view class for working with templates



We write the base class of the form so that it can work with our template loader.

  Core.View = Backbone.View.extend({ renderQueue: false, //     initialize: function() { if (this.templateUrl) { Core.Template.load(this.templateUrl, function(data) { this.template = data; //   if (this.renderQueue !== false) { //     _.each(this.renderQueue, function(item) { this._render.apply(this, item); }.bind(this)); this.renderQueue = false; } }.bind(this)); } }, _render: function() {}, //        render render: function() { if (!this.template) { //     -      this.renderQueue = this.renderQueue || []; this.renderQueue.push(arguments); return this; } return this._render.apply(this, arguments); //   } }); 


Thus, if templateUrl is passed in our view parameters, then we load the template, otherwise we work according to the usual logic.
The only difference from the standard behavior, the direct rendering function is put into the _render method. In principle, nothing prevents to rewrite the code that wraps everything in the render method, but it seemed so more convenient and easier for me.

Using



What in practice?
This is how the modified part of the code shown at the beginning of the article will look like:

 window.AppView = Core.View.extend({ el: $("#todoapp"), //    templateUrl: '/templates/app.html', initialize: function() { AppView.__super__.initialize.apply(this); //    ... }, //  render  _render  statsTemplate  template _render: function() { this.$('#todo-stats').html(this.template({ total: Todos.length, done: Todos.done().length, remaining: Todos.remaining().length })); }, ... 


Done!

Loader code is available here .
An example of a modified todo-tutorial can be found here .
If interested, what has changed in todo: diff

Thanks for attention!

Source: https://habr.com/ru/post/138783/


All Articles