-
Notifications
You must be signed in to change notification settings - Fork 0
/
withValidation.js
126 lines (109 loc) · 3.99 KB
/
withValidation.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import React from "react";
import PropTypes from "prop-types";
// The function for creating a validation HOC
export function withValidation(
validation,
initialValues,
opts = { afterSubmit: true }
) {
return function(WrappedComponent) {
const factory = React.createFactory(WrappedComponent);
class WithValidation extends React.Component {
constructor(props) {
super(props);
// Set initial values
this.state = {
errors: {},
formData: initialValues,
isValid: true,
isSubmitted: false
};
this.acceptChange = this.acceptChange.bind(this);
this.formSubmit = this.formSubmit.bind(this);
this.updateFormData = this.updateFormData.bind(this);
this.resetFormData = this.resetFormData.bind(this);
}
// Validate the form with the new data
acceptChange(e) {
const formData = Object.assign({}, this.state.formData, {
[e.target.name]: e.target.value
});
this.setState({ formData }, this.validate);
}
validate() {
const formData = this.state.formData;
const errors = validation(formData);
const isValid = !Object.keys(errors).length;
if (!opts.afterSubmit || this.state.isSubmitted)
this.setState({ errors, isValid });
}
formSubmit(e) {
this.setState({ isSubmitted: true }, () => {
if (opts.afterSubmit) this.validate();
});
}
getChildContext() {
return {
publish: this.acceptChange,
submit: this.formSubmit
};
}
/**
* This method is presented as prop to the wrapped component
* and resets the formData.
*/
resetFormData() {
return new Promise(res => {
this.setState({ formData: initialValues }, res);
});
}
/**
* This method is presented as prop to the component
* and updates the formData.
*
* @param {object} changes The changes to apply to the formData
*/
updateFormData(changes) {
if (
changes === null ||
typeof changes !== "object" ||
Array.isArray(changes)
)
throw new Error(
"A non-object was given to updateFormData!"
);
return new Promise(res => {
const formData = Object.assign(
{},
this.state.formData,
changes
);
this.setState({ formData }, res);
});
}
// Pass on props to wrapped component
render() {
return factory(
Object.assign({}, this.props, {
validationErrors: this.state.errors,
formData: this.state.formData,
isValid: this.state.isValid,
updateFormData: this.updateFormData,
resetFormData: this.resetFormData
})
);
}
}
WithValidation.childContextTypes = {
publish: PropTypes.func,
submit: PropTypes.func
};
WithValidation.displayName = `WithValidation(${getDisplayName(
WrappedComponent
)})`;
return WithValidation;
};
}
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || "Component";
}