Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember event for best discarding changes between same Route

I have an Ember list and an edit form. Each time the selected item of the list changes the edit form discards any changes and loads new model.

My problem is that there is no way to discard changes because the deactivate event does NOT fire.

For example going from url/favs/123/edit to url/favs/456/edit deactivate (and exit) event does NOT fire. So there is no way to properly discard any changes.

Here is the part of my code I am referring to:

App.Router.map(function() {
    this.resource('favs', { path: '/favs' }, function() {
        this.route('new');
        this.route('edit', { path: ':fav_id/edit' })
    });
});

[...]

App.FavsEditRoute = Ember.Route.extend({
    deactivate: function() {
        var model = this.get('currentModel');
        if(model && model.get('isDirty')) {
            model.get('transaction').rollback();
        }
    },

    model: function(params) {
        return App.Fav.find(params.fav_id);
    },
});
like image 304
Everydaypanos Avatar asked Mar 24 '13 08:03

Everydaypanos


3 Answers

I'd recommend using the willTransition route action. It currently appears to be advertised as the solution in the Ember Guide:

https://guides.emberjs.com/release/routing/preventing-and-retrying-transitions/

Aside from being in the public API, this approach has the advantage that you can prompt the user to confirm if they actually want to abandon the change, nullifying the transition if they say no.

For example:

App.FavsEditRoute = Ember.Route.extend({
  ...
  actions: {
    willTransition: function(transition) {
      controller = this.controllerFor('fav');
      if (controller.get('isDirty') &&
          !confirm("Are you sure you want to abandon progress?")) {
        transition.abort();
        return false;
      } else {
        controller.get("content").rollback();
        return true;
      }
    }
  }
});
like image 58
Greg Malcolm Avatar answered Nov 16 '22 10:11

Greg Malcolm


The deactivate hook is just executed when the route is left completely. Therefore i would suggest to overwrite the contextDidChange function of your Route. Here is an excerpt from the Ember Source:

Ember.Route = Ember.Object.extend({
    /**
    @private

    Called when the context is changed by router.js.
  */
  contextDidChange: function() {
    this.currentModel = this.context;
  }
});

I would suggest to do this:

App.FavsEditRoute = Ember.Route.extend({
    deactivate: function() {
        this.doRollback();
    },
    contextDidChange: function() {
        this.doRollback();
        this._super();
    },
    doRollback: function(){
        var model = this.get('currentModel');
        if(model && model.get('isDirty')) {
            model.get('transaction').rollback();
        }
    }
});
like image 22
mavilein Avatar answered Nov 16 '22 08:11

mavilein


In Ember 2.2 the correct code (in route) is:

actions: {
  saveScene: function (scene) {
    var _that = this;

    scene.save().then(function (response) {
      // on saveScene action, go to list route
      _that.transitionTo('scenes');
    });
  },

  willTransition: function (transition) {
    // on transition, if model has unsaved changes, revert them
    var model = this.controller.get('model');
    if (model && model.get('hasDirtyAttributes')) {
      model.rollbackAttributes();
    }
  }
}
like image 1
ioleo Avatar answered Nov 16 '22 08:11

ioleo