Skip to content

Instantly share code, notes, and snippets.

@josemarluedke
Created September 6, 2019 23:06
Show Gist options
  • Save josemarluedke/c4828e7149fd273f7e2f85b19a14f365 to your computer and use it in GitHub Desktop.
Save josemarluedke/c4828e7149fd273f7e2f85b19a14f365 to your computer and use it in GitHub Desktop.

<ChangesetForm>

The <ChangesetForm> component binds an instance of ember-changeset to a <form> tag. This binding is achieved through the component's {{yield}}, which is a hash of form controls that interface with the underlying changeset object.

Here's a list of yielded form components,

Hash Name Component
Text <InputText>
Textarea <InputTextArea>
Date <InputDate>
Select <InputSelect>
Checkbox <InputCheckbox>
CheckboxGroup <InputCheckboxGroup>
Radio <InputRadio>
RadioGroup <InputRadioGroup>

Form Data Model

The data model used to back the <ChangesetForm> is just a simple JS object, and nested property paths are supported:

// Just a simple JS object
export const myFormModel = {
  name: {
    first: 'Ron',
    last: 'Swanson'
  },
  email: 'ron@pawnee.in.gov',
  hometown: 'Pawnee, IN',
  preferences: ['Lagavulin', 'Steak', 'Bacon', 'No govt.']
};

Validation

Changeset validation is provided by ember-changeset-validations, and is optional for <ChangesetForm> components. This takes the form of another JS object literal mapping properties to validation funcitons:

// validations.js
import validateFormat from 'ember-changeset-validations/validators/format';
import validatePresence from 'ember-changeset-validations/validators/presence';

export const myValidations = {
  'name.first': validatePresence(true),
  'name.last': validatePresence(true),
  email: validateFormat({ type: 'email' }),
  hometown: validatePresence(true),
  preferences: validatePresence(true)
};

Creating an Instance

<ChangesetForm
  @validations={{myValidations}}
  @model={{myFormModel}} as |form changeset|>

  <form.Text
    @fieldName="name.first"
    @label="First Name"
  />
  <form.Text
    @fieldName="name.last"
    @label="Last Name"
  />
  <form.Text
    @fieldName="email"
    @label="Email"
  />
  <form.Text
    @fieldName="hometown"
    @label="Home Town"
  />
  <form.Select
    @fieldName="preferences"
    @label="Preferences"
  />

  <form.Submit>Submit</form.Submit>
  <form.Reset>Reset</form.Reset>
</ChangesetForm>

Providing Your Own Changeset

For added flexibility, you may provide your own Changeset object for the form. In this case you are responsible for also providing any validation you wish to apply to your Changeset. The following is a brief example of that method:

// validators are optional!
const validations = {
  myValue: validatePresence(true)
};
const validatorFn = lookupValidator(validations);

const myModel = {
  myValue: ''
};

const myChangeset = new Changeset(myModel, validatorFn, validations);

In the template, instead of providing your @model and @validations objects, you only need to provide the @changeset object,

<ChangesetForm @changeset={{myChangeset}} as |form changeset|>

  <form.Text
    @fieldName="myValue"
    @label="My Value"
  />

  <form.Submit>Submit</form.Submit>
  <form.Reset>Reset</form.Reset>
</ChangesetForm>

Complete Example

{{demo/changeset-form/example1}}

Text

This maps to the <InputText> component.

{{demo/changeset-form/example2}}

Textarea

This maps to the <InputTextArea> component.

{{demo/changeset-form/example3}}

Date

This maps to the <InputDate> component.

{{demo/changeset-form/example4}}

Select

This maps to the <InputSelect> component.

{{demo/changeset-form/example5}}

Checkbox and CheckboxGroup

These map to the <InputCheckbox> and <InputCheckboxGroup> components respectively.

{{demo/changeset-form/example6}}

Radio and RadioGroup

These map to the <InputRadio> and <InputRadioGroup> components respectively.

{{demo/changeset-form/example7}}

Submit and Reset

The <ChangesetForm> also yields submit and reset buttons that do just what you might think. The buttons are automatically disabled based on the form's validation state. When the form isPristine or isInvalid the submit button will be disabled. The reset button will be disabled only when the form isInvalid. This may be overridden if alternative disabled states are desired. When triggered, each button will call their respective handler action, onSubmit and onReset.

<ChangesetForm
  @onSubmit={{action this.mySubmit}}
  @onReset={{action this.myReset}}
  @model={{this.model}} as |Form changeset|>

  {{!-- form goes here --}}

  <Form.Submit disabled={{or changeset.isInvalid changeset.isPristine}}>Submit</Form.Submit>
  <Form.Reset>Reset</Form.Reset>
</ChangesetForm>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment