0

I'm using react-select to render two types of "job" options. From the dropdown the user is able to select either of the options. Based on the option selected they should render different divs that contain more input values. The input values are dependent on the selectedOption. I have two class components with render methods that should display the different inputs corresponding to the jobType

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      selectedOption: null
    };

    this.onChange = this.onChange.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }

  onChange = e => {
    this.set({ [e.target.name]: e.target.value });
    console.log([e.target.value]);
  };

  handleChange = selectedOption => {
    this.setState({ selectedOption });
    console.log("Option selected: ", selectedOption);
  };

  render() {
    const { selectedOption } = this.state;
    return (
      <div>
        <fieldset>
          <legend>Parameters</legend>
          <label htmlFor="jobType" style={{ display: "block" }}>
            jobType:
          </label>
          <div>
            <Select
              value={selectedOption}
              onChange={this.handleChange}
              options={options}
              placeholder="Select a jobType..."
              isSearchable={options}
            />
          </div>
        </fieldset>
        <div>
          {selectedOption === "Batch" ? (
            <BatchParams />
          ) : selectedOption === "Streaming" ? (
            <StreamingParams />
          ) : null}
        </div>
      </div>
    );
  }
}

So let's say when the Streaming option is selected from the dropdown the following class component should be rendered:

class StreamingParams extends React.Component {
      constructor(props) {
        super(props);

        this.state = {
          maxHits: 1
        };
        this.handleMaxHitsChange = this.handleMaxHitsChange.bind(this);
      }

      handleMaxHitsChange = e => {
        this.set({ [e.target.name]: e.target.valu });
      };
      render() {
        return (
          <div>
            <label>maxHits:</label>
            <input
              type="number"
              name="maxHits"
              onChange={this.handleMaxHitsChange}
              placeholder="1"
              min="1"
              step="1"
              required
            />
          </div>
        );
      }
    }

I can't quite get the additional input boxes to render, not sure if I'm taking the correct approach here. I have included a codesandbox with my issue.

0

3 Answers 3

2

So it looks like the value that is getting set in this.state.selectedOption is an object with a value and a label field.

enter image description here

So you need to key off of those. Instead of doing this

          {selectedOption === "Batch" ? (
            <BatchParams />
          ) : selectedOption === "Streaming" ? (
            <StreamingParams />
          ) : null}

Do this

          {selectedOption && selectedOption.value === "batch" ? (
            <BatchParams />
          ) : selectedOption && selectedOption.value === "streaming" ? (
            <StreamingParams />

You should opt for value instead of label in case of localization or translations.

Fork https://codesandbox.io/s/ll5p30nx5q

Sign up to request clarification or add additional context in comments.

3 Comments

You all very adequately answered the question with ample explanation, than you. Also +1 for mentioning use of value over label
Hey that was my idea! No worries, better to learn from others than advocating your code.
@Siavas I very much appreciate your time and effort looking into my issue. After edits the answers were of no discernible difference. If I could mark both as solutions I certainly would!
2

Only the ternary operator has to be changed: find an updated codesandbox here.

In the ternary operators you will have to check this.state.selectedOption.value as that is where your option value is stored.

{!this.state.selectedOption ? 
    null : 
    this.state.selectedOption.value === "batch" ? (
        <BatchParams />
    ) : (
        <StreamingParams />
    )
}

Also you will have to first check for null as that is the initial value you get for this.state.selectedOption when no element in the select has been set.

Comments

1

The issue was that you have to take the value in the selectedOptions and assign that value to the selectedOption in the event handler setState. You were trying to assign an object and therefore the issue. Have made the changes in the sandbox also. Hope it helps.

import React from "react";
import ReactDOM from "react-dom";
import Select from "react-select";

import "./styles.css";

const options = [
  { value: "batch", label: "Batch" },
  { value: "streaming", label: "Streaming" }
];

class BatchParams extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      batchNumber: 1
    };
    this.handleBatchNumChange = this.handleBatchNumChange.bind(this);
  }

  handleBatchNumChange = e => {
    this.set({ [e.target.name]: e.target.valu });
  };
  render() {
    return (
      <div>
        <label>batchNumberSize:</label>
        <input
          type="number"
          name="batchNumberSize"
          onChange={this.handleBatchNumChange}
          placeholder="1"
          min="1"
          step="1"
          required
        />
      </div>
    );
  }
}

class StreamingParams extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      maxHits: 1
    };
    this.handleMaxHitsChange = this.handleMaxHitsChange.bind(this);
  }

  handleMaxHitsChange = e => {
    this.set({ [e.target.name]: e.target.valu });
  };
  render() {
    return (
      <div>
        <label>maxHits:</label>
        <input
          type="number"
          name="maxHits"
          onChange={this.handleMaxHitsChange}
          placeholder="1"
          min="1"
          step="1"
          required
        />
      </div>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      selectedOption: null
    };

    this.onChange = this.onChange.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }

  onChange = e => {
    this.set({ [e.target.name]: e.target.value });
    console.log([e.target.value]);
  };

  handleChange =( {value}) => {
    console.log(value);
    this.setState({ selectedOption: value });
    
  };

  render() {
    const { selectedOption } = this.state;
    return (
      <div>
        <fieldset>
          <legend>Parameters</legend>
          <label htmlFor="querySchemaName" style={{ display: "block" }}>
            jobType:
          </label>
          <div>
            <Select
              value={selectedOption}
              onChange={this.handleChange}
              options={options}
              placeholder="Select a jobType..."
              isSearchable={options}
            />
          </div>
        </fieldset>
        <div>

          {selectedOption === "batch" && <BatchParams /> }
          {selectedOption === "streaming" && <StreamingParams />}
        </div>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.