Ivan
Ivan

Reputation: 436

How to make password validation from child components?

I have a react project. I need to validate 2 values from child components

Child component:

class PasswordField extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            password: '',

            len: null,
            upperCaseChar: null,
            lowerCaseChar: null,
            number: null,
        };

        this.passwordValidator = this.passwordValidator.bind(this);
    }

    passwordValidator(event) {
        const string = event.target.value;
        this.props.callback(event.target.value);
        this.setState({
            len: string.length >= 8 && string.length <= 30,
            upperCaseChar: /[A-Z]/.test(string),
            lowerCaseChar: /[a-z]/.test(string),
            number: /\d/.test(string),
            password: string
        });
    }

    render() {
        return (
            <div>
                <input className={styles.niceInput} type="password" name={this.props.formName} onChange={this.passwordValidator} placeholder={this.props.placeholder} required/><br/>
                {this.state.len === false &&
                <InformationElement error={true} message={"[8, 30]"}/>}
                {this.state.upperCaseChar === false &&
                <InformationElement error={true} message={"A"}/>}
                {this.state.lowerCaseChar === false &&
                <InformationElement error={true} message={"a"}/>}
                {this.state.number === false &&
                <InformationElement error={true} message={"1"}/>}
            </div>
        );
    }
}

Parent component:

import React from 'react';

import UsernameField from "./UsernameField";
import PasswordField from "./PasswordField";
import InformationElement from "../InformationElement";

class RegistrationForm extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            api_base_url: "http://127.0.0.1",
            api_base_port: "8000",
            api_user_url: "/api/v1/user",

            username: '',
            password: '',
            confirm_password: '',
            passwords_are_similar: true,
            username_is_ok: null
        };
    }

    render() {
        return <div className="form-group">
            <form method="POST">
                <label htmlFor="login" className="font-weight-bold">Registration</label>
                <UsernameField
                    id="login"
                    className="container"
                    callbackUsername={(value) => this.setState({username: value})}
                    callbackStatus={(value) => this.setState({username_is_ok: value})}
                    api_base_url={`${this.state.api_base_url}:${this.state.api_base_port}${this.state.api_user_url}`}/>
                <PasswordField
                    placeholder="Password"
                    formName="password"
                    callback={(value) => this.setState({password: value})}
                />
                <PasswordField
                    placeholder="Confirm password"
                    formName="confirm_password"
                    callback={(value) => this.setState({confirm_password: value})}
                />
                <br/>
                {this.state.passwords_are_similar === false &&
                <InformationElement error={true} message={"Passwords do not match"}/>}
                <button type="button" className="btn btn-light" onClick={this.formSender}
                        disabled={this.state.username_is_ok !== true}>Registrate
                </button>
            </form>
        </div>
    }
}


export default RegistrationForm;

I want to get value from both PasswordFields, but onChange is already taken by passwordValidator, so I can not pass (or I do not know how) another function. How to validate passwords in the parent component?

Also if there are any other problems in my code, feel free to point me, that is my first react project

Upvotes: 0

Views: 172

Answers (1)

Carlos Saiz Orteu
Carlos Saiz Orteu

Reputation: 1805

Right so your parent component would be like this:

import React from 'react';

import PasswordField from "./PasswordField";

class RegistrationForm extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            api_base_url: "http://127.0.0.1",
            api_base_port: "8000",
            api_user_url: "/api/v1/user",

            username: '',
            password: '',
            confirm_password: '',
            passwords_are_similar: true,
            username_is_ok: null
        };
    }

    render() {
        return <div className="form-group">
            <form method="POST">
                <label htmlFor="login" className="font-weight-bold">Registration</label>
                <PasswordField
                    placeholder="Password"
                    formName="password"
                    callback={(value) => this.setState({password: value})}
                />
                <PasswordField
                    placeholder="Confirm password"
                    formName="confirm_password"
                    callback={(value) => this.setState({confirm_password: value})}
                />
            </form>
        </div>
    }
}


export default RegistrationForm;

And your PasswordField component would be like this:

class PasswordField extends React.Component {

  constructor(props) {
      super(props);

      this.state = {
          password: '',

          len: null,
          upperCaseChar: null,
          lowerCaseChar: null,
          number: null,
      };

      this.passwordValidator = this.passwordValidator.bind(this);
  }

  passwordValidator(event) {
      const string = event.target.value;
      this.props.callback(event.target.value);
      this.setState({
          len: string.length >= 8 && string.length <= 30,
          upperCaseChar: /[A-Z]/.test(string),
          lowerCaseChar: /[a-z]/.test(string),
          number: /\d/.test(string),
          password: string
      });
  }

  onChange = (val) => {
    const { callback } = this.props;
    this.passwordValidator(val);
    callback(val);
  }

  render() {
      return (
          <div>
              <input className={styles.niceInput} type="password" name={this.props.formName} onChange={(e) => onChange(e.target.value)} placeholder={this.props.placeholder} required/><br/>
              {this.state.len === false &&
              <InformationElement error={true} message={"[8, 30]"}/>}
              {this.state.upperCaseChar === false &&
              <InformationElement error={true} message={"A"}/>}
              {this.state.lowerCaseChar === false &&
              <InformationElement error={true} message={"a"}/>}
              {this.state.number === false &&
              <InformationElement error={true} message={"1"}/>}
          </div>
      );
  }
}

Might have some error missing but that would be the way.

Upvotes: 1

Related Questions