diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 00000000..b0c0c8bd
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,3 @@
+{
+ "extends": "airbnb"
+}
diff --git a/.npmignore b/.npmignore
index d2e1dc1b..35b54cdc 100644
--- a/.npmignore
+++ b/.npmignore
@@ -2,7 +2,7 @@
.editorconfig
.travis.yml
testrunner.js
-webpack.production.config.js
+webpack.config.js
examples/
release/
tests/
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 00000000..2b0aa212
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+8.2.1
diff --git a/.travis.yml b/.travis.yml
index ac935e72..3db720c2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
language: node_js
sudo: false
node_js:
- - '4.1'
+ - '8.2.1'
diff --git a/API.md b/API.md
index 42150562..9fb7bb0a 100644
--- a/API.md
+++ b/API.md
@@ -1,90 +1,82 @@
# API
-- [Formsy.Form](#formsyform)
- - [className](#classname)
- - [mapping](#mapping)
- - [validationErrors](#validationerrors)
- - [onSubmit()](#onsubmit)
- - [onValid()](#onvalid)
- - [onInvalid()](#oninvalid)
- - [onValidSubmit()](#onvalidsubmit)
- - [onInvalidSubmit()](#oninvalidsubmit)
- - [onChange()](#onchange)
- - [reset()](#resetform)
- - [getModel()](#getmodel)
- - [updateInputsWithError()](#updateinputswitherrorerrors)
- - [preventExternalInvalidation](#preventexternalinvalidation)
-- [Formsy.Mixin](#formsymixin)
- - [name](#name)
- - [value](#value)
- - [validations](#validations)
- - [validationError](#validationerror)
- - [validationErrors](#validationerrors-1)
- - [required](#required)
- - [getValue()](#getvalue)
- - [setValue()](#setvalue)
- - [resetValue()](#resetvalue)
- - [getErrorMessage()](#geterrormessage)
- - [getErrorMessages()](#geterrormessages)
- - [isValid()](#isvalid)
- - [isValidValue()](#isvalidvalue)
- - [isRequired()](#isrequired)
- - [showRequired()](#showrequired)
- - [showError()](#showerror)
- - [isPristine()](#ispristine)
- - [isFormDisabled()](#isformdisabled)
- - [isFormSubmitted()](#isformsubmitted)
- - [validate](#validate)
- - [formNoValidate](#formnovalidate)
-- [Formsy.HOC](#formsyhoc)
- - [innerRef](#innerRef)
-- [Formsy.Decorator](#formsydecorator)
-- [Formsy.addValidationRule](#formsyaddvalidationrule)
-- [Validators](#validators)
-
-### Formsy.Form
-
-#### className
-```jsx
-
-```
-Sets a class name on the form itself.
-
-#### mapping
-```jsx
-var MyForm = React.createClass({
- mapInputs: function (inputs) {
+- [Formsy](#formsy)
+ - [mapping](#mapping)
+ - [validationErrors](#validationErrors)
+ - [onSubmit()](#onSubmit)
+ - [onValid()](#onValid)
+ - [onInvalid()](#onInvalid)
+ - [onValidSubmit()](#onValidsubmit)
+ - [onInvalidSubmit()](#onInvalidsubmit)
+ - [onChange()](#onChange)
+ - [reset()](#reset)
+ - [getModel()](#getModel)
+ - [updateInputsWithError()](#updateInputsWithError)
+ - [preventExternalInvalidation](#preventExternalInvalidation)
+- [withFormsy](#withFormsy)
+ - [name](#name)
+ - [innerRef](#innerRef)
+ - [value](#value)
+ - [validations](#validations)
+ - [validationError](#validationError)
+ - [validationErrors](#validationErrors)
+ - [required](#required)
+ - [getValue()](#getvalue)
+ - [setValue()](#setValue)
+ - [resetValue()](#resetValue)
+ - [getErrorMessage()](#getErrorMessage)
+ - [getErrorMessages()](#getErrorMessages)
+ - [isValid()](#isValid)
+ - [isValidValue()](#isValidValue)
+ - [isRequired()](#isRequired)
+ - [showRequired()](#showRequired)
+ - [showError()](#showError)
+ - [isPristine()](#isPristine)
+ - [isFormDisabled()](#isFormDisabled)
+ - [isFormSubmitted()](#isFormSubmitted)
+ - [formNoValidate](#formNoValidate)
+- [propTypes](#propTypes)
+- [addValidationRule](#addValidationRule)
+- [Validators](#validators)
+
+### Formsy
+
+`import Formsy from 'react-formsy';`
+
+#### mapping
+
+```jsx
+class MyForm extends React.Component {
+ mapInputs(inputs) {
return {
'field1': inputs.foo,
'field2': inputs.bar
};
- },
- submit: function (model) {
+ }
+ submit(model) {
model; // {field1: '', field2: ''}
- },
- render: function () {
+ }
+ render() {
return (
-
+
-
+
);
}
-})
+}
```
+
Use mapping to change the data structure of your input elements. This structure is passed to the submit hooks.
-#### validationErrors
+#### validationErrors
+
You can manually pass down errors to your form. In combination with `onChange` you are able to validate using an external validator.
```jsx
-var Form = React.createClass({
- getInitialState: function () {
- return {
- validationErrors: {}
- };
- },
- validateForm: function (values) {
+class Form extends React.Component {
+ state = { validationErrors: {} };
+ validateForm = (values) => {
if (!values.foo) {
this.setState({
validationErrors: {
@@ -96,152 +88,213 @@ var Form = React.createClass({
validationErrors: {}
});
}
- },
- render: function () {
+ }
+ render() {
return (
-
+
-
+
);
}
-});
+}
```
-#### onSubmit(data, resetForm, invalidateForm)
+#### onSubmit(data, resetForm, invalidateForm)
+
```jsx
-
+
```
+
Takes a function to run when the submit button has been clicked.
The first argument is the data of the form. The second argument will reset the form. The third argument will invalidate the form by taking an object that maps to inputs. This is useful for server side validation. E.g. `{email: "This email is taken"}`. Resetting or invalidating the form will cause **setState** to run on the form element component.
-#### onValid()
+#### onValid()
+
```jsx
-
+
```
+
Whenever the form becomes valid the "onValid" handler is called. Use it to change state of buttons or whatever your heart desires.
-#### onInvalid()
+#### onInvalid()
+
```jsx
-
+
```
+
Whenever the form becomes invalid the "onInvalid" handler is called. Use it to for example revert "onValid" state.
-#### onValidSubmit(model, resetForm, invalidateForm)
+#### onValidSubmit(model, resetForm, invalidateForm)
+
```jsx
-
+
```
+
Triggers when form is submitted with a valid state. The arguments are the same as on `onSubmit`.
-#### onInvalidSubmit(model, resetForm, invalidateForm)
+#### onInvalidSubmit(model, resetForm, invalidateForm)
+
```jsx
-
+
```
+
Triggers when form is submitted with an invalid state. The arguments are the same as on `onSubmit`.
-#### onChange(currentValues, isChanged)
+#### onChange(currentValues, isChanged)
+
```jsx
-
+
```
+
"onChange" triggers when setValue is called on your form elements. It is also triggered when dynamic form elements have been added to the form. The "currentValues" is an object where the key is the name of the input and the value is the current value. The second argument states if the forms initial values actually has changed.
-#### reset(values)
+#### reset(values)
+
```jsx
-var MyForm = React.createClass({
- resetForm: function () {
+class MyForm extends React.Component {
+ resetForm = () => {
this.refs.form.reset();
- },
- render: function () {
+ }
+ render() {
return (
-
+
...
-
+
);
}
-});
+}
```
+
Manually reset the form to its pristine state. You can also pass an object that inserts new values into the inputs. Keys are name of input and value is of course the value.
-#### getModel()
+#### getModel()
+
```jsx
-var MyForm = React.createClass({
- getMyData: function () {
+class MyForm extends React.Component {
+ getMyData = () => {
alert(this.refs.form.getModel());
- },
- render: function () {
+ }
+ render() {
return (
-
+
...
-
+
);
}
-});
+}
```
+
Manually get values from all registered components. Keys are name of input and value is of course the value.
-#### updateInputsWithError(errors)
+#### updateInputsWithError(errors)
+
```jsx
-var MyForm = React.createClass({
- someFunction: function () {
+class MyForm extends React.Component {
+ someFunction = () => {
this.refs.form.updateInputsWithError({
email: 'This email is taken',
'field[10]': 'Some error!'
});
- },
- render: function () {
+ }
+ render() {
return (
-
+
...
-
+
);
}
-});
+}
```
-Manually invalidate the form by taking an object that maps to inputs. This is useful for server side validation. You can also use a third parameter to the [`onSubmit`](#onsubmitdata-resetform-invalidateform), [`onValidSubmit`](#onvalidsubmitmodel-resetform-invalidateform) or [`onInvalidSubmit`](#oninvalidsubmitmodel-resetform-invalidateform).
-#### preventExternalInvalidation
+Manually invalidate the form by taking an object that maps to inputs. This is useful for server side validation. You can also use a third parameter to the [`onSubmit`](#onSubmit), [`onValidSubmit`](#onValid) or [`onInvalidSubmit`](#onInvalid).
+
+#### preventExternalInvalidation
+
```jsx
-var MyForm = React.createClass({
- onSubmit: function (model, reset, invalidate) {
+class MyForm extends React.Component {
+ onSubmit(model, reset, invalidate) {
invalidate({
foo: 'Got some error'
});
- },
- render: function () {
+ }
+ render() {
return (
-
+
...
-
+
);
}
-});
+}
```
+
With the `preventExternalInvalidation` the input will not be invalidated though it has an error.
-### Formsy.Mixin
+### `withFormsy`
+
+All Formsy input components must be wrapped in the `withFormsy` higher-order component, which provides the following properties and methods through `props`.
+
+```jsx
+import { withFormsy } from 'formsy-react';
+
+class MyInput extends React.Component {
+ render() {
+ return (
+
+ this.props.setValue(e.target.value)}/>
+
+ );
+ }
+}
+export default withFormsy(MyInput);
+```
+
+#### name
-#### name
```jsx
-
-
+
+
```
+
The name is required to register the form input component in the form. You can also use dot notation. This will result in the "form model" being a nested object. `{email: 'value', address: {street: 'value'}}`.
-#### value
+#### innerRef
+
+Use an `innerRef` prop to get a reference to your DOM node.
+
```jsx
-
+class MyForm extends React.Component {
+ componentDidMount() {
+ this.searchInput.focus()
+ }
+ render() {
+ return (
+
+ { this.searchInput = c; }} />
+
+ );
+ }
+}
```
+
+#### value
+
+```jsx
+
+```
+
You should always use the [**getValue()**](#getvalue) method inside your formsy form element. To pass an initial value, use the value attribute. This value will become the "pristine" value and any reset of the form will bring back this value.
-#### validations
+#### validations
+
```jsx
-
-
-
+
+
-
```
+
A comma separated list with validation rules. Take a look at [**Validators**](#validators) to see default rules. Use ":" to separate argument passed to the validator. The argument will go through a **JSON.parse** converting them into correct JavaScript types. Meaning:
```jsx
-
-
+
+
```
+
Works just fine.
-#### validationError
+#### validationError
+
```jsx
-
+
```
+
The message that will show when the form input component is invalid. It will be used as a default error.
-#### validationErrors
+#### validationErrors
+
```jsx
-
```
+
The message that will show when the form input component is invalid. You can combine this with `validationError`. Keys not found in `validationErrors` defaults to the general error message.
-#### required
+#### required
+
```jsx
-
+
```
A property that tells the form that the form input component value is required. By default it uses `isDefaultRequiredValue`, but you can define your own definition of what defined a required state.
```jsx
-
+
```
+
Would be typical for a checkbox type of form element that must be checked, e.g. agreeing to Terms of Service.
-#### getValue()
+#### getValue()
+
```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- render: function () {
+class MyInput extends React.Component {
+ render() {
return (
-
+
);
}
-});
+}
```
+
Gets the current value of the form input component.
-#### setValue(value)
+#### setValue(value\[, validate = true])
+
```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- changeValue: function (event) {
- this.setValue(event.currentTarget.value);
- },
- render: function () {
+class MyInput extends React.Component {
+ changeValue = (event) => {
+ this.props.setValue(event.currentTarget.value);
+ }
+ render() {
return (
-
+
);
}
-});
+}
```
+
Sets the value of your form input component. Notice that it does not have to be a text input. Anything can set a value on the component. Think calendars, checkboxes, autocomplete stuff etc. Running this method will trigger a **setState()** on the component and do a render.
-#### resetValue()
+You can also set the value without forcing an immediate validation by passing a second parameter of `false`. This is useful in cases where you want to only validate on blur / change / etc.
+
+#### resetValue()
+
```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- changeValue: function (event) {
- this.setValue(event.currentTarget.value);
- },
- render: function () {
+class MyInput extends React.Component {
+ changeValue = (event) => {
+ this.props.setValue(event.currentTarget.value);
+ }
+ render() {
return (
-
-
+
+
);
}
-});
+}
```
+
Resets to empty value. This will run a **setState()** on the component and do a render.
-#### getErrorMessage()
+#### getErrorMessage()
+
```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- changeValue: function (event) {
- this.setValue(event.currentTarget.value);
- },
- render: function () {
+class MyInput extends React.Component {
+ changeValue = (event) => {
+ this.props.setValue(event.currentTarget.value);
+ }
+ render() {
return (
);
}
-});
+}
```
+
Will return the validation message set if the form input component is invalid. If form input component is valid it returns **null**.
-#### getErrorMessages()
+#### getErrorMessages()
+
Will return the validation messages set if the form input component is invalid. If form input component is valid it returns empty array.
-#### isValid()
+#### isValid()
+
```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- changeValue: function (event) {
- this.setValue(event.currentTarget.value);
- },
- render: function () {
- var face = this.isValid() ? ':-)' : ':-(';
+class MyInput extends React.Component {
+ changeValue = (event) => {
+ this.props.setValue(event.currentTarget.value);
+ }
+ render() {
+ var face = this.props.isValid() ? ':-)' : ':-(';
return (
);
}
-});
+}
```
+
Lets you check if the form input component should indicate if it is a required field. This happens when the form input component value is empty and the required prop has been passed.
-#### showError()
+#### showError()
+
```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- changeValue: function (event) {
- this.setValue(event.currentTarget.value);
- },
- render: function () {
- var className = this.showRequired() ? 'required' : this.showError() ? 'error' : '';
+class MyInput extends React.Component {
+ changeValue = (event) => {
+ this.props.setValue(event.currentTarget.value);
+ }
+ render() {
+ var className = this.props.showRequired() ? 'required' : this.props.showError() ? 'error' : '';
return (
);
}
-});
+}
```
+
Lets you check if the form input component should indicate if there is an error. This happens if there is a form input component value and it is invalid or if a server error is received.
-#### isPristine()
+#### isPristine()
+
```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- changeValue: function (event) {
- this.setValue(event.currentTarget.value);
- },
- render: function () {
+class MyInput extends React.Component {
+ changeValue = (event) => {
+ this.props.setValue(event.currentTarget.value);
+ }
+ render() {
return (
-
- {this.isPristine() ? 'You have not touched this yet' : ''}
+
+ {this.props.isPristine() ? 'You have not touched this yet' : ''}
);
}
-});
+}
```
-By default all formsy input elements are pristine, which means they are not "touched". As soon as the [**setValue**](#setvaluevalue) method is run it will no longer be pristine.
-**note!** When the form is reset, using the resetForm callback function on for example [**onSubmit**](#onsubmitdata-resetform-invalidateform) the inputs are reset to their pristine state.
+By default all Formsy input elements are pristine, which means they are not "touched". As soon as the [**setValue**](#setValue) method is run it will no longer be pristine.
+
+**note!** When the form is reset (using `reset(...)`) the inputs are reset to their pristine state.
+
+#### isFormDisabled()
-#### isFormDisabled()
```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- render: function () {
+class MyInput extends React.Component {
+ render() {
return (
-
+
);
}
-});
+}
-React.render();
+React.render();
```
+
You can now disable the form itself with a prop and use **isFormDisabled()** inside form elements to verify this prop.
-#### isFormSubmitted()
+#### isFormSubmitted()
+
```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- render: function () {
- var error = this.isFormSubmitted() ? this.getErrorMessage() : null;
+class MyInput extends React.Component {
+ render() {
+ var error = this.props.isFormSubmitted() ? this.props.getErrorMessage() : null;
return (
-
+
{error}
);
}
-});
+}
```
-You can check if the form has been submitted.
-#### validate
-```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- changeValue: function (event) {
- this.setValue(event.target.value);
- },
- validate: function () {
- return !!this.getValue();
- },
- render: function () {
- return (
-
-
-
- );
- }
-});
+You can check if the form has been submitted.
-React.render();
-```
-You can create custom validation inside a form element. The validate method defined will be run when you set new values to the form element. It will also be run when the form validates itself. This is an alternative to passing in validation rules as props.
+#### formNoValidate
-#### formNoValidate
To avoid native validation behavior on inputs, use the React `formNoValidate` property.
-```jsx
-var MyInput = React.createClass({
- mixins: [Formsy.Mixin],
- render: function () {
- return (
-
-
-
- );
- }
-});
-```
-### Formsy.HOC
-The same methods as the mixin are exposed to the HOC version of the element component, though through the `props`, not on the instance.
```jsx
-import {HOC} from 'formsy-react';
-
-class MyInputHoc extends React.Component {
+class MyInput extends React.Component {
render() {
return (
- this.props.setValue(e.target.value)}/>
+
);
}
-};
-export default HOC(MyInputHoc);
+}
```
-#### innerRef
+### `propTypes`
-Use an `innerRef` prop to get a reference to your DOM node.
+If you are using React's PropType type checking, you can spread Formsy’s propTypes into your local propTypes to avoid having to repeatedly add `withFormsy`’s methods to your components.
```jsx
-var MyForm = React.createClass({
- componentDidMount() {
- this.searchInput.focus()
- },
- render: function () {
- return (
-
- { this.searchInput = c; }} />
-
- );
- }
-})
-```
+import PropTypes from 'prop-types';
+import { propTypes } from 'formsy-react';
-### Formsy.Decorator
-The same methods as the mixin are exposed to the decorator version of the element component, though through the `props`, not on the instance.
-```jsx
-import {Decorator as FormsyElement} from 'formsy-react';
-
-@FormsyElement()
class MyInput extends React.Component {
- render() {
- return (
-
- this.props.setValue(e.target.value)}/>
-
- );
+ static propTypes = {
+ firstProp: PropTypes.string,
+ secondProp: PropTypes.object,
+ ...propTypes
}
+}
+
+MyInput.propTypes = {
+ firstProp: PropTypes.string,
+ secondProp: PropTypes.object,
+ ...propTypes,
};
-export default MyInput
```
-### Formsy.addValidationRule(name, ruleFunc)
+### `addValidationRule(name, ruleFunc)`
+
+`import { addValidationRule } from 'formsy-react';`
+
An example:
+
```jsx
-Formsy.addValidationRule('isFruit', function (values, value) {
+addValidationRule('isFruit', function (values, value) {
return ['apple', 'orange', 'pear'].indexOf(value) >= 0;
});
```
+
```jsx
-
+
```
+
Another example:
+
```jsx
-Formsy.addValidationRule('isIn', function (values, value, array) {
+addValidationRule('isIn', function (values, value, array) {
return array.indexOf(value) >= 0;
});
```
+
```jsx
-
+
```
+
Cross input validation:
+
```jsx
-Formsy.addValidationRule('isMoreThan', function (values, value, otherField) {
+addValidationRule('isMoreThan', function (values, value, otherField) {
// The this context points to an object containing the values
// {childAge: "", parentAge: "5"}
// otherField argument is from the validations rule ("childAge")
return Number(value) > Number(values[otherField]);
});
```
+
```jsx
-
-
+
+
```
-## Validators
+
+## Validators
+
**matchRegexp**
+
```jsx
-
```
+
Returns true if the value is thruthful
_For more complicated regular expressions (emoji, international characters) you can use [xregexp](https://github.com/slevithan/xregexp). See [this comment](https://github.com/christianalfoni/formsy-react/issues/407#issuecomment-266306783) for an example._
**isEmail**
+
```jsx
-
+
```
+
Return true if it is an email
**isUrl**
+
```jsx
-
+
```
+
Return true if it is an url
**isExisty**
+
```jsx
-
+
```
+
Returns true if the value is not undefined or null
**isUndefined**
+
```jsx
-
+
```
+
Returns true if the value is the undefined
**isEmptyString**
+
```jsx
-
+
```
+
Returns true if the value is an empty string
**isTrue**
+
```jsx
-
+
```
+
Returns true if the value is the boolean true
**isFalse**
+
```jsx
-
+
```
+
Returns true if the value is the boolean false
**isAlpha**
+
```jsx
-
+
```
+
Returns true if string is only letters
**isNumeric**
+
```jsx
-
+
```
+
Returns true if string only contains numbers. Examples: 42; -3.14
**isAlphanumeric**
+
```jsx
-
+
```
+
Returns true if string only contains letters or numbers
**isInt**
+
```jsx
-
+
```
+
Returns true if string represents integer value. Examples: 42; -12; 0
**isFloat**
+
```jsx
-
+
```
+
Returns true if string represents float value. Examples: 42; -3.14; 1e3
**isWords**
+
```jsx
-
+
```
+
Returns true if string is only letters, including spaces and tabs
**isSpecialWords**
+
```jsx
-
+
```
+
Returns true if string is only letters, including special letters (a-z,ú,ø,æ,å)
**equals:value**
+
```jsx
-
+
```
+
Return true if the value from input component matches value passed (==).
**equalsField:fieldName**
+
```jsx
-
-
+
+
```
+
Return true if the value from input component matches value passed (==).
**isLength:length**
+
```jsx
-
+
```
+
Returns true if the value length is the equal.
**minLength:length**
+
```jsx
-
+
```
+
Return true if the value is more or equal to argument.
**Also returns true for an empty value.** If you want to get false, then you should use [`required`](#required) additionally.
**maxLength:length**
+
```jsx
-
+
```
+
Return true if the value is less or equal to argument
diff --git a/CHANGES.md b/CHANGES.md
deleted file mode 100644
index 72a94734..00000000
--- a/CHANGES.md
+++ /dev/null
@@ -1,81 +0,0 @@
-This is the old CHANGES file. Please look at [releases](https://github.com/christianalfoni/formsy-react/releases) for latest changes.
-
-**0.8.0**
- - Fixed bug where dynamic form elements gave "not mounted" error (Thanks @sdemjanenko)
- - React is now a peer dependency (Thanks @snario)
- - Dynamically updated values should now work with initial "undefined" value (Thanks @sdemjanenko)
- - Validations are now dynamic. Change the prop and existing values are re-validated (thanks @bryannaegele)
- - You can now set a "disabled" prop on the form and check "isFormDisabled()" in form elements
- - Refactored some code and written a couple of tests
-
-**0.7.2**:
- - isNumber validation now supports float (Thanks @hahahana)
- - Form XHR calls now includes CSRF headers, if exists (Thanks @hahahana)
-
-**0.7.1**
- - Fixed bug where external update of value on pristine form element did not update the form model (Thanks @sdemjanenko)
- - Fixed bug where children are null/undefined (Thanks @sdemjanenko)
-
-**0.7.0**
- - Dynamic form elements. Add them at any point and they will be registered with the form
- - **onChange()** handler is called whenever an form element has changed its value or a new form element is added to the form
- - isNumeric validator now also handles actual numbers, not only strings
- - Some more tests
-
-**0.6.0**
- - **onSubmit()** now has the same signature regardless of passing url attribute or not
- - **isPristine()** is a new method to handle "touched" form elements (thanks @FoxxMD)
- - Mapping attributes to pass a function that maps input values to new structure. The new structure is either passed to *onSubmit* and/or to the server when using a url attribute (thanks for feedback @MattAitchison)
- - Added default "equalsField" validation rule
- - Lots of tests!
-
-**0.5.2**
- - Fixed bug with handlers in ajax requests (Thanks @smokku)
-
-**0.5.1**
- - Fixed bug with empty validations
-
-**0.5.0**
- - Added [cross input validation](#formsyaddvalidationrule)
- - Fixed bug where validation rule refers to a string
- - Added "invalidateForm" function when manually submitting the form
-
-**0.4.1**
- - Fixed bug where form element is required, but no validations
-
-**0.4.0**:
- - Possibility to handle form data manually using "onSubmit"
- - Added two more default rules. *isWords* and *isSpecialWords*
-
-**0.3.0**:
- - Deprecated everything related to buttons automatically added
- - Added onValid and onInvalid handlers, use those to manipulate submit buttons etc.
-
-**0.2.3**:
-
- - Fixed bug where child does not have props property
-
-**0.2.2**:
-
- - Fixed bug with updating the props
-
-**0.2.1**:
-
- - Cancel button displays if onCancel handler is defined
-
-**0.2.0**:
-
- - Implemented hasValue() method
-
-**0.1.3**:
-
- - Fixed resetValue bug
-
-**0.1.2**:
-
- - Fixed isValue check to empty string, needs to support false and 0
-
-**0.1.1**:
-
- - Added resetValue method
- - Changed value check of showRequired
diff --git a/README.md b/README.md
index 65cacd14..7f45ac74 100644
--- a/README.md
+++ b/README.md
@@ -1,135 +1,131 @@
-formsy-react [![GitHub release](https://img.shields.io/github/release/christianalfoni/formsy-react.svg)](https://github.com/christianalfoni/formsy-react/releases) [![Build Status](https://travis-ci.org/christianalfoni/formsy-react.svg?branch=master)](https://travis-ci.org/christianalfoni/formsy-react)
-============
+# formsy-react [![GitHub release](https://img.shields.io/github/release/christianalfoni/formsy-react.svg)](https://github.com/christianalfoni/formsy-react/releases) [![Build Status](https://travis-ci.org/christianalfoni/formsy-react.svg?branch=master)](https://travis-ci.org/christianalfoni/formsy-react)
-A form input builder and validator for React JS
+A form input builder and validator for React.
-| [How to use](#how-to-use) | [API](/API.md) | [Examples](/examples) |
-|---|---|---|
+| [Quick Start](#quick-start) | [API](/API.md) | [Examples](/examples) |
+| --------------------------- | -------------- | --------------------- |
-## Background
-I wrote an article on forms and validation with React JS, [Nailing that validation with React JS](http://christianalfoni.github.io/javascript/2014/10/22/nailing-that-validation-with-reactjs.html), the result of that was this extension.
+## Background
-The main concept is that forms, inputs and validation is done very differently across developers and projects. This extension to React JS aims to be that "sweet spot" between flexibility and reusability.
+I wrote an article on forms and validation with React, [Nailing that validation with React JS](http://christianalfoni.github.io/javascript/2014/10/22/nailing-that-validation-with-reactjs.html), the result of that was this component.
-## What you can do
+The main concept is that forms, inputs, and validation are done very differently across developers and projects. This React component aims to be that “sweet spot” between flexibility and reusability.
- 1. Build any kind of form element components. Not just traditional inputs, but anything you want and get that validation for free
+## What You Can Do
- 2. Add validation rules and use them with simple syntax
-
- 3. Use handlers for different states of your form. Ex. "onSubmit", "onError", "onValid" etc.
-
- 4. Pass external errors to the form to invalidate elements
-
- 5. You can dynamically add form elements to your form and they will register/unregister to the form
-
-## Default elements
-You can look at examples in this repo or use the [formsy-react-components](https://github.com/twisty/formsy-react-components) project to use bootstrap with formsy-react, or use [formsy-material-ui](https://github.com/mbrookes/formsy-material-ui) to use [Material-UI](http://material-ui.com/) with formsy-react.
+1. Build any kind of form element components. Not just traditional inputs, but anything you want, and get that validation for free
+2. Add validation rules and use them with simple syntax
+3. Use handlers for different states of your form. (`onError`, `onSubmit`, `onValid`, etc.)
+4. Pass external errors to the form to invalidate elements (E.g. a response from a server)
+5. Dynamically add form elements to your form and they will register/unregister to the form
## Install
- 1. Download from this REPO and use globally (Formsy) or with requirejs
- 2. Install with `npm install formsy-react` and use with browserify etc.
- 3. Install with `bower install formsy-react`
+`yarn add formsy-react react react-dom` and use with webpack, browserify, etc.
-## Changes
+## Quick Start
-[Check out releases](https://github.com/christianalfoni/formsy-react/releases)
+### 1. Build a Formsy element
-[Older changes](CHANGES.md)
+```jsx
+// MyInput.js
+import { withFormsy } from 'formsy-react';
+import React from 'react';
-## How to use
+class MyInput extends React.Component {
+ constructor(props) {
+ super(props);
+ this.changeValue = this.changeValue.bind(this);
+ }
-See [`examples` folder](/examples) for examples. [Codepen demo](http://codepen.io/semigradsky/pen/dYYpwv?editors=001).
+ changeValue(event) {
+ // setValue() will set the value of the component, which in
+ // turn will validate it and the rest of the form
+ // Important: Don't skip this step. This pattern is required
+ // for Formsy to work.
+ this.props.setValue(event.currentTarget.value);
+ }
+
+ render() {
+ // An error message is returned only if the component is invalid
+ const errorMessage = this.props.getErrorMessage();
+
+ return (
+
+
+ {errorMessage}
+
+ );
+ }
+}
+
+export default withFormsy(MyInput);
+```
-Complete API reference is available [here](/API.md).
+`withFormsy` is a [Higher-Order Component](https://facebook.github.io/react/docs/higher-order-components.html) that exposes additional props to `MyInput`. See the [API](/API.md#withFormsy) documentation to view a complete list of the props.
-#### Formsy gives you a form straight out of the box
+### 2. Use your Formsy element
```jsx
- import Formsy from 'formsy-react';
-
- const MyAppForm = React.createClass({
- getInitialState() {
- return {
- canSubmit: false
- }
- },
- enableButton() {
- this.setState({
- canSubmit: true
- });
- },
- disableButton() {
- this.setState({
- canSubmit: false
- });
- },
- submit(model) {
- someDep.saveEmail(model.email);
- },
- render() {
- return (
-
-
-
-
- );
- }
- });
+import Formsy from 'formsy-react';
+import React from 'react';
+import MyInput from './MyInput';
+
+export default class App extends React.Component {
+ constructor(props) {
+ super(props);
+ this.disableButton = this.disableButton.bind(this);
+ this.enableButton = this.enableButton.bind(this);
+ this.state = { canSubmit: false };
+ }
+
+ disableButton() {
+ this.setState({ canSubmit: false });
+ }
+
+ enableButton() {
+ this.setState({ canSubmit: true });
+ }
+
+ submit(model) {
+ fetch('http://example.com/', {
+ method: 'post',
+ body: JSON.stringify(model)
+ });
+ }
+
+ render() {
+ return (
+
+
+
+
+ );
+ }
+}
```
-This code results in a form with a submit button that will run the `submit` method when the submit button is clicked with a valid email. The submit button is disabled as long as the input is empty ([required](/API.md#required)) or the value is not an email ([isEmail](/API.md#validators)). On validation error it will show the message: "This is not a valid email".
+This code results in a form with a submit button that will run the `submit` method when the form is submitted with a valid email. The submit button is disabled as long as the input is empty ([required](/API.md#required)) and the value is not an email ([isEmail](/API.md#validators)). On validation error it will show the message: "This is not a valid email".
-#### Building a form element (required)
-```jsx
- import Formsy from 'formsy-react';
+## Contribute
- const MyOwnInput = React.createClass({
+- Fork repo
+- `yarn`
+- `yarn examples` runs the development server on `localhost:8080`
+- `yarn test` runs the tests
- // Add the Formsy Mixin
- mixins: [Formsy.Mixin],
+## Changelog
- // setValue() will set the value of the component, which in
- // turn will validate it and the rest of the form
- changeValue(event) {
- this.setValue(event.currentTarget.value);
- },
-
- render() {
- // Set a specific className based on the validation
- // state of this component. showRequired() is true
- // when the value is empty and the required prop is
- // passed to the input. showError() is true when the
- // value typed is invalid
- const className = this.showRequired() ? 'required' : this.showError() ? 'error' : null;
-
- // An error message is returned ONLY if the component is invalid
- // or the server has returned an error message
- const errorMessage = this.getErrorMessage();
-
- return (
-
-
- {errorMessage}
-
- );
- }
- });
-```
-The form element component is what gives the form validation functionality to whatever you want to put inside this wrapper. You do not have to use traditional inputs, it can be anything you want and the value of the form element can also be anything you want. As you can see it is very flexible, you just have a small API to help you identify the state of the component and set its value.
-
-## Related projects
-- [formsy-material-ui](https://github.com/mbrookes/formsy-material-ui) - A formsy-react compatibility wrapper for [Material-UI](http://material-ui.com/) form components.
-- [formsy-react-components](https://github.com/twisty/formsy-react-components) - A set of React JS components for use in a formsy-react form.
-- ...
-- Send PR for adding your project to this list!
-
-## Contribute
-- Fork repo
-- `npm install`
-- `npm run examples` runs the development server on `localhost:8080`
-- `npm test` runs the tests
+[Check out releases](https://github.com/christianalfoni/formsy-react/releases)
## License
diff --git a/bower.json b/bower.json
deleted file mode 100644
index b4d7faa4..00000000
--- a/bower.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "name": "formsy-react",
- "version": "0.18.0",
- "description": "A form input builder and validator for React JS",
- "repository": {
- "type": "git",
- "url": "https://github.com/christianalfoni/formsy-react.git"
- },
- "main": "src/main.js",
- "license": "MIT",
- "ignore": [
- "build/",
- "Gulpfile.js"
- ],
- "dependencies": {
- "react": "^0.14.7 || ^15.0.0"
- },
- "keywords": [
- "react",
- "form",
- "forms",
- "validation",
- "react-component"
- ]
-}
diff --git a/examples/.eslintrc b/examples/.eslintrc
new file mode 100644
index 00000000..93c55315
--- /dev/null
+++ b/examples/.eslintrc
@@ -0,0 +1,10 @@
+{
+ "env": {
+ "browser": true
+ },
+ "extends": "eslint:recommended",
+ "rules": {
+ "react/jsx-filename-extension": 0,
+ "react/no-multi-comp": 0
+ }
+}
diff --git a/examples/README.md b/examples/README.md
index e542748c..8af62aac 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -29,7 +29,7 @@ If it is not helped try update your node.js and npm.
2. [**Custom Validation**](custom-validation)
- One field with added validation rule (`Formsy.addValidationRule`) and one field with dynamically added validation and error messages.
+ One field with added validation rule (`addValidationRule`) and one field with dynamically added validation and error messages.
3. [**Reset Values**](reset-values)
diff --git a/examples/components/Checkbox.js b/examples/components/Checkbox.js
new file mode 100644
index 00000000..26c1b37e
--- /dev/null
+++ b/examples/components/Checkbox.js
@@ -0,0 +1,48 @@
+import React from 'react';
+import { propTypes, withFormsy } from 'formsy-react';
+
+class MyCheckbox extends React.Component {
+ constructor(props) {
+ super(props);
+ this.changeValue = this.changeValue.bind(this);
+ this.state = {
+ value: true,
+ };
+ }
+
+ changeValue(event) {
+ // setValue() will set the value of the component, which in
+ // turn will validate it and the rest of the form
+ this.props.setValue(event.target.checked)
+ }
+
+ render() {
+ // Set a specific className based on the validation
+ // state of this component. showRequired() is true
+ // when the value is empty and the required prop is
+ // passed to the input. showError() is true when the
+ // value typed is invalid
+ const className = `form-group ${this.props.className} ${this.props.showRequired() ? 'required' : ''} ${this.props.showError() ? 'error' : ''}`;
+ const value = this.props.getValue();
+ return (
+
+
+
+
+ );
+ }
+}
+
+MyCheckbox.propTypes = {
+ ...propTypes,
+};
+
+export default withFormsy(MyCheckbox);
diff --git a/examples/components/Input.js b/examples/components/Input.js
index fd668344..03579fc8 100644
--- a/examples/components/Input.js
+++ b/examples/components/Input.js
@@ -1,44 +1,47 @@
import React from 'react';
-import Formsy from 'formsy-react';
+import { propTypes, withFormsy } from 'formsy-react';
-const MyInput = React.createClass({
-
- // Add the Formsy Mixin
- mixins: [Formsy.Mixin],
+class MyInput extends React.Component {
+ constructor(props) {
+ super(props);
+ this.changeValue = this.changeValue.bind(this);
+ }
- // setValue() will set the value of the component, which in
- // turn will validate it and the rest of the form
changeValue(event) {
- this.setValue(event.currentTarget[this.props.type === 'checkbox' ? 'checked' : 'value']);
- },
- render() {
+ // setValue() will set the value of the component, which in
+ // turn will validate it and the rest of the form
+ this.props.setValue(event.currentTarget[this.props.type === 'checkbox' ? 'checked' : 'value']);
+ }
+ render() {
// Set a specific className based on the validation
// state of this component. showRequired() is true
// when the value is empty and the required prop is
// passed to the input. showError() is true when the
// value typed is invalid
- const className = 'form-group' + (this.props.className || ' ') +
- (this.showRequired() ? 'required' : this.showError() ? 'error' : '');
+ const className = `form-group ${this.props.className} ${this.props.showRequired() ? 'required' : ''} ${this.props.showError() ? 'error' : ''}`;
// An error message is returned ONLY if the component is invalid
// or the server has returned an error message
- const errorMessage = this.getErrorMessage();
+ const errorMessage = this.props.getErrorMessage();
return (