Benjamin RD
Benjamin RD

Reputation: 12034

How can I expose a property from my `Input` control to any other Component?

I created a basic input, with few effects, but a simple input [type='text'] in the base. But, I'm not able to get the value or any property of the state from my Input control. How can I expose a property from my Input control to any other Component?

input.js

import React from "react";

class Input extends React.Component {
  constructor(props) {
    super();
    this.state = {
      inputValue: "",
      fieldActive: false,
      label: props.label,
      placeholder: props.placeholder,
      type: props.type,
      maxLength: props.maxLength,
      error: false,
      required: props.required
    };

    this.updateInputValue = this.updateInputValue.bind(this);
    this.activateField = this.activateField.bind(this);
    this.disableFocus = this.disableFocus.bind(this);
  }

  activateField() {
    this.setState({
      fieldActive: true
    });
  }

  disableFocus(e) {
    if (e.target.value == "") {
      this.setState({
        fieldActive: false
      });

      this.setState({
        error: this.state.required
      });
    } else {
      if (this.state.type == "email") {
        this.setState({
          error: !/^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[A-Za-z]+$/.test(e.target.value)
        });
      }
    }
  }

  updateInputValue(e) {
    this.setState({
      inputValue: e.target.value
    });
    this.activateField(e);
    e.preventDefault();
  }

  render() {
    return (
      <div className="form-group field-group">
        <label
          htmlFor=""
          className={
            this.state.fieldActive
              ? this.state.error
                ? "field-active form-label floating error"
                : "field-active form-label floating"
              : "form-label floating hide"
          }
        >
          {this.props.label}
        </label>
        <input
          className={
            this.state.error
              ? "form-input floating-label error"
              : "form-input floating-label"
          }
          type={this.props.type}
          placeholder={this.props.placeholder}
          maxLength={this.props.maxLength}
          value={this.state.inputValue}
          name={this.props.id}
          id={this.props.id}
          autoComplete="off"

          onFocus={this.activateField}
          onBlur={this.disableFocus}
          onChange={this.updateInputValue}
        />
      </div>
    );
  }
}

export default Input;

MyView.js

<Input
    label="Firstname"
    placeholder="Firstname"
    id="firstname"
    type="text"
    required='true'
    value=''
    maxLength='20'
    onChange={this.handleChange}
/>
</div>

Upvotes: 1

Views: 1913

Answers (3)

new Q Open Wid
new Q Open Wid

Reputation: 2283

You can only do that to its parent or child components. For others, you wouldn't be able to do it.

For parent components, like MyView, check this question: How to pass data from child component to its parent in ReactJS? which has mostly easy-to-understand solutions.

Or, you can check other answers.

For parent to child, easy. Just plug in input = {this.state.x} where x is the property you want to expose and then you can access that by using this.props.input.

Upvotes: 1

Benjamin RD
Benjamin RD

Reputation: 12034

I found a way, not sure if it is better, but it is working. Basically, you can pass a function a receive it as props in the component constructor. And use the view function in the component as a callback function.

view.js

<Input
    label="Firstname"
    placeholder="Firstname"
    id="firstname"
    type="text"
    required='true'
    value=''
    maxLength='20'
    onChange={this.handleChange}
/>

  handleChange = (id, value) => {
    console.log(id);
    console.log(value);
    console.log('-');
    /*this.setState({
      [e.target.name]: e.target.value
    });*/
  };

Input.js

class Input extends React.Component {
  constructor(props) {
    super();
    this.state = {
      inputValue: "",
      fieldActive: false,
      label: props.label,
      placeholder: props.placeholder,
      type: props.type,
      maxLength: props.maxLength,
      error: false,
      required: props.required,
      inputChange: props.onChange,
      id: props.id
    };

    console.log(props);

    this.updateInputValue = this.updateInputValue.bind(this);
    this.activateField = this.activateField.bind(this);
    this.disableFocus = this.disableFocus.bind(this);
  }

  activateField() {
    this.setState({
      fieldActive: true
    });
  }

  disableFocus(e) {
    if (e.target.value == "") {
      this.setState({
        fieldActive: false
      });

      this.setState({
        error: this.state.required
      });
    } else {
      if (this.state.type == "email") {
        this.setState({
          error: !/^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[A-Za-z]+$/.test(e.target.value)
        });
      }
    }
  }

  updateInputValue(e) {
    this.setState({
      inputValue: e.target.value
    });

    if(this.state.inputChange!= undefined && this.state.inputChange != null)
      this.state.inputChange(e.target.id, e.target.value)


    this.activateField(e);
    e.preventDefault();
  }

  render() {
    return (
      <div className="form-group field-group">
        <label
          htmlFor=""
          className={
            this.state.fieldActive
              ? this.state.error
                ? "field-active form-label floating error"
                : "field-active form-label floating"
              : "form-label floating hide"
          }
        >
          {this.props.label}
        </label>
        <input
          className={
            this.state.error
              ? "form-input floating-label error"
              : "form-input floating-label"
          }
          type={this.props.type}
          placeholder={this.props.placeholder}
          maxLength={this.props.maxLength}
          value={this.state.inputValue}
          name={this.props.id}
          id={this.props.id}
          autoComplete="off"

          onFocus={this.activateField}
          onBlur={this.disableFocus}
          onChange={this.updateInputValue}
        />
      </div>
    );
  }
}

export default Input;

Upvotes: 0

Ekaterina
Ekaterina

Reputation: 31

You can only pass its value to parent or child components. So if you want to share some state of a component X with a component Y, then Y should be either X's ancestor or a child of X or a child of X's ancestor.

Parent component can get child's value either from ref or from a callback:

  • Option 1. Add some ref='myinput' to Input, then access it by this.refs.myinput.value from parent component.
  • Option 2. Add some grabChildValue function to a parent method, then add this.props.grabChildValue(this.value) call to input's onChange.

Upvotes: 1

Related Questions