makepanic / ember-validated-form

Easily create forms with client side validations.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ember-validated-form

npm version Ember Observer Score Build Status Dependency status

Easily create forms with client side validations.

Demo

gif

Want to try it yourself? See the live demo.

This ember-cli addon is based on the following excellent addons

and provides a handy out-of-the-box setup for user-friendly client-side validations, featuring

  • Hiding of validation errors until field has been interacted with (or submit button was pressed)
  • Preventing submit action until form is valid
  • Live-updating validation errors
  • Bootstrap integration
  • Loading class on submit button while async task is executed
  • Loading contextual template parameter set while async submit task is executed

Why *YAEFA?

*Yet another ember form addon

There are many existing ember addons with this style of API, the most prominent probably being ember-form-for. With this addon, we want to:

  • focus on forms that require client-side validations
  • provide good user experience out of the box

For more information, see this blog post.

Usage

First, install the addon:

ember install ember-validated-form

After, you'll need to set up

  • a template containing your form elements
  • a validations file (see ember-changeset-validations)
  • a controller, route and/or component that provides your template with the validations and your model

You'll find a basic example in this twiddle or in the following code blocks:

{{#validated-form
  model        = (changeset model UserValidations)
  on-submit    = (action "submit")
  as |f|}}

  {{f.input label="First name" name="firstName"}}
  {{f.input label="Last name" name="lastName"}}

  {{f.input type="textarea" label="About me" name="aboutMe"}}

  {{f.input
    type     = "select"
    label    = "Country"
    name     = "country"
    options  = countries
    value    = model.country
    }}

  {{f.input type="radioGroup" label="Gender" name="gender" options=genders}}

  {{#f.input label="Favorite Color" name="color" as |fi|}}
    {{favorite-colors-component colors=colors onupdate=fi.update onhover=fi.setDirty}}
  {{/f.input}}

  {{f.input type="checkbox" label="I agree with the terms and conditions" name="terms"}}

  {{f.submit label="Save"}}
{{/validated-form}}
// controller
import Controller from '@ember/controller';
import UserValidations from 'dummy/validations/user';

export default Controller.extend({
  UserValidations,

  actions: {
    submit(model) {
      return model.save();
    }
  }
});
// route
import Route from '@ember/routing/route';

export default Route.extend({
  model() {
    return { firstName: 'Max' } // or an ember object, an ember-data model, ...
  }
});

UserValidations is a changeset:

// validations/user.js
import {
  validatePresence,
  validateLength,
  validateInclusion
} from 'ember-changeset-validations/validators';

export default {
  firstName: [validatePresence(true), validateLength({ min: 3, max: 40 })],
  lastName: [validatePresence(true), validateLength({ min: 3, max: 40 })],
  aboutMe: [validateLength({ allowBlank: true, max: 200 })],
  country: [validatePresence(true)],
  gender: [validatePresence(true)],
  terms: [
    validateInclusion({
      list: [true],
      message: 'Please accept the terms and conditions!'
    })
  ],
  color: [validatePresence(true)]
};

Options

{{validated-form}} takes the following options:

Name Type Description
model Object ember-changeset containing the model that backs the form
validateBeforeSubmit Boolean Specifies whether to run validations on inputs before the form has been submitted. Defaults to true.
on-submit Action Action, that is triggered on form submit. The changeset is passed as a parameter. If the action returns a promise, then any rendered submit buttons will have a customizable CSS class added and the yielded loading template parameter will be set.

When the submission of your form can take a little longer and your users are of the impatient kind, it is often necessary to disable the submit button to prevent the form from being submitted multiple times. This can be done by using the loading template parameter and works very well with ember-concurrency tasks.

// controller
import Controller from '@ember/controller';
import { task } from 'ember-concurrency';

export default Controller.extend({
  submit: task(function * (model) {
    yield model.save();
    // ... more code to show success messages etc.
  })
});
{{#validated-form
  ...
  on-submit = submit
  as |f|}}
  ...
  {{f.submit label="Save" disabled=f.loading}}
{{/validated-form}}

For a minimal demo see this twiddle.

Input fields

{{validated-form}} yields an object, that contains the contextual component input. All input fields share some common properties:

Name Type Description
label String The label of the form field.
name String This is is the name of the model property this input is bound to.
hint String Additional explanatory text displayed below the input field.
type String Type of the form field (see supported field types below). Default: text.
disabled Boolean Specifies if the input field is disabled.
required Boolean If true, a "*" is appended to the field's label indicating that it is required.
value String Initial value of the form field. Default: model property defined by name.
validateBeforeSubmit Boolean Specifies whether to run validations on this input before the form has been submitted. Defaults to the value set on the form.
on-update Action Per default, the input elements are two-way-bound. If you want to implement custom update behavior, pass an action as on-update. The function receives two arguments: update(value, changeset).

The supported field types are essentially given by ember-one-way-controls. This addon does not much more than translating {{f.input type="select"}} to {{one-way-select}}.

However, some field types require extra parameters. The supported field types are listed below.

Text input

If no field type is specified, a simple <input type="text"> is rendered. Other HTML5 text-like inputs like email, number, search require specifying their type. The element also supports the following options:

  • placeholder
  • autofocus
{{f.input label="First name" name="firstName"}}
{{f.input type="email" label="Email" name="email"}}

Textarea

The textarea element also supports the following options:

  • rows and cols
  • autofocus
  • placeholder
{{f.input type="textarea" label="Description" name="description"}}

Select

The select element supports more options (see {{one-way-select}}):

  • value
  • options
  • optionLabelPath
  • optionValuePath
  • optionTargetPath
  • includeBlank
  • promptIsSelectable

The prompt property is currently not supported (see this related issue).

{{f.input
  type    = "select"
  label   = "Country"
  name    = "country"
  options = countries
  prompt  = "Please choose..."
  promptIsSelectable = true
  }}

Checkbox

This component renders a {{one-way-checkbox}}.

{{f.input type="checkbox" label="I agree with the terms and conditions" name="terms"}}

Radio button group

This component renders a list of {{one-way-radio}} components.

{{f.input type="radioGroup" label="Shapes" name="shapes" options=shapes}}
// in your controller
shapes: [{
  key: 't',
  label: 'Triangle'
}, {
  key: 's',
  label: 'Square'
}, {
  key: 'c',
  label: 'Circle'
}],

If you want to customize the markup for each radio-button's label, you can invoke this component using block form. This is helpful if you need to localize your labels using something like ember-i18n.

{{#f.input type="radioGroup" label=(t 'some.scope.shapes') name="shapes" options=shapes}}
  {{t option.label}}
{{/f.input}}
// in your controller
shapes: [{
  key: 't',
  label: 'some.scope.triangle'
}, {
  key: 's',
  label: 'some.scope.square'
}, {
  key: 'c',
  label: 'some.scope.circle'
}],
// in your locale file
export default {
  'some': {
    'scope': {
      'shapes': 'les formes',
      'triangle': 'un triangle',
      'square': 'un carré',
      'circle': 'un cercle'
    }
  }
};

Custom input elements

If the input element you need is not explicitly supported, you can easily integrate it with this addon by using f.input in block form:

{{!-- ember-power-select --}}
{{#f.input name='example' as |fi|}}
  {{#power-select options=options selected=fi.value onchange=fi.update onblur=fi.setDirty as |name|}}
    {{name}}
  {{/power-select}}
{{/f.input}}

{{!-- homemade component --}}
{{#f.input label="Favorite Color" name="color" as |fi|}}
  {{favorite-colors-component selected=fi.value colors=colors onupdate=fi.update onhover=fi.setDirty}}
{{/f.input}}

There are three integration points for custom components:

  • initialize the state of your component with fi.value
  • update the model's value with fi.update
  • mark your component as dirty with fi.setDirty

Buttons

{{validated-form}} also yields a submit button component that can be accessed with {{f.submit}}. You can also use it as a block style component {{#f.submit}}Test{{/f.submit}} if you don't want to pass the label as a property. It takes the following properties:

Name Type Description
label String The label of the form button.
type String Type of the button. Default: button.
disabled Boolean Specifies if the button is disabled.
loading Boolean Specifies if the button is loading. Default: Automatic integration of ember-concurrency

Config

Currently, the configuration supports

  • label.submit: default label for the submit button. If you're using ember-i18n, you can also specify a translation key.
  • css: Custom CSS Classes
    • form
    • group (div wrapping every form element including label and validation messages)
    • control (applied to form elements like input, select, ...)
    • label
    • radio (div wrapping radio button groups)
    • checkbox (div wrapping checkboxes)
    • help (span containing validation messages)
    • hint (p containing form input hints)
    • button
    • submit (Special styling for the submit button, overrides button)
    • error (Name of the class added to group when the element is invalid)
    • valid (Name of the class added to group when the element is valid)
    • loading (Name of the class added to button when the element is loading)

See an example integration of Bootstrap and Semantic UI below.

Bootstrap

// environment.js

var ENV = {
  // ...
  'ember-validated-form': {
    label: {
      submit: 'Go for it!',
    },
    css: {
      // bootstrap classes
      group: 'form-group',
      control: 'form-control',
      label: 'form-label',
      checkbox: 'checkbox',
      radio: 'radio',
      help: 'help-block',
      hint: 'help-block',
      button: 'btn btn-default',
      submit: 'btn btn-primary'
    }
  },
  // ...
}

Semantic UI

// environment.js

var ENV = {
  // ...
  'ember-validated-form': {
    label: {
      submit: 'Go for it!',
    },
    css: {
      // semantic ui classes
      form: 'ui form',
      radio: 'ui radio',
      help: 'ui red',
      checkbox: 'ui checkbox',
      button: 'ui button',
      group: 'field',
      error: 'error'
    }
  },
  // ...
}

Contributing

Bug reports, suggestions and pull requests are always welcome!

Installation

  • git clone https://github.com/adfinis-sygroup/ember-validated-form
  • cd ember-validated-form
  • yarn install

Running

Running Tests

  • yarn test (Runs ember try:each to test your addon against multiple Ember versions)
  • ember test
  • ember test --server

Building

  • ember build

For more information on using ember-cli, visit https://ember-cli.com/.

About

Easily create forms with client side validations.

License:MIT License


Languages

Language:JavaScript 80.5%Language:HTML 19.1%Language:CSS 0.3%