Multiple modals being added in Backbone

2019-04-09 11:56发布

问题:

I am opening the modal from the DetailsView

as follows:

    var $ = jQuery = require('jquery'),
  Backbone = require('backbone'),
  Handlebars = require('handlebars'),
  _ = require('underscore'),
  skuDetailsTemplate = require("../../templates/sku/SkuDetails.html"),
  skuDetailsModel = require('../../models/sku/SkuDetailsModel'),
  updateSkuModel = require('../../models/sku/UpdateSkuModel'),
  skuUpdateView = require('../../views/sku/UpdateSkuView'),
  inventoryForFacilityModel = require('../../models/inventory/InventoryForFacilityModel'),
  skuListingModel = require('../../models/sku/listing/SkuListingModel');
var SkuDetailsView = Backbone.View.extend({
  el: ".sku-details-container",
  tagName: "div",
  initialize: function (options) {
    var self = this;
    this.skuDetailsModel = new skuDetailsModel();
    this.inventoryForFacilityModel = new inventoryForFacilityModel();
    this.skuListingModel = new skuListingModel();
    this.listenTo(self.skuDetailsModel, 'add', self.render);
    this.listenTo(self.skuDetailsModel, 'change', self.render);
    this.listenTo(self.inventoryForFacilityModel, 'add', self.render);
    this.listenTo(self.inventoryForFacilityModel, 'change', self.render);

    this.listenTo(self.skuListingModel, 'add', self.render);
    this.listenTo(self.skuListingModel, 'change', self.render);


    this.sku_id = options.sku_id;
    this.skuDetailsModel.set("id", this.sku_id);
    this.skuDetailsModel.fetch({});
    this.inventoryForFacilityModel.set("id", this.sku_id);
    this.inventoryForFacilityModel.fetch({})
    this.skuListingModel.set("id", this.sku_id);
    this.skuListingModel.fetch({})
  },
  events: {
    "click .openModal": "openUpdateModal",
    "click .btnEditSku": "openUpdateModal"
  },
  openUpdateModal: function (ev) {
    var data = { model: this.skuDetailsModel };
    var modalView = new skuUpdateView(data);
    modalView.show();
  },
  render: function () {
    var self = this;
    this.$el.html(skuDetailsTemplate({
      skuDetails: self.skuDetailsModel.toJSON(),
      inventoryByFacility: self.inventoryForFacilityModel.toJSON(),
      skuListing: self.skuListingModel.toJSON()
    }));
  }

});

module.exports = SkuDetailsView;

ModalView

    var UpdateSkuView = Backbone.View.extend({
  className: "modal fade",
  attributes: {
    tabindex: "-1",
    role: "dialog",
  },

  initialize: function (options) {
    var self = this;
    this.model = options.model;
    this.updateSkuModel = new updateSkuModel();
    this.template = skuUpdateTemplate;

  },
  events: {
    "click .save": "saveHandler",
    "click .closeModal": "close",
    "change .clsEdit": "recordModelChange"
  },
  recordModelChange: function (e) {
    var field = e.target.id;
    var value = e.target.value;
    var res = this.model.toJSON();
    var obj = {};

    // if (field === "length" || field === "width" || field === "height" || field === "weight" || field === "mrp" || field === "recommended_selling_price") {
    //   value = parseFloat(value);
    // }
    obj[field] = value;
    obj["id"] = res.records[0].id;
    //var res = this.model.toJSON();

    this.updateSkuModel.set(obj, { validate: true });
  },
  saveHandler: function (e) {
    //Save logic
    var self = this;
    e.preventDefault();
    var options = {
      validate: true,
      success: function (model, response) {
        self.showSuccessMessage("SKU with id " + response.records[0].id + " updated successfully");
        setTimeout(function () {
          self.close();
        }, 1500);

      }
    };
    this.updateSkuModel.save({}, options);
  },
  render: function () {
    var self = this;
    this.$el.html(this.template({
      skuDetails: self.model.toJSON()
    })).modal()

    return this;
  },

  show: function () {
    $(document.body).append(this.render().el);
  },

  close: function () {
    this.$el.remove(".modal fade");
    this.$el.modal("hide");
    this.$el.empty();
    this.undelegateEvents();

  }
});

module.exports = UpdateSkuView;

If i open one modal and then close it and then open another instance of the modal it comes over the previous one.

Please help.

My problem:

回答1:

Vini, your modal view never calls remove http://backbonejs.org/#View-remove either from parent view or from itself.

Modals are pain to keep track of. Exactly for that reason I used Rendering bootstrap modal using backbone

Despite all that! Look at the events you have. You re-render your parent view with out cleaning up the bindings or removing subsequent views.

this.listenTo(self.skuDetailsModel, 'add', self.render);
this.listenTo(self.skuDetailsModel, 'change', self.render);
this.listenTo(self.inventoryForFacilityModel, 'add', self.render);
this.listenTo(self.inventoryForFacilityModel, 'change', self.render);

this.listenTo(self.skuListingModel, 'add', self.render);
this.listenTo(self.skuListingModel, 'change', self.render);

I sense that this.listenTo(self.skuListingModel, 'change', self.render); binds 'click event' every time you re-render / update your "sku" Remove it and see it works.



回答2:

I use a modalManager class that extend the Backbone.View for use to show modal views. I think your problem is on the close function, you need to hide the modal and then remove it like my hide funtion.

modalManager = Backbone.View.extend({
    className: "modal",
    template: 'modals/modal.html',
    title: '',
    content: '',
    showButton: true,
    events: {
        'click .close': 'hide',
        'click .btn': 'hide'
    },
    initialize: function (options) {
        _.extend(this, _.pick(options, "title"));
        _.extend(this, _.pick(options, "content"));
        this.render();
    },
    show: function () {
        this.$el.modal('show');
    },
    hide: function () {
        this.$el.modal('hide');
        this.remove();
    },
    render: function () {
        this.$el.html(this.template({title: this.title, content: this.content, showButton: this.showButton}));
    },
    setTitle: function(title) {
        this.title=title;
        this.render();
    },
    setContent: function(content) {
        this.content=content;
        this.render();
    },
    setShowButton: function(showbutton) {
        this.showButton=showbutton;
        this.render();
    }
})


回答3:

Your close-method must be altered:

close: function () {
    this.undelegateEvents();
    this.$el.remove();
    this.remove();
}

Since you are always creating a new modal the old one is unnecessary (garbage)



回答4:

You create a modal instance here:

var modalView = new skuUpdateView(data);

and here you open it.

modalView.show();

Modal view can not be garbage collected because it is referenced form another view.

You have to close the modal from the view where you reference it

modalView.close();


回答5:

Solved my issue:

It was because i had multiple instances of my detailsview that the modal was being rendered so many times.

What i did to solve the issue:

Gave a unique $el to my DetailsView