My Backbone.View won't render

2019-09-05 07:04发布

问题:

I reorganized my fully-working Backbone.js project and moved all my models, collections and views into separate files, and did a little rewriting, and now it won't render. I've tried everything I can think of. Any tips?

var SessionView = Backbone.View.extend({
    model: Session,
    el: '#list',
    template:  _.template($('#session-template').html()),
    initialize: function () {
        this.model.bind('change', _.bind(this.render, this));
        this.render();
    },
    render: function () {
        this.$el.html(this.template({sessions: sessionList}));
        return this;
    }
});
var sessionView = new SessionView();

var SessionListView = Backbone.View.extend({
    el: '#list',
    model: sessionList,
    initialize: function () {
        sessionList.bind('add', this.add, this);
        sessionList.bind('reset', this.add, this);
        sessionList.fetch();
    },
    render: function () {
        var view = new sessionListView();
        this.$el.append(view.render().el);
        new SessionView({model: Session});
        return this;
    }
});

var sessionListView = new SessionListView();

回答1:

Few things that I noticed:

  1. Backbone.View does not have a model property. Only Backbone.Collection has a model property, which backbone will use to create an instance of model using the specified model constructor (blueprint) and data passed to it.

    But views doesn't have a functionality like this (as far as I know). People usually pass an instance of a specific type of model with the options while creating a view, that's not the same as specifying a model property which points to a model constructor in the View's constructor.

    sessionList doesn't seems to be an instance of a model (since it is specified in the view's constructor. If it's an instance it'll be shared by all the SessionListView instances which is not the desired behavior in most cases) and seems to be undefined

    in the following:new SessionView({model: Session}); Session doesn't look like an instance of a model (Doesn't start with a capital letter, hoping you're following naming conventions) and also seems to be undefined

    Well nothing is stopping you from specifying a model constructor in view's constructor or passing a model constructor into the view, but then you should make an instance of it (mostly while initializing) inside the view to work with. In other words you can not do blueprintOfAModel.bind('change'..); and you should build an actual model for the view to work with.

  2. You seems to be creating new SessionListView in the render method of SessionListView itself with var view = new sessionListView(); won't that create infinite number of SessionListView instances when you simply try to create one..?

    Well by looking at it again, you are not calling the actual constructor SessionListView with the new operator, but with an instance of it (sessionListView) which is likely to throw an error.

  3. Both SessionView and SessionListView points to the same element, which seems weird. I haven't seen people doing that before since modifying the el of one view will have an impact on the other view, which is not desired in most practical cases.

    Also judging by the names, since you have a list view of session, SessionView should not be pointing to a particular element with an id selector. You should create a new element for each SessionView instance. Backbone will do that for you if you don't specify el property.

(I'd say you created an unintentional mess that wasn't there with a little rewrite :)


To make sense, your code should look somewhat like the following. Note that things starting with capital letter are constructor functions and things starting with small letters are object instances

var Session = Backbone.Model.extend({
  defaults: {},
  initialize: function() {}
});
var SessionList = Backbone.Collection.extend({
  model: Session,
  initialize: function() {}
});
var SessionView = Backbone.View.extend({
  initialize: function() {
    this.model.bind('change', _.bind(this.render, this));
    this.render();
  },
  template: _.template($('#session-template').html()),
  render: function() {
    this.$el.html(this.template({
      session: this.model
    }));
    return this;
  }
});
var SessionListView = Backbone.View.extend({
  el: '#list',
  initialize: function() {
    this.collection.bind('add', this.add, this); // method doesn't exist, should throw error
    this.collection.bind('reset', this.add, this); // same here
    this.collection.fetch();  // <--- watch out, this happens asynchronously
  },
  render: function() {
    // iterate through collection, create instances of SessionView and append to el
    return this;
  }
});

var sessionList = new SessionList(); // will create n number of Session instances in future

var sessionListView = new SessionListView({ // will create n number of SessionView instances in future
  collection: sessionList
});