Skip to content

Instantly share code, notes, and snippets.

@JSchaenzle
Last active April 21, 2018 14:47
Show Gist options
  • Save JSchaenzle/3727f5bda08cd6a31e18c24e61c263ce to your computer and use it in GitHub Desktop.
Save JSchaenzle/3727f5bda08cd6a31e18c24e61c263ce to your computer and use it in GitHub Desktop.

Revisions

  1. JSchaenzle revised this gist Oct 2, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion ruleRunner.js
    Original file line number Diff line number Diff line change
    @@ -13,7 +13,7 @@ export const ruleRunner = (field, name, ...validations) => {

    export const run = (state, runners) => {
    return runners.reduce((memo, runner) => {
    Object.assign(memo, runner(state));
    return Object.assign(memo, runner(state));
    }, {});
    };

  2. JSchaenzle revised this gist Oct 1, 2016. 1 changed file with 3 additions and 4 deletions.
    7 changes: 3 additions & 4 deletions ruleRunner.js
    Original file line number Diff line number Diff line change
    @@ -12,10 +12,9 @@ export const ruleRunner = (field, name, ...validations) => {
    };

    export const run = (state, runners) => {
    let errors = {};
    runners.reduce((memo, runner) => {
    Object.assign(errors, runner(state));
    return runners.reduce((memo, runner) => {
    Object.assign(memo, runner(state));
    }, {});
    return errors;
    };


  3. JSchaenzle revised this gist Oct 1, 2016. 1 changed file with 34 additions and 0 deletions.
    34 changes: 34 additions & 0 deletions TextField.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    import React from 'react';
    import OptionallyDisplayed from './OptionallyDisplayed.jsx';

    export default class TextField extends React.Component {

    constructor(props) {
    super(props);
    this.shouldDisplayError = this.shouldDisplayError.bind(this);
    }

    shouldDisplayError() {
    return this.props.showError && this.props.errorText != "";
    }

    render() {
    return (
    <div>
    <input type="text" placeholder={this.props.placeholder}
    value={this.props.text} onChange={this.props.onFieldChanged} />
    <OptionallyDisplayed display={this.shouldDisplayError()}>
    <div className="validation-error">
    <span className="text">{this.props.errorText}</span>
    </div>
    </OptionallyDisplayed>
    </div>
    );
    }
    }

    TextField.propTypes = {
    showError: React.PropTypes.bool.isRequired,
    onFieldChanged: React.PropTypes.func.isRequired
    };

  4. JSchaenzle created this gist Oct 1, 2016.
    49 changes: 49 additions & 0 deletions CreateAccount.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,49 @@
    const fieldValidations = [
    ruleRunner("name", "Name", required),
    ruleRunner("emailAddress", "Email Address", required),
    ruleRunner("password1", "Password", required, minLength(6)),
    ruleRunner("password2", "Password Confirmation", mustMatch("password1", "Password"))
    ];

    export default class CreateAccount extends React.Component {
    constructor() {
    // ...
    this.state = {
    showErrors: false,
    validationErrors: {}
    };

    // Run validations on initial state
    this.state.validationErrors = run(this.state, fieldValidations);
    }

    handleFieldChanged(field) {
    return (e) => {
    // update() is provided by React Immutability Helpers
    // https://facebook.github.io/react/docs/update.html
    let newState = update(this.state, {
    [field]: {$set: e.target.value}
    });
    newState.validationErrors = run(newState, fieldValidations);
    this.setState(newState);
    };

    handleSubmitClicked() {
    this.setState({showErrors: true});
    if($.isEmptyObject(this.state.validationErrors) == false) return null;
    // ... continue submiting data to server
    }

    render() {
    return (
    <div>
    <TextView placeholder="Email address" showError={this.state.showErrors}
    text={this.props.emailAddress} onFieldChanged={this.handleFieldChanged("emailAddress")}
    errorText={this.errorFor("emailAddress")} />

    // Render Name, Password, Submit button, etc. fields
    </div>
    );
    }

    }
    12 changes: 12 additions & 0 deletions errorMessages.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@

    export const isRequired = fieldName => `${fieldName} is required`;

    export const mustMatch = otherFieldName => {
    return (fieldName) => `${fieldName} must match ${otherFieldName}`;
    };

    export const minLength = length => {
    return (fieldName) => `${fieldName} must be at least ${length} characters`;
    };


    21 changes: 21 additions & 0 deletions ruleRunner.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,21 @@

    export const ruleRunner = (field, name, ...validations) => {
    return (state) => {
    for (let v of validations) {
    let errorMessageFunc = v(state[field], state);
    if (errorMessageFunc) {
    return {[field]: errorMessageFunc(name)};
    }
    }
    return null;
    };
    };

    export const run = (state, runners) => {
    let errors = {};
    runners.reduce((memo, runner) => {
    Object.assign(errors, runner(state));
    }, {});
    return errors;
    };

    22 changes: 22 additions & 0 deletions rules.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,22 @@
    import * as ErrorMessages from './errorMessages.js';

    export const required = (text) => {
    if (text) {
    return null;
    } else {
    return ErrorMessages.isRequired;
    }
    };

    export const mustMatch = (field, fieldName) => {
    return (text, state) => {
    return state[field] == text ? null : ErrorMessages.mustMatch(fieldName);
    };
    };

    export const minLength = (length) => {
    return (text) => {
    console.log("Checking for length greater than ", length);
    return text.length >= length ? null : ErrorMessages.minLength(length);
    };
    };