kernelpanic kernelpanic - 5 months ago 32
Javascript Question

Ember model rollback reset the view to previous state

I've got a simple form (that container a few textfields and checkboxes bound to the model) which is either visible or hidden using jQuery's slideToggle.

This form has two buttons: Save and Cancel.

Basically this form becomes visible when I need to make some changes to the model. When save button is clicked I save the model

this.get('model.content').save();


and hide the form.

Same goes for the cancel. I tried calling

this.get('model.content').rollback();


but it does not reverts the textfields, nor resets the checkboxes. I'd like them to be in previous 'unsaved' state when I open the form next time. How would I do that?

Answer

You should rollback the model:

this.get('model').rollback();

However, relying on the user to click "Cancel" might be a problem- What if they navigate using the back button? In my experience, it's better to bind your forms to a copy of the model object, so you can easily throw away changes. The "save" action will copy from the temporary object back to the route's model and save. Also, consider the implications of the server failing to save. You should probably have a then() on your call to save() so you can warn the user / recover / rollback / etc.

You can copy each attribute to a "buffer" attribute and in your form template do this:

{{#with buffer}}
    {{input value=fieldOne}}
    {{input value=fieldTwo}}
{{/with}}

To create an attributes computed property on your model object, add this:

attributes: function() {
    var model = this,
        result = [];
    Ember.keys(this.get('data')).forEach(function(key) {
        result.push(Ember.Object.create({
            model: model,
            key: key,
            valueBinding: 'model.' + key
        }));
    });
    return result;
}.property()

Then, to create a temporary buffer for your form to use, you can do this on your controller:

setupController: function(controller, model) {
    var buffer={};
    controller.set('model', model);
    model.get('attributes').forEach(function(item) {
        buffer[item.get('key')]= item.get('value');
    });
    controller.set('buffer', buffer);
    this._super(controller, model);
}

I personally use these as Mixins, so I can easily add them to all my model objects and edit controllers.