3

Using mustache.js,

I wish to rely on the browser standard page loader to load my mustaches.js templates.

In other words, I want to remove the JQuery request ($.get) to get the templates into memory, yet leaving the template into a separate html file. For now this work:


File contact.html:

<script id="tpl-test" type="text/html">
   <h1> {{firstname}} </h1>
</script>

File my.js

$.get("tpl/contact.html", function(templates){
   var template = $(templates).filter('#tpl-test').html();
   var jdata={firstname: 'fname'};
   $('body').append(Mustache.render(template, jdata));
});

And I wish to have something similar to this:


File contact.html (remain as is)

and instead of a jquery $.get request, I would prefer:

In index.html:

<script id="tpl-test" src="tmpl/contact.html" type="text/html"></script>

Update: In Chrome, the template is loaded like this: enter image description here


File my.js (my wish, but this does not work)

function ondemand(){
   var template = $(templates).filter('#tpl-test').html();
   var jdata={firstname: 'fname'};
   $('body').append(Mustache.render(template, jdata));
});

Thanks in advance.

Alain
  • 1,450
  • 3
  • 20
  • 37
  • 2
    – You won't be able to do it this way. Is there a specific problem you are trying to overcome that `$.get` is causing for you? My guess is that you don't like the delay when you go to use the template. Can you elaborate? – Doug Neiner Nov 28 '12 at 16:03
  • 1
    @Doug Neiner: Good comment, I do not wish to synchronize the window.load event with a (custom event, confirming the loading of all the templates). I want to avoid turning into a scenario where I use a template, but find out it is not loaded already. In my perception, $.get should be used on users dynamic action (or demand). For me templates are a static element. As a minor detail, esthetically, I do not wish to pollute the main index.html with all those templates and I oversee a problem on different index.html composition later on. – Alain Nov 28 '12 at 16:17
  • 1
    – I normally use Require.JS and the text plugin. I require my templates into the files that need them. And I can precompile all my JS and templates into a single asset for production. I'll add that my answer as well should you find it helpful. – Doug Neiner Nov 28 '12 at 16:24
  • I know I should use require.js, However, my knowledge is not there yet. But again, require.js is a dynamic process while the templates are static elements, and I do not wish to process them in a dynamic way. Any tricks without require.js would be appreciated ? – Alain Nov 28 '12 at 16:40
  • – I understand if you are not ready to jump into require. However, its not dynamic once you compile the templates. The dynamic nature is only during development where all your files are separate. – Doug Neiner Nov 28 '12 at 16:49
  • 1
    However, you can't load them in to the HTML without JavaScript unless you use a server side include to include them in the HTML. Of course, you don't want to pollute your HTML (agreed), so that leaves JavaScript. The two ways I have suggested both solve the problem. I can elaborate more on the first answer, but it does what you want. Starts loading the template as soon as the page loads (like the script solution you wanted), but you can use your `ondemand` regardless of if the template is ready yet. Nothing else is coming to mind, sorry :( – Doug Neiner Nov 28 '12 at 16:51
  • I do not want to change the question, but a related question would be: why it is not possible to manipulate a script tag loaded with script+type='text/html' as it is to manipulate a script tag loaded the $.get() ? I could not end up with the same solutions on both script option using the jq...html(). – Alain Nov 28 '12 at 17:04
  • The file isn't even loaded by the script tag. If you open your network tab on Chrome Dev Tools, you'll see the file is not requested from the server. I didn't look too much into why, but it just wasn't even loading. – Doug Neiner Nov 28 '12 at 18:02

2 Answers2

4

As I said in my comment, you won't be able to reference template files like you want to (Using script and the src attribute).

If I can guess why you might not like $.get is that it makes you wait to use the template by the time you actually request the file.

I'd like to suggest a small change to your code that might do what you want:

// Somewhere that runs immediately
// contactTemplate will contain a jqXHR object
var contactTemplate = $.get( "tmpl/contact.html ");


// Somewhere later in your code
function ondemand(){
   contactTemplate.done( function ( template ) {
       var jdata={firstname: 'fname'};
       $('body').append(Mustache.render(template, jdata));
   });
});

This allows your template to most likely be loaded by the time ondemand is called, but if it isn't, the done callback will wait for it to return. This removes the concern of a race condition, and still loads the templates quickly.

Once it has loaded, subsequent calls to ondemand would call the done callback immediately.

This uses the newer jqXHR return value from $.get that supports jQuery Deferreds.

Update

Just to comment on how I handle this in my projects. I use RequireJS and the text plugin to handle templates. I also use r.js optimizer, so all my templates and JS code can be bundled into a single resource on the production site. This lets me specify the dependency where it is used (The JavaScript), but never have to wonder if my templates are loaded when I go to use them.

To give you and idea how this looks in require, lets say I have a contact.js that has my ondemand call:

define( [
  "jquery",
  "mustache",
  "text!tmpl/contact.tmpl"
], function ( $, Mustache, contactTemplate ) {
  function ondemand(){
    var jdata={firstname: 'fname'};
    $('body').append(Mustache.render(contactTemplate, jdata));
  });

  return {
     show: ondemand
  };
});
Doug Neiner
  • 65,509
  • 13
  • 109
  • 118
  • 1
    I like your proposition. For now, all my searches on the web could not solve this issue. Although you did not prevent the $.get, you did improve the searched solution by avoiding beautifully the race condition between the load() and the uses() of a template. – Alain Nov 28 '12 at 16:52
0

All this $.get can be avoided by this solution

This solution meet the following needs:

  1. Have an external file (not .html but .js) to contain all templates.
  2. Have the <script> handle the $.get of the corresponding .js file.
  3. Simplified when used with coffeescript to remove end-of-line escapes.
  4. Probably faster to load a .js string then having to load and process each files to finally end up with .js strings anyway.
Community
  • 1
  • 1
Alain
  • 1,450
  • 3
  • 20
  • 37