newBike
newBike

Reputation: 15022

Backbone issues multiple ajax requests unexpectedly

I put the fetch url with deferred method and I expect it will only invoke the remote ajax request one time.

However, it calls three times when I load the page.

How could I fix it? Thanks

js scripts

var Comments = Backbone.Collection.extend({
    model: Comment,
    url: fetch_comments_url,
    initialize: function() {
        this.fetch({
            success: this.fetchSuccess,
            error: this.fetchError
        });
        this.deferred = new $.Deferred();
    },
    deferred: Function.constructor.prototype,
    fetchSuccess: function(collection, response) {
        collection.deferred.resolve();
    },
    fetchError: function(collection, response) {
        throw new Error("Products fetch did get collection from API");
    },
var comments = new Comments();

...

comments.deferred.done(function() {
    commentView.render();
    emptyCommentView.render();
});

compelte js scripts

var Comments = Backbone.Collection.extend({
    model: Comment,
    url: fetch_comments_url,
    initialize: function() {
        this.fetch({
            success: this.fetchSuccess,
            error: this.fetchError
        });
        this.deferred = new $.Deferred();
    },
    deferred: Function.constructor.prototype,
    fetchSuccess: function(collection, response) {
        collection.deferred.resolve();
    },
    fetchError: function(collection, response) {
        throw new Error("Products fetch did get collection from API");
    },
    wellFormedComments: function () {
        var MESSAGE_LIMIT_LENGTH = 80
        var models = comments.select(function (model) {
          var msg = model.get("message")
          if (msg!=null) {
            msg = msg.replace(/^\s+|\s+$/g, '')
            if (msg.length >= MESSAGE_LIMIT_LENGTH) {
              model.set("preview_message", msg.substr(0, MESSAGE_LIMIT_LENGTH/2));
            } else{
            };
            return true
          }
          else{
              return false
          };
        });
        return new Comments(models);
    },
    emptyComments: function () {
        var models = comments.select(function (model) {
          var msg = model.get("message")
          return false===_(msg).notBlank();
        });
        return new Comments(models);
    }
    });
var comments = new Comments();
var CommentView = Backbone.View.extend({
    el: $("#comments_section"),
    render: function() {
        var notNullComments = comments.wellFormedComments();
        if (notNullComments.length > 0) {
            $("#dadasay_comments_plugin").show();
        }
        var html = commentsTmpl(notNullComments.toJSON());
        $(this.el).append(html);
    },
});
var EmptyCommentView = Backbone.View.extend({
    el: $("#empty_comments_list"),
    render: function() {
        var source = $('#empty_comments_list_tmpl').html();
        var emptyComments = comments.emptyComments();
        var html = emptyCommentsTmpl(emptyComments.toJSON());
        $(this.el).html(html);
    },
});
var commentView = new CommentView({
    collection: comments
});
var emptyCommentView = new EmptyCommentView({
    collection: comments
});
comments.deferred.done(function() {
    commentView.render();
    emptyCommentView.render();
});

Upvotes: 0

Views: 97

Answers (1)

T J
T J

Reputation: 43166

The problem is that your comments collection triggers fetch when initialized. It's methods wellFormedComments and emptyComments creates new comments collections so they triggers fetch as well.

You can fix this by manually triggering fetch when required, something like:

var Comments = Backbone.Collection.extend({
  model: Comment,
  url: fetch_comments_url,
  wellFormedComments: function() {
    var MESSAGE_LIMIT_LENGTH = 80
    var models = this.select(function(model) {
      var msg = model.get("message")
      if (msg != null) {
        msg = msg.replace(/^\s+|\s+$/g, '')
        if (msg.length >= MESSAGE_LIMIT_LENGTH) {
          model.set("preview_message", msg.substr(0, MESSAGE_LIMIT_LENGTH / 2));
        } else {};
        return true
      } else {
        return false
      };
    });
    return new Comments(models);
  },
  emptyComments: function() {
    var models = this.select(function(model) {
      var msg = model.get("message")
      return false === _(msg).notBlank();
    });
    return new Comments(models);
  }
});
var CommentView = Backbone.View.extend({
  el: $("#comments_section"),
  render: function() {
    var notNullComments = comments.wellFormedComments();
    if (notNullComments.length > 0) {
      $("#dadasay_comments_plugin").show();
    }
    var html = commentsTmpl(notNullComments.toJSON());
    $(this.el).append(html);
  },
});
var EmptyCommentView = Backbone.View.extend({
  el: $("#empty_comments_list"),
  render: function() {
    var source = $('#empty_comments_list_tmpl').html();
    var emptyComments = comments.emptyComments();
    var html = emptyCommentsTmpl(emptyComments.toJSON());
    $(this.el).html(html);
  },
});
var comments = new Comments();
var commentView = new CommentView({
  collection: comments
});
var emptyCommentView = new EmptyCommentView({
  collection: comments
});

comments.fetch({ // <--------- Do this manually once
  success: function() {
    commentView.render();
    emptyCommentView.render();
  },
  error: function() {}
});

I think you can better structure your code as shown below, hope the comments explain the changes

var Comments = Backbone.Collection.extend({
  model: Comment,
  url: fetch_comments_url,
  wellFormedComments: function() {
    var MESSAGE_LIMIT_LENGTH = 80
    var models = this.select(function(model) {
      var msg = model.get("message")
      if (msg != null) {
        msg = msg.replace(/^\s+|\s+$/g, '')
        if (msg.length >= MESSAGE_LIMIT_LENGTH) {
          model.set("preview_message", msg.substr(0, MESSAGE_LIMIT_LENGTH / 2));
        }
        return true
      }
      return false

    });
    return new Comments(models);
  },
  emptyComments: function() {
    var models = this.select(function(model) {
      var msg = model.get("message")
      return false === _(msg).notBlank();
    });
    return new Comments(models);
  }
});
var CommentView = Backbone.View.extend({
  el: $("#comments_section"),
  template: commentsTmpl, // template reference, better create it here
  initialize: function() {
    this.render(); // self rendering
  },
  render: function() {
    if (this.collection.length) { // use this.collection to refer to view's collection rather than external variables
      $("#dadasay_comments_plugin").show(); //This shouldn't be a global selection
    }
    var html = this.template(this.collection.toJSON());
    this.$el.append(html);
    //---^ use cached jQuery object rather than creating new one
  },
});
var EmptyCommentView = Backbone.View.extend({
  el: $("#empty_comments_list"),
  template: emptyCommentsTmpl,
  initialize: function() {
    this.render();
  },
  render: function() {
    var source = $('#empty_comments_list_tmpl').html(); // unused?
    var html = this.template(this.collection.toJSON());
    this.$el.html(html);
  },
});
var comments = new Comments();

comments.fetch({ // <--------- Do this manually once
  success: function(collection, response) {
    //----------------^ comments collection, all comments
    var commentView = new CommentView({
      collection: collection.wellFormedComments() // pass the resuting collection
    });
    var emptyCommentView = new EmptyCommentView({
      collection: collection.emptyComments() // pass the resuting collection
    });
  },
  error: function() {}
});

Upvotes: 2

Related Questions