Form object pattern in Ember apps (similar to ActiveModel Form Objects in Ruby on Rails)
- Declarative validations (depends on ember-validations under the hood)
- Handles client & server side validation errors
- Properties proxied to / synced from model
- Virtual, async & readonly properties
- Well defined form save (submit) process with appropriate hooks
- Manage form "dirty", "loaded", "submitting" and "valid" state
- Prevent form loss with confirmation when leaving dirty form
- Add/remove properties in runtime (useful for dynamic forms)
- Detect model property conflicts while form is being edited (in "dirty" state)
This project is currently in alpha phase. Public API of the library is still under active development.
ember install ember-form-object
// app/forms/todo.js
import Ember from 'ember';
import ModelFormObject from 'ember-form-object/forms/model-form';
export default ModelFormObject.extend({
properties: {
'title': { validate: { presence: true } },
'completed': {},
'assignee': {},
'subscribers': { async: true },
'description': { virtual: true, validate: { presence: true } },
'people': { virtual: true, async: true }
},
setDescription() {
return this.get('model.description');
},
syncDescription() {
const parsedDescription = Ember.String.capitalize(this.get('description').trim());
this.set('model.description', parsedDescription);
},
beforeSubmit() {
this._super(...arguments);
},
afterSubmit() {
this._super(...arguments);
this.set('description', this.setDescription());
}
});
import Ember from 'ember';
import FormRouteMixin from 'ember-form-object/mixins/form-route';
export default Ember.Route.extend(FormRouteMixin, {
formName: 'todo',
model(params) {
return this.store.peekRecord('todo', params.id);
},
afterModel() {
this._super(...arguments);
this.set('form.people', this.store.peekAll('user'));
},
actions: {
saveModelForm() {
this.get('form').save();
// .then() => form saved
// .catch() => validation probably failed
}
}
});
import Ember from 'ember';
import BaseForm from 'ember-form-object/forms/base-form';
export default BaseForm.extend({
properties: {
'email': {
value: '',
validate: { presence: true }
},
'password': {
value: '',
validate: { presence: true }
},
'rememberMe': {
value: false
}
},
submit() {
const credentials = this.getProperties('email', 'password');
// This is mocked, you should actually login here :)
return new Ember.RSVP.Promise((resolve) => setTimeout(() => resolve(credentials), 1000));
}
});
- Add "isValid" state to each property
- Move server validation error logic to base form object
- Example page & docs
- Better test coverage
- Remove form-loss feature from route mixin and just add it as an example
- Add blueprints for ember-cli
git clone
this repositorynpm install
bower install
ember server
- Visit your app at http://localhost:4200.
npm test
(Runsember try:testall
to test your addon against multiple Ember versions)ember test
ember test --server
Contributors welcome.
Infinum LTD © 2016