Skip to content

Maintain position of JST templates #80

Closed
wants to merge 1 commit into from
@shayne
shayne commented Oct 15, 2010

Ran into an issue where I needed some vendored libraries (like underscore and jQuery) loaded before my templates, but my application specific js (e.g. common.js, core.js) loaded after the templates.

Updates to packager and compressor.

@shayne shayne Maintain first instance index/position of templates in assets file.
Grep the template paths and get the position of the first template, shifting off first template to create a list of paths to not set URLs for.

Set URLs for all paths, minus the remaining template paths (templates having one aggregate URL).

If necessary, set the asset_url at the index of the first template path (this maintains our position in the yml file).

Similar changes made to the compressor to concatenate the JS files around the position of the first JST template.
3cb6152
@jashkenas
DocumentCloud member

I kind of think that it's a feature to have all of the templates included at the bottom of the asset package. Shouldn't your JavaScript that needs the templates to be loaded be waiting for DOMReady, and not executing the templates immediately?

@shayne
shayne commented Oct 15, 2010

I understand your point and maybe you can weigh in on my reasoning.

I'm building a simple example app using Rails, Backbone and Jammit. My backbone collections, models and views are loaded into memory before the DOM is ready, this seems logical to me.

The order specified is my assets.yml looks something like:
- public/javascripts/jquery.js
- public/javascripts/underscore.js
- public/javascripts/backbone.js
- app/views/*/.jst
- public/javascripts/common.js

The common.js files contains the Backbone models, views and collections.

Here's one of those views:

var TaskView = Backbone.View.extend({
  tagName: "li",

  events: {
    "click .destroy" : "destroyTask"
  },

  template: JST["task"],    // needs to have template in memory

  initialize : function() {
    this.render();

    this.model.bind("change", _.bind(this.render, this));
  },

  render : function() {
    $(this.el).html(this.template(this.model.toJSON()));
    this.handleEvents();
    return this;
  },

  destroyTask : function() {
    this.model.destroy();
    $(this.el).slideUp(300, function() {
      $(this).remove();
    });
    return false;
  }
});

With the Jammit always putting JSTs at the bottom I'd need to create three expansions in my assets.yml:

  1. vendor - all 3rd party libs
  2. templates - JSTs
  3. common - application specific JS including Backbone models, views, collections, etc...

This is a workaround really that adds two additional requests for JS just to accomodate an order of operations.

Interested at your take...

@jashkenas
DocumentCloud member

That's an excellent use case for doing ordered JavaScript template includes. I'll take a pass at merging your patch. For the time being, you can just look up the template from the JST object inside of the render function...

@mikz
mikz commented Oct 16, 2010

I would use @Array.split@ or @Array.chunk@ to split array and preserve ordering even if there would be multiple template blocks. But sadly first is dependent on active_support/core_extensions and second on Ruby 1.9.2.

@agibralter

You could also not refer to global objects before they are defined and access them at "run time" (i.e. when the function is called):

var TaskView = Backbone.View.extend({
  tagName: "li",

  events: {
    "click .destroy" : "destroyTask"
  },

  template: "task",

  initialize : function() {
    this.render();

    this.model.bind("change", _.bind(this.render, this));
  },

  render : function() {
    $(this.el).html(JST[this.template](this.model.toJSON()));
    this.handleEvents();
    return this;
  },

  destroyTask : function() {
    this.model.destroy();
    $(this.el).slideUp(300, function() {
      $(this).remove();
    });
    return false;
  }
});
@zerowidth

+1 to this. In the meantime, lazy-evaluation of templates in the render function bypasses the issue.

@trungpham

I need this too...

@jsmestad

+1 to this as well.

@atavistock

We're facing the same problem. It would also be the path of least confusion to make reasonable attempts to preserve the order.

@trungpham

any update on this pull request? it has only been opened for 10 months. :)

@jashkenas
DocumentCloud member

Nope -- just been busy, sorry about that.

@unicornrainbow

+1 This would be nice to have.

I was surprised to learn that JST are included at the end... I'm curious about the rationale behind doing it that way verus just honoring the order specified in the assets.yml file.

@jarosan
jarosan commented Dec 28, 2011

Just came across this issue. +1 on keeping the include order.

@euge
euge commented Jan 31, 2012

+1

@euge
euge commented Jan 31, 2012

This patch is still valid, but PATH_TO_URL needs to be replaced with path_to_url. Thanks

@splurgy-michi

+1. Hit a scenario where the document ready state is ALREADY true when the JS is being loaded in. This causes the application to start running as soon as it is loaded in before it has a chance to load in the templates (this is an IE8-only issue and is highly annoying). Using document on ready does not help in this scenario.

@sobrinho

I'm surprised by this behaviour too, I workarounded it using the lazy-evaluation but still do not make sense.

+1 for merging, respecting the assets.yml order is a must 👍

@shayne shayne closed this Oct 29, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.