简体   繁体   中英

Dynamically set child View $el and have Backbone events fire

I have a parent view (and associated model), with several children Views with the same associated model. The parent view is defined statically from the HTML. These events are working fine.

The children views are created dynamically, and are ultimately different, but have some similar initial structure. The #id s will be different from each other (using the view id number) so that we can know which one is interacted with by the user. I have tried the following from reading around:

  • Adding the el declaration when I create the View (towards the end of the JS)
  • statically defining it, then trying to update it.
  • using _.ensureElement()
  • setting the el in the init()

But I just can't seem to get it for the children views on a fiddle.

Fiddle

JS: Parent

  //The view for our measure
  parentModule.View = Backbone.View.extend({
    //
    //This one is static, so I can set it directly, no problem, the events are working
    //
    el: $('#measure-container'),
    events: {
        'click .test': 'test'
    },
    test: function(){
      alert('test');
    },
    initialize: function() {
      this.template = _.template($('#instrument-template').html());
    },
    render: function(){
      $(this.el).append(this.template(this.model.toJSON()));
      return this;
    }
  });

  return parentModule;
});

JS: Child

  // THe child views are dynamic, so how do I set their id's dynamicall and still get the click events to fire?
  //
  childModule.View = Backbone.View.extend({
    //
    // Do I set the el here statically then override?
    //
    events: {
      'click .remove-rep' : 'removeRepresentation',
      'click .toggle-rep' : 'toggleRepType',
      'click .sAlert': 'showAlert'
    },
    initialize: function(options) {
      //
      //Do I set the el here using ensure_element?
      //
      this.model=options.model;
    },
    render: function(){
      //
      // Do I Set it here when it renders?
      //

      this.template = _.template($('#rep-template').html());
      $('#measure-rep-container').append(this.template());
      return this;
    },
    showAlert: function() {
      alert("This is an alert!");
    }
  });

JS: Instantiation

define( "app", ["jquery", "backbone", "parentModule", "childModule"], function($, Backbone, ParentModule, ChildModule) {    
  var app = {};
    app.model = new ParentModule.Model({ name: "Snare", numOfBeats: 4 });
    app.view = new ParentModule.View({ model: app.model });
    app.view.render();

    app.firstRepChildModel = new ChildModule.Model({ id: 1, type: 'circle', parentModel: app.model });
    // 
    // Do I add the el as a parameter when creating the view?
    // 
    app.firstRepChildView = new ChildModule.View({ el:'#rep'+app.firstRepChildModel.get('id'), model: app.firstRepChildModel });
    app.firstRepChildView.render();

    app.secondRepChildModel = new ChildModule.Model({ id: 2, type: 'line', parentModel: app.model });
    // 
    // Do I add the el as a parameter when creating the view?
    // 
    app.secondRepChildView = new ChildModule.View({ el:'#rep'+app.secondRepChildModel.id, model: app.secondRepChildModel });
    app.secondRepChildView.render();
  return app;
});

HTML:

<h3>Measure View</h3>
    <div id="measure-container">
    </div>

<!-- Templates -->
<script type="text/template" id="instrument-template">
  <div class="instrument">
      I am an instrument. My name is <%=name%>. <br/>
      Here are my children repViews: <br/>
      <div id="measure-rep-container">
        <div class="btn btn-primary test">Add a rep</div>
      </div>
  </div>
</script>

<script type="text/template" id="rep-template">
  <div class="rep" id="rep<%=this.model.id%>">
      I am a repView <br/>
      My ID is 'rep<%=this.model.id%>' <br/>
      My el is '<%=this.$el.selector%>'<br/>
      My type is '<%=this.model.type%>' <br/>
      I have this many beats '<%=this.model.numOfBeats%>' <br/>
      <div class="beatContainer"></div>
      <div class="btn btn-danger remove-rep" id="">Remove this rep</div>
      <div class="btn btn-primary toggle-rep" id="">Toggle rep type</div>
      <div class="btn sAlert">Show Alert</div>
  </div>
</script>

Every view has a associated el , whether you set it directly or not, if you don't set it then it's el is just a empty div.

In your code you aren't modifying your child view's el or attaching it to the DOM .

Try the following

render: function(){

  this.template = _.template($('#rep-template').html());
  //this sets the content of the el, however it still isn't attached to the DOM
  this.$el.html(this.template()); 
  $('#measure-rep-container').append(this.el);
  return this;
},

Updated fiddle

As a separate point if you are going to be reusing the same template multiple times you might want to just compile it once, for example

childModule.View = Backbone.View.extend({

events: {
  'click .remove-rep' : 'removeRepresentation',
  'click .toggle-rep' : 'toggleRepType',
  'click .sAlert': 'showAlert'
},

//get's called once regardless of how many child views you have
template: _.template($('#rep-template').html()), 

render: function(){
  this.$el.html(this.template()); 
  $('#measure-rep-container').append(this.el);
  return this;
},

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM