logo

NJP

Underscore.js client side templates in CMS

Import · Oct 14, 2015 · article

I spent a few days working to get client side js based templates to work in our CMS. I wanted to share with everyone how I made that work.

1. The templates will have to be embedded in the DOM under script tags.

2. The template syntax will require using the Jelly tags for special characters, and some interesting 2 stage parsing to clean up the mess jelly leaves in the templates

this includes replacing the "&", "<" and ">" characters with jelly equivalents: ${AMP}, ${LT}, ${GT}

3. Jelly mangles the special characters contained in HTML attributes, which is the reason for a wierd second stage string replace in the client

// do a global replace for the html character codes jelly produces for brackets

// second pass required for any brackets encased in html attributes

templ_str = _.unescape($templ.html()).replace(/&lt;/g, '<').replace(/&gt;/g, '>');

4. jQuery is used to pull the templates out of the DOM and the HTML contained in the script tag is passed to the underscore template engine

1. two dynamic blocks are used, one acts as a container for all client side templates

wrapper

<?xml version="1.0" encoding="utf-8" ?>

      <!-- sysid: ******************************* -->

     

/j:jelly

client side template - search

<?xml version="1.0" encoding="utf-8" ?>

      <!-- sys_id: *************************** -->

      </p> <p>              ${LT}% if(data.length){   %${GT}</p> <p>                      <div class="col-sm-12 padding-left-0 padding-right-0" data-category="${LT}%= category_name %${GT}"></p> <p>                              <div class="row"></p> <p>                                      <div class="col-sm-12 header padding-top-2pct padding-bottom-1pct"></p> <p>                                              <h3 class="h3">Knowledge Base</h3></p> <p>                                      </div></p> <p>                              </div>                       </p> <p>                              <div class="row"></p> <p>                                      <div class="col-sm-12 request_list" data-delegate-bound="true">                               </p> <p>                                              <ul class="styled_link"></p> <p>                                                      ${LT}% _.each(data, function(obj, key){   %${GT}</p> <p>                                                              <li data-sys-id="${LT}%= obj.sys_id %${GT}"></p> <p>                                                                      <div class="title"></p> <p>                                                                              <a target="_new" href="#"></p> <p>                                                                                      <span>${LT}%= obj.descr %${GT}</span></p> <p>                                                                              </a></p> <p>                                                                      </div></p> <p>                                                                      <div class="short-description"></p> <p>                                                                              <span>${LT}%= obj.intro %${GT}</span></p> <p>                                                                      </div></p> <p>                                                              </li></p> <p>                                                      ${LT}% });   %${GT}</p> <p>                                              </ul> </p> <p>                                      </div></p> <p>                              </div>     </p> <p>                      </div>     </p> <p>              ${LT}% } %${GT}           </p> <p>     

/j:jelly

Client script function to parse template from DOM

/**

          read underscore.js formatted js template from DOM, and convert to a template function

          @method _getTemplate

          @param {str} tmpl_id DOM id of the template

          @returns {function} underscore template fx

          @link http://stackoverflow.com/questions/4778881/how-to-use-underscore-js-as-a-template-engine

      */

      _getTemplate : function(tmpl_id){

              var result;

              var context = this;

              // prevent jQuery and prototype collision with an IIFE

              (function($){

                      try{

                              if (!(_.isString(tmpl_id) && tmpl_id.length)){

                                      throw new Error('Invalid parameter "template id"');

                              }

                              // pull up the template and correct for the html encoded brackets

                              var $templ = $('#'+tmpl_id);

                              var templ_str = '';

                              if ($templ && $templ.length){

                                      if ($templ.html().length){

                                              // do a global replace for the html character codes jelly produces for brackets

                                              // second pass required for any brackets encased in html attributes

                                              templ_str = _.unescape($templ.html()).replace(/&lt;/g, '<').replace(/&gt;/g, '>');

                                              //log.info(templ_str);

                                              result = _.template(templ_str);

                                      }

                                      else{

                                              throw new Error('Template "'+tmpl_id+'" is empty. No HTML found to render');

                                      }

                              }

                              else{

                                      throw new Error('Template "'+tmpl_id+'" not found in the DOM');

                              }

                      }

                      catch(e){

                            log.error('Error: '+e.message+' - _getTemplate::'+context.type);

                      }

              })(jQuery);

              return result;

      },

View original source

https://www.servicenow.com/community/south-carolina-snug/underscore-js-client-side-templates-in-cms/ba-p/2280913