Umbro
Umbro

Reputation: 2204

Creating an input select in an editable form

From the App component, I bring status = paid to the Todo component, then to theEditForm component. The contents of this.props.status = 10 attempts to display ininput select. In select, I put value = {this.props.status}. Select should display paid. It displays unpaid. Status value is 10, but I want display instead of 10 I want to display 'paid'

Code here: https://stackblitz.com/edit/react-xsl5mf

  class EditForm extends React.Component {
      render() {
        return (
          <select defaultValue ={this.props.status} onChange={(e) => this.props.handleChangeStatus(e)}>
              <option value="0">Unpaid</option>
              <option value="10">paid</option>
              <option value="20">free</option>
            </select>
        )
  }
}

class Todo extends Component {

  state = {
    status: ''
  }

  handleChangeStatus = (evt) => {
    this.setState({
      status: evt.target.value
    })
  }


  componentDidMount = () => {
    const { todo } = this.props;

    this.setState({
      status: todo.status
    })
  }

  render() {

    return (

        <EditForm
            handleChangeStatus={this.handleChangeStatus}
            status={this.props.status}
          />
    )
  }
}

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

    this.state = {

      todos: [
        {
          status: 10 //paid
        }
      ]
    };
  }


  render() {
    return (
      <div>
        <ul>
          {
            this.state.todos
              .map((todo, index) =>
                <Todo
                  key={index}
                  index={index}
                  todo={todo}
                />
              )
          }
        </ul>
      </div>
    );
  }
}

Upvotes: 0

Views: 56

Answers (4)

Ozan
Ozan

Reputation: 1762

In your component Todo you are passing the this.props.status which is undefined since such a prop does not exist.

In your Todo componetn when it is mounted you set the status to be todo.status

However here it receives this.props.status whereas you should be passing this.props.todo.status since componentDidMount is uncessary here and it won't actually reflect the status since it will trigger it after the render() method. You could use componentDidMount but it is deprecated so you can do what you are doing inside the constructor.

If you still want to keep the values as integer then you will have to map them to the strings.

  const prices = {
    paid: 20,
    unpaid: 10,
    free: 0
   }


 <EditForm
    handleChangeStatus={this.handleChangeStatus}
    status={this.props.status}
  />

On the other hand your values do not match the value that's being sent to the component. It should be as following since if you define value='10' and has the string of paid it won't know which value is the default value. Your event handler will update the status to be the price in this case.

 <select defaultValue={this.props.status} onChange={(e) => this.props.handleChangeStatus(e)}>
          <option value="unpaid">unpaid</option>
          <option value="paid">paid</option>
          <option value="free">free</option>
 </select>

Take a look at this example here

Upvotes: 0

Taki
Taki

Reputation: 17654

In Todo : you call EditForm with status={this.props.status}, this.props.status is undefined and should be this.state.status

In EditForm : use value instead of defaultValue and the values of the options are not the same as the status, you'd get paid in the props as status but the option's value is 20, you'll need to handle that, for the snippet below i chnged it to paid :

class EditForm extends React.Component {
  render() {
    return (
      <select value ={this.props.status} onChange={(e) => this.props.handleChangeStatus(e)}>
          <option value="0">Unpaid</option>
          <option value="10">paid</option>
          <option value="20">free</option>
        </select>
    )
  }
}

class Todo extends React.Component {

  state = {
    status: ''
  }

  handleChangeStatus = (evt) => {
    this.setState({
      status: evt.target.value
    })
  }


  componentDidMount = () => {
    const { todo } = this.props;

    this.setState({
      status: todo.status
    })
  }

  render() {

    return (
      
        <EditForm
            handleChangeStatus={this.handleChangeStatus}
            status={this.state.status}
          />
    )
  }
}

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

    this.state = {

      todos: [
        {
          status: '10'
        }
      ]
    };
  }


  render() {
    return (
      <div>
        <ul>
          {
            this.state.todos
              .map((todo, index) =>
                <Todo
                  key={index}
                  index={index}
                  todo={todo}
                />
              )
          }
        </ul>
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

Upvotes: 1

Pierre
Pierre

Reputation: 1114

You are doing a couple things wrong:

  • this.props.status inside Editform doesn't exist.
  • The value inside the option elements is incorrect, they should match the string that you are passing into the defaultValue.

    import React, { Component } from 'react'; import { render } from 'react-dom'; import Hello from './Hello'; import './style.css';

    class EditForm extends React.Component { render() { return ( this.props.handleChangeStatus(e)}> Unpaid paid free ) } }

    class Todo extends Component {

    state = { status: '' }

    handleChangeStatus = (evt) => { this.setState({ status: evt.target.value }) }

    render() { console.log(this.state) return (

        <EditForm
            handleChangeStatus={this.handleChangeStatus}
            status={this.props.todo.status}
          />
    )
    

    } }

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

    this.state = {
    
      todos: [
        {
          status: 'paid'
        }
      ]
    };
    

    }

    render() { return (

      { this.state.todos .map((todo, index) => ) }
    ); } } render(, document.getElementById('root'));

Upvotes: 0

Prabhat Mishra
Prabhat Mishra

Reputation: 1021

Actually the EditForm should be like below

    <EditForm
    handleChangeStatus={this.handleChangeStatus}
    status={this.state.status}
    />

And before passing it defaultValue do conversion and map paid to 10.

Upvotes: 0

Related Questions