kikuchiyo
kikuchiyo

Reputation: 3421

Cannot get variables to interpolate in underscore.js template while jasmine.js testing

EDIT: Forgot to remind the reader that I remembered to set templateSettings as follows:

_.templateSettings = {
    interpolate : /\{\{([\s\S]+?)\}\}/g
};

I'm having a hard time getting a varialbe to interpolate in underscore, while running my Jasmine specs. Given the template, rendering method, and jasmine test below, I am able to get the template to interpolate variables properly via:

_.template(
  boneHeaderInstance.template.html(), 
  { id:boneHeaderInstance.id,  
    columns:boneHeaderInstance.columns
  }
)

While this fails to interpolate the columns variable:

boneHeader = Backbone.View.extend({
  el: $('#boneTableHeader'),
  template: $('#boneTableHeaderTemplate'),
  initialize: function(){
    this.id = 'boneTableHeader';
    this.el = $( '#' + this.id );
    this.columns = 'blah';
    this.template = $( '#' + this.id + 'Template' );
    this.render();
    return this;
  },
  render: function(){
    var that = this;
    var data = {id: that.id, columns: that.columns}
    this.el.html( _.template( this.template.html(), data ) );
  }
});

Template:

<script type = 'text/template' id = 'boneTableHeaderTemplate'>
  <tr id = "{{obj.id}}Row">
    {{obj.columns}}
  </tr>
</script> 

In Render Method:

render: function(){
  var that = this;
  var data = {id: that.id, columns: that.columns}
  this.el.html( _.template( that.template.html(), data ) );
}

Jasmine Test:

describe('boneHeader', function(){
  beforeEach(function(){
    boneHeaderInstance = boneTableInstance.header;
  }); 
  describe('rendering', function(){
    it('should have expected html', function(){
      expect( 
        boneHeaderInstance.el.html().replace(/\s\t\n/ , '', 'g') 
      ).toEqual( 
        _.template(boneHeaderInstance.template.html(), 
        { id:boneHeaderInstance.id,  
          columns:boneHeaderInstance.columns
        }).replace(/\s\t\n/ , '', 'g') 
      );
    }); 
  }); 
});

Jasmine Result:

Expected ' <tr id="boneTableHeaderRow"></tr> ' to equal ' <tr id = "boneTableHeaderRow"> blah </tr> '

Upvotes: 0

Views: 2087

Answers (1)

mu is too short
mu is too short

Reputation: 434965

You have various problems. First of all, Underscore uses <% %> for templates unless you change it with something like:

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

So your template should look like this:

<script type = 'text/template' id = 'boneTableHeaderTemplate'>
    <tr id = "<%= obj.id %>Row">
        <td><%= obj.columns %></td>
    </tr>
</script>

I've also fixed the HTML error you had in your template, you can't have a text node as an immediate child of a <tr> and there's no telling what sort of chicanery a browser will get up to if you try such a thing.

Secondly, _.template() is usually used to return a compiled version of a template and that compiled version is a function that you execute to get the final HTML:

var t    = _.template(some_template_html);
var html = t(data);

So you probably want something like this in your constructor:

this.template = _.template($('#' + this.id + 'Template').html());

and this in your render:

this.el.html(this.template(data));

You can do it all at once with _.template(template_html, context) though.

Thirdly, you're referencing obj.id and obj.columns in your template but you're only giving it id and columns so either drop the obj. prefixes from your template or alter data thusly:

var data = {
    obj: {
        id: that.id,
        columns: that.columns
    }
};

Demo: http://jsfiddle.net/ambiguous/NYLqH/

You'll have to fix your test to account for the corrected HTML of course.

Upvotes: 2

Related Questions