Skip to content

Commit 46c1f2c

Browse files
committed
Merge pull request christianalfoni#275 from christianalfoni/issue-267
Issue 267
2 parents fbd0911 + dcac495 commit 46c1f2c

File tree

4 files changed

+74
-65
lines changed

4 files changed

+74
-65
lines changed

release/formsy-react.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

release/formsy-react.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main.js

Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -56,30 +56,27 @@ Formsy.Form = React.createClass({
5656
detachFromForm: this.detachFromForm,
5757
validate: this.validate,
5858
isFormDisabled: this.isFormDisabled,
59-
isValidValue: function (component, value) {
59+
isValidValue: (component, value) => {
6060
return this.runValidation(component, value).isValid;
61-
}.bind(this)
61+
}
6262
}
6363
}
6464
},
6565

6666
// Add a map to store the inputs of the form, a model to store
6767
// the values of the form and register child inputs
6868
componentWillMount: function () {
69-
this.inputs = {};
70-
this.model = {};
69+
this.inputs = [];
7170
},
7271

7372
componentDidMount: function () {
7473
this.validateForm();
7574
},
7675

7776
componentWillUpdate: function () {
78-
79-
// Keep a reference to input keys before form updates,
77+
// Keep a reference to input names before form updates,
8078
// to check if inputs has changed after render
81-
this.prevInputKeys = Object.keys(this.inputs);
82-
79+
this.prevInputNames = this.inputs.map(component => component.props.name);
8380
},
8481

8582
componentDidUpdate: function () {
@@ -88,8 +85,8 @@ Formsy.Form = React.createClass({
8885
this.setInputValidationErrors(this.props.validationErrors);
8986
}
9087

91-
var newInputKeys = Object.keys(this.inputs);
92-
if (utils.arraysDiffer(this.prevInputKeys, newInputKeys)) {
88+
var newInputNames = this.inputs.map(component => component.props.name);
89+
if (utils.arraysDiffer(this.prevInputNames, newInputNames)) {
9390
this.validateForm();
9491
}
9592

@@ -110,62 +107,65 @@ Formsy.Form = React.createClass({
110107
// If any inputs have not been touched yet this will make them dirty
111108
// so validation becomes visible (if based on isPristine)
112109
this.setFormPristine(false);
113-
this.updateModel();
114-
var model = this.mapModel();
110+
var model = this.getModel();
111+
model = this.mapModel(model);
115112
this.props.onSubmit(model, this.resetModel, this.updateInputsWithError);
116113
this.state.isValid ? this.props.onValidSubmit(model, this.resetModel, this.updateInputsWithError) : this.props.onInvalidSubmit(model, this.resetModel, this.updateInputsWithError);
117114

118115
},
119116

120-
mapModel: function () {
117+
mapModel: function (model) {
118+
121119
if (this.props.mapping) {
122-
return this.props.mapping(this.model)
120+
return this.props.mapping(model)
123121
} else {
124-
return formDataToObject(Object.keys(this.model).reduce(function (mappedModel, key) {
122+
return formDataToObject(Object.keys(model).reduce((mappedModel, key) => {
125123

126124
var keyArray = key.split('.');
127125
var base = mappedModel;
128126
while (keyArray.length) {
129127
var currentKey = keyArray.shift();
130-
base = (base[currentKey] = keyArray.length ? base[currentKey] || {} : this.model[key]);
128+
base = (base[currentKey] = keyArray.length ? base[currentKey] || {} : model[key]);
131129
}
132130

133131
return mappedModel;
134132

135-
}.bind(this), {}));
133+
}, {}));
136134
}
137135
},
138136

139137
// Goes through all registered components and
140138
// updates the model values
141-
updateModel: function () {
142-
Object.keys(this.inputs).forEach(function (name) {
143-
var component = this.inputs[name];
144-
this.model[name] = component.state._value;
145-
}.bind(this));
139+
getModel: function () {
140+
return this.inputs.reduce((model, component) => {
141+
var name = component.props.name;
142+
model[name] = component.state._value;
143+
return model;
144+
}, {});
146145
},
147146

148147
// Reset each key in the model to the original / initial / specified value
149148
resetModel: function (data) {
150-
Object.keys(this.inputs).forEach(function (name) {
149+
this.inputs.forEach(component => {
150+
var name = component.props.name;
151151
if (data && data[name]) {
152-
this.inputs[name].setValue(data[name]);
152+
component.setValue(data[name]);
153153
} else {
154-
this.inputs[name].resetValue();
154+
component.resetValue();
155155
}
156-
}.bind(this));
156+
});
157157
this.validateForm();
158158
},
159159

160160
setInputValidationErrors: function (errors) {
161-
Object.keys(this.inputs).forEach(function (name, index) {
162-
var component = this.inputs[name];
161+
this.inputs.forEach(component => {
162+
var name = component.props.name;
163163
var args = [{
164164
_isValid: !(name in errors),
165165
_validationError: typeof errors[name] === 'string' ? [errors[name]] : errors[name]
166166
}];
167167
component.setState.apply(component, args);
168-
}.bind(this));
168+
});
169169
},
170170

171171
// Checks if the values have changed from their initial value
@@ -174,9 +174,8 @@ Formsy.Form = React.createClass({
174174
},
175175

176176
getPristineValues: function() {
177-
var inputs = this.inputs;
178-
return Object.keys(inputs).reduce(function (data, name) {
179-
var component = inputs[name];
177+
return this.inputs.reduce((data, component) => {
178+
var name = component.props.name;
180179
data[name] = component.props.value;
181180
return data;
182181
}, {});
@@ -186,49 +185,45 @@ Formsy.Form = React.createClass({
186185
// stored in the inputs map. Change their state to invalid
187186
// and set the serverError message
188187
updateInputsWithError: function (errors) {
189-
Object.keys(errors).forEach(function (name, index) {
190-
var component = this.inputs[name];
191-
188+
Object.keys(errors).forEach((name, index) => {
189+
var component = utils.find(this.inputs, component => component.props.name === name);
192190
if (!component) {
193-
throw new Error('You are trying to update an input that does not exist. Verify errors object with input names. ' + JSON.stringify(errors));
191+
throw new Error('You are trying to update an input that does not exist. ' +
192+
'Verify errors object with input names. ' + JSON.stringify(errors));
194193
}
195194
var args = [{
196195
_isValid: this.props.preventExternalInvalidation || false,
197196
_externalError: typeof errors[name] === 'string' ? [errors[name]] : errors[name]
198197
}];
199198
component.setState.apply(component, args);
200-
}.bind(this));
199+
});
201200
},
202201

203202
isFormDisabled: function () {
204203
return this.props.disabled;
205204
},
206205

207206
getCurrentValues: function () {
208-
return Object.keys(this.inputs).reduce(function (data, name) {
209-
var component = this.inputs[name];
207+
return this.inputs.reduce((data, component) => {
208+
var name = component.props.name;
210209
data[name] = component.state._value;
211210
return data;
212-
}.bind(this), {});
211+
}, {});
213212
},
214213

215214
setFormPristine: function (isPristine) {
216-
var inputs = this.inputs;
217-
var inputKeys = Object.keys(inputs);
218-
219215
this.setState({
220-
_formSubmitted: !isPristine
221-
})
216+
_formSubmitted: !isPristine
217+
});
222218

223219
// Iterate through each component and set it as pristine
224220
// or "dirty".
225-
inputKeys.forEach(function (name, index) {
226-
var component = inputs[name];
221+
this.inputs.forEach((component, index) => {
227222
component.setState({
228223
_formSubmitted: !isPristine,
229224
_isPristine: isPristine
230225
});
231-
}.bind(this));
226+
});
232227
},
233228

234229
// Use the binded values and the actual input value to
@@ -362,16 +357,13 @@ Formsy.Form = React.createClass({
362357
// Validate the form by going through all child input components
363358
// and check their state
364359
validateForm: function () {
365-
var allIsValid;
366-
var inputs = this.inputs;
367-
var inputKeys = Object.keys(inputs);
368360

369361
// We need a callback as we are validating all inputs again. This will
370362
// run when the last component has set its state
371363
var onValidationComplete = function () {
372-
allIsValid = inputKeys.every(function (name) {
373-
return inputs[name].state._isValid;
374-
}.bind(this));
364+
var allIsValid = this.inputs.every(component => {
365+
return component.state._isValid;
366+
});
375367

376368
this.setState({
377369
isValid: allIsValid
@@ -392,8 +384,7 @@ Formsy.Form = React.createClass({
392384

393385
// Run validation again in case affected by other inputs. The
394386
// last component validated will run the onValidationComplete callback
395-
inputKeys.forEach(function (name, index) {
396-
var component = inputs[name];
387+
this.inputs.forEach((component, index) => {
397388
var validation = this.runValidation(component);
398389
if (validation.isValid && component.state._externalError) {
399390
validation.isValid = false;
@@ -403,12 +394,12 @@ Formsy.Form = React.createClass({
403394
_isRequired: validation.isRequired,
404395
_validationError: validation.error,
405396
_externalError: !validation.isValid && component.state._externalError ? component.state._externalError : null
406-
}, index === inputKeys.length - 1 ? onValidationComplete : null);
407-
}.bind(this));
397+
}, index === this.inputs.length - 1 ? onValidationComplete : null);
398+
});
408399

409400
// If there are no inputs, set state where form is ready to trigger
410401
// change event. New inputs might be added later
411-
if (!inputKeys.length && this.isMounted()) {
402+
if (!this.inputs.length && this.isMounted()) {
412403
this.setState({
413404
canChange: true
414405
});
@@ -418,16 +409,24 @@ Formsy.Form = React.createClass({
418409
// Method put on each input component to register
419410
// itself to the form
420411
attachToForm: function (component) {
421-
this.inputs[component.props.name] = component;
422-
this.model[component.props.name] = component.state._value;
412+
413+
if (this.inputs.indexOf(component) === -1) {
414+
this.inputs.push(component);
415+
}
416+
423417
this.validate(component);
424418
},
425419

426420
// Method put on each input component to unregister
427421
// itself from the form
428422
detachFromForm: function (component) {
429-
delete this.inputs[component.props.name];
430-
delete this.model[component.props.name];
423+
var componentPos = this.inputs.indexOf(component);
424+
425+
if (componentPos !== -1) {
426+
this.inputs = this.inputs.slice(0, componentPos)
427+
.concat(this.inputs.slice(componentPos + 1));
428+
}
429+
431430
this.validateForm();
432431
},
433432
render: function () {

src/utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,15 @@ module.exports = {
3737
}
3838

3939
return a === b;
40+
},
41+
42+
find: function (collection, fn) {
43+
for (var i = 0, l = collection.length; i < l; i++) {
44+
var item = collection[i];
45+
if (fn(item)) {
46+
return item;
47+
}
48+
}
49+
return null;
4050
}
4151
};

0 commit comments

Comments
 (0)