Skip to content

Commit

Permalink
Report validity state of all registration fields on any change
Browse files Browse the repository at this point in the history
This passes the validity state of all fields to the consumer of
`RegistrationForm` via the `onValdiationChange` callback, instead of just the
most recent error.

In addition, we notify the consumer for any validation change, whether success
or failure. This allows old validation messages to be properly cleared. It also
allows the consumer to be aware of multiple validation errors and display the
next one after you have fixed the first.

Fixes element-hq/element-web#8769
  • Loading branch information
jryans committed Feb 21, 2019
1 parent acae2e9 commit 86a375c
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 17 deletions.
13 changes: 11 additions & 2 deletions src/components/structures/auth/Registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,16 @@ module.exports = React.createClass({
});
},

onFormValidationFailed: function(errCode) {
onFormValidationChange: function(fieldErrors) {
// Find the first error and show that.
const errCode = Object.values(fieldErrors).find(value => value);
if (!errCode) {
this.setState({
errorText: null,
});
return;
}

let errMsg;
switch (errCode) {
case "RegistrationForm.ERR_PASSWORD_MISSING":
Expand Down Expand Up @@ -490,7 +499,7 @@ module.exports = React.createClass({
defaultPhoneNumber={this.state.formVals.phoneNumber}
defaultPassword={this.state.formVals.password}
minPasswordLength={MIN_PASSWORD_LENGTH}
onError={this.onFormValidationFailed}
onValidationChange={this.onFormValidationChange}
onRegisterClick={this.onFormSubmit}
onEditServerDetailsClick={onEditServerDetailsClick}
flows={this.state.flows}
Expand Down
33 changes: 18 additions & 15 deletions src/components/views/auth/RegistrationForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ module.exports = React.createClass({
defaultUsername: PropTypes.string,
defaultPassword: PropTypes.string,
minPasswordLength: PropTypes.number,
onError: PropTypes.func,
onValidationChange: PropTypes.func,
onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise
onEditServerDetailsClick: PropTypes.func,
flows: PropTypes.arrayOf(PropTypes.object).isRequired,
Expand All @@ -60,15 +60,14 @@ module.exports = React.createClass({
getDefaultProps: function() {
return {
minPasswordLength: 6,
onError: function(e) {
console.error(e);
},
onValidationChange: console.error,
};
},

getInitialState: function() {
return {
fieldValid: {},
// Field error codes by field ID
fieldErrors: {},
// The ISO2 country code selected in the phone number entry
phoneCountry: this.props.defaultPhoneCountry,
};
Expand All @@ -81,7 +80,7 @@ module.exports = React.createClass({
// the error that ends up being displayed
// is the one from the first invalid field.
// It's not super ideal that this just calls
// onError once for each invalid field.
// onValidationChange once for each invalid field.
this.validateField(FIELD_PHONE_NUMBER, ev.type);
this.validateField(FIELD_EMAIL, ev.type);
this.validateField(FIELD_PASSWORD_CONFIRM, ev.type);
Expand Down Expand Up @@ -134,9 +133,9 @@ module.exports = React.createClass({
* @returns {boolean} true if all fields were valid last time they were validated.
*/
allFieldsValid: function() {
const keys = Object.keys(this.state.fieldValid);
const keys = Object.keys(this.state.fieldErrors);
for (let i = 0; i < keys.length; ++i) {
if (this.state.fieldValid[keys[i]] == false) {
if (this.state.fieldErrors[keys[i]]) {
return false;
}
}
Expand Down Expand Up @@ -218,13 +217,17 @@ module.exports = React.createClass({
}
},

markFieldValid: function(fieldID, val, errorCode) {
const fieldValid = this.state.fieldValid;
fieldValid[fieldID] = val;
this.setState({fieldValid: fieldValid});
if (!val) {
this.props.onError(errorCode);
markFieldValid: function(fieldID, valid, errorCode) {
const { fieldErrors } = this.state;
if (valid) {
fieldErrors[fieldID] = null;
} else {
fieldErrors[fieldID] = errorCode;
}
this.setState({
fieldErrors,
});
this.props.onValidationChange(fieldErrors);
},

fieldElementById(fieldID) {
Expand All @@ -244,7 +247,7 @@ module.exports = React.createClass({

_classForField: function(fieldID, ...baseClasses) {
let cls = baseClasses.join(' ');
if (this.state.fieldValid[fieldID] === false) {
if (this.state.fieldErrors[fieldID]) {
if (cls) cls += ' ';
cls += 'error';
}
Expand Down

0 comments on commit 86a375c

Please sign in to comment.