8

Is there a way to set the templateSettings for lodash when using RequireJS?

Right now in my main startup I have,

  require(['lodash', 'question/view'], function(_, QuestionView) {
    var questionView;
    _.templateSettings = {
      interpolate: /\{\{(.+?)\}\}/g,
      evaluate: /\{\%(.+?)\%\}/g
    };
    questionView = new QuestionView();
    return questionView.render();
  });

but it doesn't seem to want to set the templateSettings globally because when I use _.template(...) in a module it wants to use the default templateSettings. The problem is that I don't want to change this setting in every module that uses _.template(...).

milkypostman
  • 2,955
  • 27
  • 23
  • [This SO question](http://stackoverflow.com/questions/8842223/share-resources-across-different-amd-modules) has an answer that is a viable solution to this situation. – Tyson Phalp Jan 15 '13 at 21:24

3 Answers3

16

Based on @Tyson Phalp suggestion, that means this SO question.
I adapted it to your question and I tested it using RequireJS 2.1.2 and SHIM configuration.
This is the main.js file, that is where the requireJS config is:

require.config({
/*  The shim config allows us to configure dependencies for
    scripts that do not call define() to register a module */

    shim: {
      underscoreBase: {
        exports: '_'
      },
      underscore: {
        deps: ['underscoreBase'],
        exports: '_'
      }

    },
    paths: {
      underscoreBase: '../lib/underscore-min',
      underscore: '../lib/underscoreTplSettings',
    }
});

require(['app'],function(app){
  app.start();
});

Then you should create the underscoreTplSettings.js file with your templateSettings like so:

define(['underscoreBase'], function(_) {
    _.templateSettings = {
        evaluate:    /\{\{(.+?)\}\}/g,
        interpolate: /\{\{=(.+?)\}\}/g,
        escape: /\{\{-(.+?)\}\}/g
    };
    return _;
});

So your module underscore will contain the underscore library and your template settings.
From your application modules just require the underscore module, in this way:

define(['underscore','otherModule1', 'otherModule2'], 
   function( _, module1, module2,) { 
      //Your code in here
   }
);

The only doubt I have is that I'm exporting the same symbol _ two times, even tough this work I'm not sure if this is considered a good practice.

=========================

ALTERNATIVE SOLUTION: This also works fine and I guess it's a little bit more clean avoiding to create and requiring an extra module as the solution above. I've changed the 'export' in the Shim configuration using an initialization function. For further understanding see the Shim config reference.

//shim config in main.js file
shim: {     
  underscore: {
      exports: '_',
      init: function () {
        this._.templateSettings = {
          evaluate:/\{\{(.+?)\}\}/g,
          interpolate:/\{\{=(.+?)\}\}/g,
          escape:/\{\{-(.+?)\}\}/g
        };
        return _; //this is what will be actually exported! 
      }
  }
}
Community
  • 1
  • 1
Leonardo
  • 4,046
  • 5
  • 44
  • 85
  • 1
    but couldn't you just change what `underscoreBase` exports? I really like this solution though. Nice and clean with a very minor wrapper. – milkypostman Jan 28 '13 at 22:33
  • 1
    You are right, I added an alternative solution in the code above. – Leonardo Jan 29 '13 at 01:53
  • In case you're using Marionette with the requirejs-tpl plugin (https://github.com/ZeeAgency/requirejs-tpl) consider adding templateSettings = _.templateSettings || { ... }; to line 26 of tpl.js ... This prevents the boogery override of this useful solution above in RequireJS environments. – 4Z4T4R Nov 16 '13 at 03:26
  • 1
    Should the assigned regexes for evaluate and interpolate in the above ALTERNATIVE SOLUTION be reversed? i.e. evaluate should have '='? – 4Z4T4R Nov 16 '13 at 03:31
0

You should pass your _ variable with template settings as function argument or as property in global object (window for browsers or proccess for nodejs).

_.templateSettings = {
      interpolate: /\{\{(.+?)\}\}/g,
      evaluate: /\{\%(.+?)\%\}/g
};
questionView = new QuestionView(_);

Or

_.templateSettings = {
      interpolate: /\{\{(.+?)\}\}/g,
      evaluate: /\{\%(.+?)\%\}/g
};
window._ = _  

First option is better.

Vyacheslav Voronchuk
  • 2,403
  • 19
  • 16
  • but then don't I have to keep passing it down all the way to the actual view thats going to use it? because I have a View containing a Collection, each element in the Collection has its own View and the single views of the collection elements are what is actually rendering templates. – milkypostman Oct 25 '12 at 18:18
  • Actualy you should, but if you can access other object from your view, you can "attach" _ to that object. You can set _ to prototype of your sigle view object, so you will define it once, not for every object: `collectionElementViewObject.constructor.prototype._ = _;` or `collectionElementView.prototype._ = _;` Alternative is either to use global variable or singleton registry-like storage. But it's considired bad practice. – Vyacheslav Voronchuk Oct 25 '12 at 20:24
0

Bear in mind that if you're using underscore >=1.6.0 or lodash-amd the solution is pretty simple:

"main.js" configuration file

require.config({
  baseUrl: './', // Your base URL
  paths: {
    // Path to a module you create that will require the underscore module.
    // You cannot use the "underscore" name since underscore.js registers "underscore" as its module name.
    // That's why I use "_".
    _: 'underscore',

   // Path to underscore module 
   underscore: '../../bower_components/underscore/underscore',
  }
});

Your "_.js" file:

define(['underscore'], function(_) {

  // Here you can manipulate/customize underscore.js to your taste.
  // For example: I usually add the "variable" setting for templates
  // here so that it's applied to all templates automatically.

  // Add "variable" property so templates are able to render faster!
  // @see http://underscorejs.org/#template
  _.templateSettings.variable = 'data';

  return _;
});

A module file. It requires our "_" module which requires "underscore" and patches it.

define(['_'], function(_){
  // You can see the "variable" property is there
  console.log(_.templateSettings);   
});
Túbal Martín
  • 709
  • 6
  • 6