1

Here's a template I'm using

<script type="text/template" id="template-message">
  <p class="message"><%= message %></p>
</script>

Here's my Backbone.View

var MessageView = Backbone.View.extend({

  template: _.template(Backbone.$("#template-message").html()),

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

How I'm using it

var msg  = new Message({message: "hello"}),
    view = new MessageView({model: msg});

$("body").append(view.render().el);

Output

<body>
  <div>
    <p class="message">
      hello
    </p>
  </div>
</body>

I understand why it's happening (the default tagName for a view is div), but I don't want the wrapper div on there. I would like to see this as the output

<body>
  <p class="message">
    hello
  </p>
</body>

I'm aware that I could have this in my view

var MessageView = Backbone.View.exntend({
  tagName: "p",
  className: "message",
  // ...
});

The end user will be define the templates, so I don't want those things to be specified in the Backbone.View source code.

How can I get the desired output and still bind the view to the html?

Mulan
  • 129,518
  • 31
  • 228
  • 259

2 Answers2

1

Thanks to @Gohn67's comment, I was able to get this working

var MessageView = Backbone.View.extend({

  template: _.template(Backbone.$("#template-message").html()),

  initialize: function() {
    this.setElement(this.template(this.model.attributes));
  }

});

If we take a look at the Backbone Source Code, we can see it setElement does everything we want it to do

// backbone source code
setElement: function(element, delegate) {
  if (this.$el) this.undelegateEvents();
  this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
  this.el = this.$el[0];
  if (delegate !== false) this.delegateEvents();
  return this;
},

It even handles the event delegation. Cool!


I recently had to implement this on jQuery 1.3.2. Gross, I know, but it was a simple fix.

The only part that changes is the setElement bit

  initialize: function() {
    this.setElement(
      $( this.template(this.model.attributes) )
    );
  }

The template result must be wrapped in $() in order to work. I know, it doesn't make a lot of sense considering Backbone is already trying to do this automatically. It's the only thing I could do to make it work with jQuery 1.3.2 though.

Mulan
  • 129,518
  • 31
  • 228
  • 259
0

You could also use Backbone.Declarative.Views (which I have written) and define the el properties – like tagName, className etc – as data attributes in the template. See this answer on SO.

Community
  • 1
  • 1
hashchange
  • 7,029
  • 1
  • 45
  • 41