Series: Editing and Validating Forms with ember-changeset

Introduction to ember-changeset

Published on Aug 10, 2016

Two-way binding can cause weird interactions in complex apps, and this is especially true when editing forms.

The Ember community has tried many ways to solve this (lots of them really complicated), but ember-changeset promises to be an easy solution.


Links

Code

$ ember install ember-changeset
//templates/monsters/monster/edit.hbs
{{monster-form changeset=(changeset model) save=(action "save") rollback=(action "rollback")}}
//components/monster-form.js
import Ember from 'ember';

export default Ember.Component.extend({
  actions: {
    save(){
      this.attrs.save(this.get('changeset'));
    },
    rollback(){
      this.attrs.rollback(this.get('changeset'));
    }
  },
})
//monsters/monster/edit.js
import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    save(changeset){
      changeset.save().then(()=>{
        this.transitionToRoute('monsters.monster.show', this.get("model"));
      });
    },
    rollback(changeset){
      changeset.rollback();
    }
  }
});

Transcript

Back when Ember was first released, we thought two-way binding was awesome. You go to your edit form and you could start changing something and it’ll be reflected immediately everywhere else in your app. But that’s not great for certain real world applications. It’s relatively harmless here, but it could cause real problems elsewhere. Even here it’s causing a problem, you just don’t see it yet. See, you probably think this has been saved, but it hasn’t. So I reload and it’s back to Sparkachu instead of Spar. And you thought it was saved because it was reflected elsewhere. So for a while, people have been trying to solve this problem through various means, usually pretty complex. I remember something with proxies from a while back. But now Ember changeset has made it really easy.

First, let’s install Ember changeset. Today we’re going to be working with our monster-form. If you’ve already seen previous episodes, you may be a little bit familiar with what we’ve done. But basically we’re just having an input and it’s reliant on the model. So it’s directly in the model, then when we call save, the monster-form component sends it back up to the edit controller where it does the typical save and then transition. Now let’s see what if this will have to change in order to get Ember changeset working. So the first is to use the changeset helper when we’re feeding in the model. You can think of this as a deep copy. It’s doing more than that of course, but that’s how you can think of it in order to conceptualize it. Here we’re passing it in to the component, but not everyone has a component that they can pass in. If you’re doing it just in a form, then you may have to do something like with (changeset model) as |changeset|, and then you use changeset everywhere.

So back to what we have with us. So here we’re passing it in as model. And we can do that. We're going to go ahead and change this to changeset. That is not strictly necessary, but I feel that it will help us understand what we’re actually doing. So we’re feeding in the value of the changeset.

So this is part of the battle. Here we can edit and it’s not updating over here. But when we hit save, it doesn’t actually do anything. We need to get the changeset to reflect back on to the model when we call save. And this is pretty easy. So we’re going to go to our monster-form component JavaScript, and here when we’re calling save, we’re going to push it back up to the save and edit.js, we’re going to make sure to push up the changeset as one of the parameters. So then we’ll get the changeset from here, and then we can call save on the changeset instead of the model. And that will propagate it back to the model.

So now when we make this change we’ll see that it’s not reflected over here yet, but when we hit save, then it reflects everywhere. That’s pretty awesome. Now what if you want to be editing something but then you want to roll back the changes without reloading the page? So you don’t want to save it, but you don’t want to reload in order to get back what you had before. That’s where the rollback command comes in.

So we’ll start by creating the rollback action in our edit controller. It’ll of course take a changeset and it’ll call changeset. rollback, and that’s it. Then we will be sure to pass this down, it’s getting passed down to our component, and then in our component we’ll have an action there which will call the rollback and feed it our changeset. And then in the handlebars we will have another button, pretty similar to this one but saying Cancel instead of Save. Now when you go to edit, let’s say we mess up the level, we want to cancel it. Boom, done.

So those are the very basics of Ember changeset. It should be enough to get you going. But there is a lot more to this addon, and we’ll be exploring more of that in the coming weeks as well as the ember-changeset-validations addon that can go with it.

Editing and Validating Forms with ember-changeset

Subscribe to our mailing list