J B
J B

Reputation: 400

What's the right way of doing manual form data saving with Ember.js?

I'm trying to create a manually saved form with a moderate number of fields (let's say 20) in Ember.js (not using live bindings) and so far am confused about the correct way / best practice for doing so. I've found the following methods:

http://www.solitr.com/blog/2012/06/ember-input-field-with-save-button/

How to use one-way binding on emberjs?

https://stackoverflow.com/a/16473186/1248965

All of the above methods seem hacky to a degree; they either extend the text field or use a per-field observer, requiring you to list out each one. Is there some other way? Something like the 'unbound' helper, but allowing the auto-model updating magic / validation (via ember-data) on some action (like an 'unbound-until' or 'conditional-bind' or something)? I've gone through all the docs, SO, the github issues, the Ember forum, and the links above, and still feel like I must have missed something.

Basically, a way to say "do everything you would do with a normally bound form/fields, but only on a certain action, rather than in real time."

Upvotes: 1

Views: 720

Answers (2)

chopper
chopper

Reputation: 6709

What you want is a "Buffered Proxy", where you temporarily store all changes to the model (you can catch those using setUnkownProperty) in a proxy object. Once you are happy with the changes, you'd copy all of the proxy data over into the actual object ("flush the data").

App.Heisenberg = {
  firstName: 'Walter',
  lastName: 'White',  
};

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return App.Heisenberg;
  },
  setupController: function(controller, model) {
    controller.set('content', model);
  }
});

App.IndexController = Ember.ObjectController.extend({
  proxy: {},
  setUnknownProperty: function(key, value) {
    console.log("Set the unknown property: " + key + " to: " + value); 
    this.proxy[key] = value;
    console.log(this.proxy);
  },
  flush: function() {
    for(var key in this.proxy) 
      this.set('model.'+key, this.proxy[key]);
  }
});

Template:

<script type="text/x-handlebars" data-template-name="index">
    Saved Name: {{firstName}} {{lastName}}<br />
    <br />

    <form {{ action "saveEdit" on="submit" }}>
        First Name: {{input type="text" valueBinding="firstName"}}<br />
        Last Name: {{input type="text" valueBinding="lastName"}}<br />
        <br />
        <button {{ action "flush" }}>Flush</button>
    </form>
</script>

This would make for a nice controller Mixin.

See this jsBin for a live example.

Upvotes: 3

J B
J B

Reputation: 400

I found a workaround, but I'm not 100% happy with it:

In my "editing" template, I have:

<form {{ action "saveEdit" on="submit" }}>
  Title: {{input type="text" value=title}}
  <input type="submit" value="Save">
  <button {{ action "cancelEdit" }}>Cancel</button>
</form>

Then in my associated controller, I do:

cancelEdit: function() {

  var entry = this.get('model');

  this.set('isEditing', false);
  entry.rollback();

},

saveEdit: function() {

  var entry = this.get('model');

  this.set('isEditing', false);
  entry.save().then(

    function() {

    console.log('Saved!');

   }

I simply hide the fields where the "live updating" would show. I still would like to find a way to temporarily turn off the binding until I trigger my "saveEdit" action, since this still seems inelegant.

Upvotes: 0

Related Questions