2

The problem is I want to render option elements with the value attribute set as well as the text node.

So setting tagName to option in my ItemView does not just do this. The solution I have at the moment is to set it to option and then use the following code in the ItemView constructor to set the value attibute:

 onRender: function () {
            this.$el.attr('value', this.model.get('name'));
        }

This works.

But is there any other way?

What I'd really like to do is just tell Marionette not to output an element at all and then in my ItemView template have this:

<option value="<%= name %>"> <%= name %> </option>

Is this possible?

3 Answers3

0

It's possible but a bit fiddly, by default Backbone always uses a wrapper element (definable by using tagName) but you'd have to expressly populate the attributes (as you are doing above).

It is however possible to circumvent the wrapper element using a slightly convoluted setElement approach and this will enable you keep all markup in a template with attributes on the root node populated from the model. I like this approach as well since I personally think it keeps a clearer separation of concerns.

Take a look here for an example - Backbone, not "this.el" wrapping

Not sure if Marionette has a build in mechanism for doing this.

Community
  • 1
  • 1
Dan W
  • 762
  • 5
  • 8
0

I am not sure you should from all different kind of reasons.

But I understand that in the use case of a single tag view, the way Marionette/Backbone work you either create another tag and have a view, or you use onRender and query to update the single tag that was already generated for you.

You could have this Object that will extend ItemView, lets call it SingleTagView. Basicly I am extending ItemView and using overrunning it's render function with one change.

Instead of doing:

this.$el.html(html);

I am doing:

var $html = $(html);
this.$el.replaceWith($html);
this.setElement($html);

Here is the code:

var SingleTagView = Marionette.ItemView.extend({
 render: function() {
  this.isClosed = false;

  this.triggerMethod("before:render", this);
  this.triggerMethod("item:before:render", this);

  var data = this.serializeData();
  data = this.mixinTemplateHelpers(data);

  var template = this.getTemplate();
  var html = Marionette.Renderer.render(template, data);
  // above is standart ItemView code
  var $html = $(html);
  this.$el.replaceWith($html);
  this.setElement($html);
  // this code above replaced this.$el.html(html);
  // below is standart ItemView code
  this.bindUIElements();

  this.triggerMethod("render", this);
  this.triggerMethod("item:rendered", this);

  return this;
}
});

If you are going to use this kind of angle, make sure you test the behavior properly (event handling, Dom leaks, different flows with before:render events).

ekeren
  • 3,408
  • 3
  • 35
  • 55
0

I would try:

var optionTag = Marionette.ItemView.extend({
  tagName: "option",

  initialize: function(){
    this.attributes = {
      value: this.model.get('name');
    }
  }
}

Backbone should then do the rest (i.e. putting the content of attributes into the HTML tag)...

David Sulc
  • 25,946
  • 3
  • 52
  • 54
  • Hmm. This didn't seem to work for me. I can see why it might be expected to work. http://backbonejs.org/#View-attributes But. It didn't. I reduced it to the most simple case. Now, anyway, I have a more complex case where I have 2 html elements in the template and I want to set attributes on both of them. For now I'm just wrapping them both in a

    , but it isn't ideal.

    –  Jul 08 '13 at 14:33