Family form example
===================
This example showcases several aspects of React Forms library, most notably
defining **reusable schemas**, creating **custom fieldset components** and
custom input components for **user input formatting**.
The example form is a form for entering information about family.
.. raw:: html
Implementation
--------------
First we need to bring needed components and utilities into scope:
.. jsx::
var React = require('react')
var ReactForms = require('react-forms')
var Form = ReactForms.Form
var FormFor = ReactForms.FormFor
var Schema = ReactForms.schema.Schema
var List = ReactForms.schema.List
var Property = ReactForms.schema.Property
var RadioButtonGroup = ReactForms.input.RadioButtonGroup
Schema
~~~~~~
We start with defining schemas for commonly used fields.
SexField
~~~~~~~~
``SexField`` represents sex of a person. We want to use a radio button group as an
input component for this type of values:
.. jsx::
function SexField(props) {
props = props || {}
var options = [
{value: 'male', name: 'Male'},
{value: 'female', name: 'Female'}
]
return (
}
/>
)
}
After that we can use this field in a different schemas ````. Note how we provide a default values for ``name`` and ``label``.
NameField
~~~~~~~~~
Now let's define a schema for fields which represent a name of a person. We want
to autoformat name so it appears capitalized and we want to perform additional
validation on name value so it cannot contain number or any other non-letters.
First we define a validator:
.. jsx::
function validateName(v) {
return /^[a-z\s]+$/i.test(v) ? true : 'should contain only letters'
}
Now we can use it in schema definition:
.. jsx::
function NameField(props) {
props = props || {}
return (
)
}
Note that we referenced the ```` component. This the thin wrapper on
for ```` which autoformats user input by capitalizing it.
DateOfBirthField
~~~~~~~~~~~~~~~~
``DateOfBirthField`` is define similar to previous fields:
.. jsx::
function DateOfBirthField(props) {
props = props || {}
return (
)
}
Adult and Child
~~~~~~~~~~~~~~~
Now we can define schemas for adults and children, both using already defined
``NameField``, ``DateOfBirthField`` and ``SexField``.
Note the ``component`` property of ``Child`` schema what defines which fieldset
component should be used to render schemas of such type. We will show how to
define ``ChildFieldset`` below:
.. jsx::
function Adult(props) {
props = props || {}
return (
)
}
function Child(props) {
props = props || {}
return (
)
}
Family
~~~~~~
Finally the schema for family would look like a composition of schema types we
defined previously.
Note how we have defined ``Children`` as a list of ``Child``. That describes that a
family can have multiple children and form would have a corresponding UI
controls to add and remove children records:
.. jsx::
function Family(props) {
props = props || {}
return (
)
}
Custom input component for name formatting
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now let's define ```` component which is used by ``NameField`` field to
capitalize user input automatically:
.. jsx::
var NameInput = React.createClass({
getInitialState: function() {
return {selection: {start: 0, end: 0}}
},
onChange: function(e) {
var value = e.target.value
var node = this.getDOMNode()
this.setState({
selection: {start: node.selectionStart, end: node.selectionEnd}
})
this.props.onChange(value)
},
componentDidUpdate: function() {
var node = this.getDOMNode()
if (document.activeElement === node) {
node.setSelectionRange(this.state.selection.start, this.state.selection.end)
}
},
format: function(value) {
return value.split(/\s+/)
.map(function(s) { return s.charAt(0).toUpperCase() + s.slice(1) })
.join(' ')
},
render: function() {
var value = this.format(this.props.value)
return this.transferPropsTo(
)
}
})
It is a little verbose because we need to take care of cursor position in input
box. But other than that it is a thin wrapper for ```` which
just capitalizes every word in a value.
Custom fieldset component for Child
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now we define ``ChildFieldset`` component which is used to render values described
with ``Child`` schema. The reason we want to do this is that we want to show a
different set of fields based on a sex of a child.
Note that creating a fieldset component reduces down to using ``FieldsetMixin``
mixin and defining ``render()`` method.
``FieldsetMixin`` provides ``value()`` method which allows accessing a current
form value for this particular schema node via ``value().value``.
To render its fields ``ChildFieldset`` component uses a ``FormFor`` component
which automatically receives a corresponding schema and value based on its
``name`` property:
.. jsx::
var ChildFieldset = React.createClass({
mixins: [ReactForms.FieldsetMixin],
render: function() {
var sex = this.value().value.sex
return this.transferPropsTo(
{sex === 'male' &&
}
{sex === 'female' &&
}
)
}
})
Rendering forms
~~~~~~~~~~~~~~~
Finally we can render our *Family form* by simply using ``Form`` component with
out ``Family`` schema:
.. jsx::
React.renderComponent(
} />,
document.getElementById('example')
)