-
Notifications
You must be signed in to change notification settings - Fork 3
Forms
Mortar aims to make displaying, manipulating, and saving data simple and clean. The resources we give you to simplify this flow are as follows:
- The Form Bricks display data beautifully, and allow for immediate manipulation of form data.
- The FormStore and FormActions handle receiving updates to form data, saving them to the store (by form key) and returning that data to the page.
- Resource Actions send commands to your api to save the resource.
All form bricks can be used outside of the Form brick, but Form does a lot of heavy lifting for you. For example:
// Before the component
var MortarJS = require('../my-app').MortarJS; //Wherever you bootstrapped Mortar
var FormStore = MortarJS.Stores.FormStore;
// In our component
getInitialState: function() {
return {
user: {
first_name: 'Kyle'
}
}
},
formKey: 'a-unique-string',
componentDidMount: function() {
FormStore.addChangeListener(bindResource);
},
bindResource: function() {
this.setState({
user: FormStore.getResource(this.formKey);
})
},
// In render
<Br.Form key='my-mortar-form'> formKey='this.formKey' bindResource={this.state.user}>
<Br.Form.Input fieldKey='first_name' type='text' />
</Br.Form>With this, any changes by our form input is automatically grabbed by the Form, sent to the FormStore, and then emitted back to our component. By listening to changes on the FormStore we can grab any alterations and save them to state to make sure our data in the component is always reflecting what's in the store.
Validation can be handled in two ways. First, you can rely on the default HTML validations on input fields (e.g. required, min, max, type). The MortarJS Form and FormStore will use these properties to validate on the inputs and report errors back to the user. We have also baked in FormStore.isFormValid(<formKey>) for ensuring all form fields are valid.
However, this is not the most ideal way of doing things. With the usage of the formKey property, our forms can be chopped up across different views and columns, which might make data validation difficult. So, we've forked the great js-schema library to leverage schemas into form validation. Now, we can describe the way we would like the data to look, push that schema into the form, and the form will validate all fields against that form. This allows validation across unmounted components, which enables us to (for example) disable the save button if a required field is null, which wasn't possible with just HTML validation.
var schema = require('js-schema');
var UserSchema = schema({
first_name: String.atLeast(3) // a user should have a first_name that's a string of at least 3 chars.
});
// In render
<Br.Form key='my-mortar-form'> formKey='this.formKey' bindResource={this.state.user} schema={UserSchema}>
<Br.Form.Input fieldKey='first_name' type='text' />
</Br.Form>Now, Mortar will automatically check that the first_name is valid, and, if it's not, will style the field accordingly. js-schmea allows for very complex and customizable validation. For example:
var User = schema({
first_name: String.of(3, 20, 'A-Z') // String between 3-20 characters of only uppercase letters
});
var StudentSchema = schema({
user: User,
school: String,
"?age": Number // Age is optional, but if provided must be a number.
});
// In render
<Br.Form key='my-mortar-form'> formKey='this.formKey' bindResource={this.state.student} schema={UserSchema}>
<Br.Form.Input fieldKey="user.first_name" type="text" />
<Br.Form.DropdownSelect fieldKey="school" options={["UMass Amherst", "NYU"]} multiple={false} />
</Br.Form>We now have simple validation across relationships in our data that is customizable and extensive. These schema relationships can be deeply nested, and can cross reference each other. Be careful though, schemas that are referenced in another schema must be declared first. If, above, User was declared second, the validation would not work correctly.