UNPKG

3.09 kBJavaScriptView Raw
1import { Component, h } from 'preact'
2
3class FormContainer extends Component {
4 constructor (props) {
5 super(props)
6 this.getSetter = this.getSetter.bind(this)
7 this.startingData = props.values
8 this.validity = {}
9 this.state = Object.assign({}, props.values)
10 }
11
12 clearState () {
13 const changes = {
14 submitting: false,
15 submitError: false
16 }
17 for (const key in this.state) {
18 if (key !== 'submitting' && key !== 'submitError') {
19 changes[key] = ''
20 }
21 }
22 this.setState(changes)
23 }
24
25 setValidity (name, valid) {
26 this.validity[name] = !!valid
27 }
28
29 getSetter (name) {
30 return ({validity, value}) => {
31 if (typeof validity !== 'undefined') {
32 this.setValidity(name, !!validity)
33 }
34 if (typeof value !== 'undefined') {
35 this.setState({[name]: value})
36 }
37 }
38 }
39
40 isValid () {
41 for (const key in this.validity) {
42 if (!this.validity[key]) {
43 return false
44 }
45 }
46 return true
47 }
48
49 getChanged () {
50 if (!this.startingData) {
51 return Object.assign({}, this.state)
52 }
53 const changes = {}
54 for (const key in this.state) {
55 const currentVal = this.state[key]
56 if (currentVal !== this.startingData[key]) {
57 changes[key] = currentVal
58 }
59 }
60 for (const key in this.startingData) {
61 const currentVal = this.state[key]
62 if (currentVal !== this.startingData[key]) {
63 changes[key] = currentVal
64 }
65 }
66 if (!Object.keys(changes).length) {
67 return null
68 }
69 return changes
70 }
71
72 render () {
73 const changes = this.getChanged()
74 const hasChanged = !!changes
75 const isValid = this.isValid()
76
77 const {submitting, submitError} = this.state
78
79 const hasNotSubmitted = !submitting && !submitError
80
81 return (
82 h('form', {
83 className: this.props.className,
84 onSubmit: (e) => {
85 e.preventDefault()
86 if (isValid && (this.props.submitWhenUnchanged || hasChanged)) {
87 const values = Object.assign({}, this.state)
88 // clean up
89 delete values.submitting
90 delete values.submitError
91 const res = this.props.onSubmit({
92 values,
93 changes
94 })
95 if (res && res.then) {
96 this.setState({submitting: true})
97 res.then(
98 () => {
99 this.clearState()
100 },
101 () => {
102 this.setState({submitError: true, submitting: false})
103 }
104 )
105 }
106 }
107 }
108 },
109 submitting && submitting && h('div', null, this.props.submitMessage),
110 submitError && submitting && h('div', null, 'Something went wrong'),
111 hasNotSubmitted && this.props.children[0]({
112 values: this.state,
113 validity: this.validity,
114 getSetter: this.getSetter,
115 formIsValid: isValid
116 })
117 )
118 )
119 }
120}
121
122FormContainer.defaultProps = {
123 submitMessage: 'Sending...'
124}
125
126export default FormContainer