Grapho
Grapho

Reputation: 1654

EmberJS: bootstrap modal refuses to re-open due to record not being correctly deleted?

The Goal:

The thing that I am really trying to accomplish here is gain an understanding how to work with model records cleanly. In this particular case, these records are kind of "one-offs". If the modal is closed without saving, then they are meant to be cleared from memory... and once a record is saved to the server there is also no need to keep the re record stored client side.

Description:

I created a button action that transitions into a "payment" route, which renders inside a Bootstrap modal.

This route creates a "payment" record and also pulls a list of available "debts" the payment can be applied to.

App.PaymentRoute = Ember.Route.extend({
  model: function() {
    console.log('( Router: Model Hook )--------------------)');
    return this.store.createRecord('payment');
  },
  afterModel: function() {
    console.log('( Router: AfterModel Hook )--------------------)');
    var route = this;
    return Ember.RSVP.hash({
      debt_list: this.store.find('debt', { account_id: 36, page_size: 100, page_number: 1 })
    }).then(function(hash) {
      route.setProperties({
        account_id: 36,
        debt_list: hash.debt_list
      });
    });
  },
  setupController: function(controller, model) {
    console.log('( Router: SetupController Hook )--------------------)');
    this._super(controller, model);
    controller.setProperties({
      account_id: this.get('account_id'),
      debt_list: this.get('debt_list')
    });
  },
});

Closing the modal should delete the current record and transition back to index...

actions: {
    removeModal: function() {
      this.currentModel.deleteRecord();
      this.transitionTo('index');
      return true;
    }
  }

when payment button is clicked a second time, it "should" create a new payment record... but instead an error occurs, because the previous record has not been correctly cleared?

I successfully recreated the issue in this JSBin

Am i not creating and deleting records correctly?

Side Note:

I have set console.log() on all my route and controller methods... I noticed that setupController does not fire on the second open attempt.... also my controller cp's and observers are triggering multiple times during the initialization proces... i dont know if that is contributing to the problem or not?

Upvotes: 0

Views: 388

Answers (2)

Andrew Hacking
Andrew Hacking

Reputation: 6366

I don't think you actually want to 'delete' the record. What you want to do is rollback any changes to it and then unload it. I would do this in your willTransition hook on the route so no-matter how you leave the route, the model will be unloaded.

Code:

willTransition: function(transition) {
  var model = this.currentModel;
  var debt_list = get(this, 'debt_list');
  var store = this.store;

  // dispose of models after views have been finalised 
  Ember.run.once(function() {
    if (model) {
      model.rollback();
      store.unloadRecord(model);
    }
    if (debt_list) {
      debt_list.forEach(function(debt) {
        debt.rollback();
        store.unloadRecord(debt);
      });
    }
  }
}

UPDATE: It is important to unload records from the ember run-loop to give any views bound to those records a chance to be torn down before ripping models out from under them. That is why the model disposing is performed within Ember.run.once().

Another observation is that you should be able kick off the debt_list request in your model hook using RSVP.hash. So putting it all together your route should look something like the following:

var get = Ember.get, set = Ember.set;

App.PaymentRoute = Ember.Route.extend({
  model: function(params, transition, queryParams) {
    return Ember.RSVP.hash({
      content: this.store.createRecord('payment'),
      debt_list: this.store.find('debt', { account_id: 36, page_size: 100, page_number: 1 })
    });
  },

  setupController: function(controller, hash) {
    if (controller && hash) {
      controller.setProperties(hash);
      set(controller, 'account_id', 36);
    }
  },

  actions: {

    willTransition: function(transition) {
      var hash = this.currentModel;
      var store = this.store;

      // tell controller to reset/cleanup - you should set any
      // model related properties ie 'content'/'model' and 'debt_list'
      // to null/default values.
      this.controller.reset();

      if (hash) 
        // dispose of models after views have been finalised 
        Ember.run.once(function() {
          hash.content.rollback();
          store.unloadRecord(hash.content);
          hash.debt_list.forEach(function(debt) {
            debt.rollback();
            store.unloadRecord(debt);
          });
        });
      }
    }
  }
});

I have updated your JSBin here so its working perfectly, models are correctly removed from the store.

Upvotes: 1

Asgaroth
Asgaroth

Reputation: 4334

The problem seems to be the this.store.find('debt', { account_id: 36, page_size: 100, page_number: 1 })

Because ember data will load the items into the store once the query finishes, and the controller is bound to that array, when it changes all observers are fired.

so setDebtPayments is getting called, (before setupController), trying to do model.set('payment_debts', paymentDebts); which at that point is already destroyed.

I managed to fix this (suboptimaly) by creating a new payment record when removeModal is called.

Another option, is to check if there is a model decorated by the controller, before doing anything with it: http://jsbin.com/ziket/8

Upvotes: 2

Related Questions