ember-fit-form
v3.0.1
Published
A flexible component for form state management with data model adapters.
Downloads
36
Readme
ember-fit-form
A form component which wraps a native <form>
element and provides form state management abstractions.
ember-fit-form
provides flexible state management for
forms. We aim to support many data and validation libraries
for use within your application's forms. We're also built on
ember-concurrency, so you can easily
support promise-aware hooks to manage your applications form state.
Please note that
ember-fit-form
does not provide form control components. It is simply an html form element with abstractions for state management.
Compatibility
- Ember.js v3.16 or above
- Ember CLI v2.13 or above
- Node.js v10 or above
Installation
ember install ember-fit-form
Usage
Example
{{!-- my-form.hbs --}}
<FitForm @models={{model}} @oncancel={{action rollback}} @onsubmit={{action save}} as |form|>
<input {{on "input" (action (mut model.name) value="target.value")}} />
{{!-- other form content --}}
<button {{on "click" form.cancel}} disabled={{form.isCancelling}}>
{{if form.isCancelling "Cancelling..." "Cancel"}}
</button>
<button {{on "click" form.submit}} disabled={{form.isUnsubmittable}}>
{{if form.isSubmitting "Saving..." "Save"}}
</button>
</FitForm>
// my-form.js
rollback() {
return model.rollbackAttributes();
},
save() {
return model.save();
}
Form Adapters
This addon supports various data and validation libraries for use within your application's forms. You can even write your own custom adapters.
Built-in Adapters
ember-changeset
(default)ember-changeset model adapter
Supported Validation Libraries:
ember-model
ember-data model adapter
Supported Validation Libraries:
Each form adapter defines its own form action hooks, such as onsubmit and oncancel. The default behavior of these actions can be overwritten by passing onsubmit
and oncancel
into the component invocation. Please see source code for specifics on an adapter's default action hooks.
ex: onsubmit
not passed to component
When onsubmit
is not explicitly passed into the component, the adapter's default onsubmit
action will be called on form submission.
<FitForm @models={{models}}>
<!-- form.submit calls adapter's default `onsubmit` action -->
<button {{on "click" form.submit}}>Save</button>
</FitForm>
ex: onsubmit
passed to component
When onsubmit
is explicitly passed into the component, it will call this action in favor of the adapter's default onsubmit
action on form submission.
<FitForm @models={{models}} @onsubmit={{action "submitMe"}}>
<!-- form.submit calls "submitMe" action -->
<button {{action form.submit}}>Save</button>
</FitForm>
Configuration
By default, ember-fit-form
uses the ember-changeset
adapter which expects Changeset models. To setup your default Model, you should configure the addon through config/environment
:
module.exports = function(environment) {
var ENV = {
emberFitForm: {
adapter: 'ember-changeset' // default
}
}
}
In the case that your forms use various Models throughout the application, you can overwrite the adapter
at the component level.
<FitForm @models={{model}} @adapter="ember-model">
{{!-- form content --}}
</FitForm>
API
Fit-Form Actions
submit
Submits the form.
Submitting a form calls the form's validate
method and
then calls the form's onsubmit
hook if validation succeeds.
form.submit();
<button {{action form.submit}}>Submit</button>
{{!-- or --}}
<button onclick={{action form.submit}}>Submit</button>
The
onsubmit
hook will never be called ifonvalidate
hooks is rejected.
cancel
Cancels the form.
Cancelling a form calls the form's oncancel
hook.
form.cancel();
<button {{action form.cancel}}>Cancel</button>
{{!-- or --}}
<button onclick={{action form.cancel}}>Cancel</button>
validate
Validates the form. Validating a form calls the validate action for each of the form's models.
form.validate();
<button {{action form.validate}}>Check Validity</button>
{{!-- or --}}
<button onclick={{action form.validate}}>Check Validity</button>
Fit-Form Component Action Hooks
Fit-Form adapters each contain action hooks. Some hooks call default functions, to reduce overall boilerplate code. For example, the ember-changeset
adapter's onsubmit
hook calls changeset.save()
on each changeset by default. Declaring an onsubmit
action on the component will override this behavior.
See default component action hook behavior:
The form
object is always curried in as the last argument for all component action hooks.
onsubmit
The onsubmit
hook action is a promise-aware action which is called on form submission.
Form submission is triggered when calling form.submit()
.
<FitForm @models={{this.model}} @onsubmit={{this.save}} as |form|}}>
<button {{form.submit}}>Save</button>
</FitForm>
save(/* form */) {
return this.model.save();
}
The
onsubmit
hook will not be called on form submission ifonvalidate
hooks is rejected.
onsuccess
The onsuccess
hook is a promise-aware action which is called when the onsubmit
hook is fulfilled.
<FitForm @models={{this.model}} @onsuccess={{this.success}} as |form|}}>
<button {{form.submit}}>Save</button>
</FitForm>
success(/* result, form */) {
// Do something
}
onerror
The onerror
hook is a promise-aware action which is called when the onsubmit
hook is rejected.
<FitForm @models={{this.model}} @onerror={{this.error}} as |form|}}>
<button {{form.submit}}>Save</button>
</FitForm>
error(/* error, form */) {
// Do something
}
oncancel
The oncancel
hook is a promise-aware action which is called on form cancellation.
Form cancellation is triggered when calling form.cancel()
.
<FitForm @models={{this.model}} @oncancel={{this.rollback}} as |form|}}>
<button {{form.cancel}}>Cancel</button>
</FitForm>
rollback(/* form */) {
return this.model.rollback();
}
onvalidate
The onvalidate
hook is a promise-aware action which is called on form validation.
Form validation is triggered when calling form.validate()
or form.submit()
On form submission, if onvalidate
returns a rejected Promise
or
false
, the submission will reject, and onsubmit
will not be called.
<FitForm @models={{this.model}} @onvalidate={{this.validate}} as |form|}}>
<button {{form.validate}}>Check Fields</button>
<button {{form.submit}}>Save</button>
</FitForm>
validate(/* form */) {
return this.model.validate();
}
oninvalid
The oninvalid
hook is a promise-aware action which is called when the onvalidate
hook is rejected or returns false
.
<FitForm @models={{this.model}} @oninvalid={{this.invalid}} as |form|}}>
<button {{form.submit}}>Save</button>
</FitForm>
invalid(/* error, form */) {
// Do something
}
Fit-Form Component Event Handler Hooks
The form
object is always curried in as the last argument for all
component event handler hooks.
onkeydown
When onkeydown
is passed into fit-form
component, it registers the
keyDown
event on the html form element. The onkeydown
hook is called when
the keyDown
event is triggered.
<FitForm @models={{this.model}} @onkeydown={{this.handlekey}} as |form|}}>
{{!-- form content --}}
</FitForm>
handlekey(event, form) {
if (event.key === "Enter" && event.shiftKey) {
// Shift + Enter
form.submit();
} else if (event.key === "Escape") {
form.cancel();
}
}
return true;
to bubble the event. This is useful if you still want the form to handle the submit event.
onkeyup
When onkeyup
is passed into fit-form
component, it registers the
keyUp
event on the html form element. The onkeyup
hook is called when
the keyUp
event is triggered.
See onkeydown
example for usage.
onkeypress
When onkeypress
is passed into fit-form
component, it registers the
keyPress
event on the html form element. The onkeypress
hook is called when
the keyPress
event is triggered.
See onkeydown
example for usage.
Fit-Form Attributes
isUnsubmittable
Returns a Boolean value of the form's (un)submittability.
form.isUnsubmittable; // true
<button {{action form.submit}} disabled={{form.isUnsubmittable}}>Submit</button>
You can still call
submit
ifisUnsubmittable
is true.
isSubmittable
Returns a Boolean value of the form's submittability.
form.isSubmittable; // true
{{#if form.isSubmittable}}
<span class=fa fa-check'></span>
{{/if}}
isValid
Returns a Boolean value of the form's validity. A valid form is one where all of the form's models are valid.
form.isValid; // true
{{#if form.isValid}}
<span class=fa fa-check'></span>
{{/if}}
isInvalid
Returns a Boolean value of the form's (in)validity. A invalid form is one where the some of the form's models are invalid.
form.isInvalid; // true
{{#if form.isInvalid}}
<span class=fa fa-times></span>
{{/if}}
isDirty
Returns a Boolean value of the form's state. A dirty form is one with changes.
form.isDirty; // true
isPristine
Returns a Boolean value of the form's state. A pristine form is one with no changes.
form.isPristine; // true
isCancelling
Returns a Boolean value of the form's cancelling state. A cancelling
form is one where the oncancel
hook is pending. This attribute is
commonly coupled with the cancel
action.
form.isCancelling; // true
<button {{action form.cancel}} disabled={{form.isCancelling}}>Cancel</button>
isSubmitting
Returns a Boolean value of the form's submitting state. A submitting
form is one where the onsubmit
, onsuccess
, or onerror
hooks are
pending. This attribute is commonly coupled with the submit
action.
form.isSubmitting; // true
<button {{action form.submit}} disabled={{form.isSubmitting}}>Submit</button>
isValidating
Returns a Boolean value of the form's validating state. A validating form is one where the form's model(s) are validating upon form submission.
form.isValidating; // true
{{#if form.isValidating}}
<span class=fa fa-spinner></span>
{{/if}}
didCancel
Returns a Boolean value of the form's cancelled state. A cancelled form is one where the oncancel
hooks is settled.
form.didCancel; // true
{{#if form.didCancel}}
<span class='error'>{{model.errors}}</span>
{{/if}}
didSubmit
Returns a Boolean value of the form's submitted state. A submitted form is one where the onsubmit
hooks is settled.
form.didSubmit; // true
{{#if form.didSubmit}}
<span class='error'>{{model.errors}}</span>
{{/if}}
didValidate
Returns a Boolean value of the form's validated state. A validated form is one where the form's model(s) were validated upon form submission.
form.didValidate; // true
{{#if form.didValidate}}
<span class='error'>{{model.errors}}</span>
{{/if}}
Custom Adapters
Generate a form adapter
$ ember generate form-adapter foo-bar
This creates app/form-adapters/foo-bar.js
and a unit test at tests/unit/form-adapters/foo-bar-test.js
. By default, the form-adapter extends the BaseAdapter
.
Example - extend ember-changeset
form-adapter
In this example, we'll extend the ember-changeset
form-adapter. We will overwrite the default oncancel
action to never call rollbackAttributes()
on the Changesets.
Generate
form-adapter
ember g form-adapter ember-changeset/no-rollbacks
Extend the
ember-changeset
form-adapter
// app/form-adapters/ember-changeset/no-rollbacks; import EmberChangesetAdapter from 'ember-fit-form/form-adapters/ember-changeset'; export default class EmberChangesetNoRollbacksAdapter extends EmberChangesetAdapter { oncancel() { /* noop - ie. no rollbackAttributes */ } }
Define adapter on component or configuration
{{!-- my-template.hbs --}} <FitForm @models={{changeset}} @adapter="ember-changeset/no-rollbacks"> {{!-- other form content --}} </FitForm>
License
This project is licensed under the MIT License.