简体   繁体   中英

Backbone.js - How should a View update multiple HTML elements?

Given the following HTML

<div id="outer">
  <div id="innerA"></div>
  <div id="innerB"></div>
  <div id="innerC"></div>
</div>

Should a View's render method update each element individually, ignoring the parent (outer) div:

MyView = Backbone.View.extend({
  model: null,

  initialize: function(options) {
    var self = this;
    this.model = options.model;
    _.bindAll(this, 'render');
    this.model.bind('change', this.render);
  },

  render: function() {
    var self = this;
    $('#innerA').html(this.model.get('A'));
    $('#innerB').html(this.model.get('B'));
    $('#innerC').html(this.model.get('C'));
  },
});

Or should it write HTML and values:

MyView = Backbone.View.extend({
  el: '#outer',
  model: null,

  initialize: function(options) {
    var self = this;
    this.model = options.model;
    _.bindAll(this, 'render');
    this.model.bind('change', this.render);
  },

  render: function() {
    var self = this;
    var element = jQuery(this.el);
    element.html('');
    element.append('<div id="innerA">' + this.model.get('A') + '</div>');
    element.append('<div id="innerB">' + this.model.get('B') + '</div>');
    element.append('<div id="innerC">' + this.model.get('C') + '</div>');
    return this.el;
  },
});

Or should it create nested models and views to delegate rendering:

MyView = Backbone.View.extend({
  model: null,

  initialize: function(options) {
    var self = this;
    this.model = options.model;
    _.bindAll(this, 'render');
    this.model.bind('change', this.render);
  },

  render: function() {
    var self = this;

    var modelA = new ModelA();
    modelA.set({
      value: this.model.get('A'),
    });
    var viewA = new ViewA({
      model: modelA
    });

    // Assume ViewA renders '<div id="innerA"></div>'
    $('#innerA').html(viewA.render().html());

    // Rinse and repeat for B and C.
  },
});

This totally depends on the content of #innerA , #innerB , #innerC etc.

If those are independent functionalities with their own collection/model where they update & retrieve data, it's better to keep them as separate view's. They'll completely handle their functionalities, where the parent view will simply control actions such as their creation, deletion etc.

In the case of your first two example, all of these seems to be using the same model and is just printing single attribute. There is no need to create separate views. The rendering is commonly handled by using a template engine like underscores template method:

MyView = Backbone.View.extend({
  template: _.template($('#temp').text()),
  initialize: function(options) {
    this.listenTo(this.model, 'change', this.render);
    this.render();
  },
  render: function() {
    this.$el.append(this.template(this.model.toJSON()));
  }
});
var view = new MyView ({
 model: new Backbone.Model(),
 el: $('#outer')
});
<div id="outer">
</div>
<script type="text/template" id="temp">
  <div id="innerA"><%=A%></div>
  <div id="innerB"><%=B%></div>
  <div id="innerC"><%=C%></div>
</script>

In case #innerA , #innerB , #innerC where 3 independent functionalities, You'll have 4 views with the parent view creating all the 3 child views and appends to it as part of it's rendering.


Side notes:

  • Backbone will automatically set model & collection options to the view if present, no need to do this manually
  • We generally don't use global selectors like $('#innerA') within a view ( ignore the template selector for demo purpose ). Always limit DOM access within the view like this.$('#innerA') (alias for this.$el.find('#innerA') )
  • Read this answer regarding the other changes I've made.

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