Birish
Birish

Reputation: 5822

Sending data from a form to the parent component in ReactJS

I have this AddUser component which which is a simple componnet that gets an email address, and a role from dropdownlist and then passes these two values to the parent component. Everything works fine other than one thing: if I first enter the email address and then choose the role it onChange() doesn't get the value from dropdownlist and pass null to the parent component. But if I first choose role and then enter the email, onChange() gets both values! How can I fix it?

This component has 3 props: roles is a dictionary and I'm creating rolesListfrom it to use it as data for DropdownList (it's from react-widget, https://jquense.github.io/react-widgets/docs/#/?_k=3fo3eq). The second prop is handleChange() that set the states of the parent component. the 3th one ishandleAddNewUser() that returns the values from form to the parent component.

export const AddUser = React.createClass({
    getInitialState() {
        return {
            email: "",
            selectedRole: "",
        };
    },

    onChange() {
        var email = this.email.value;
        this.props.handleChange(email, this.state.selectedRole); 
    }, 

    render() {
        var rolesList = [];
        for(var key in this.props.roles){
            rolesList.push(key);
        }
        return(
            <div >
                <form onSubmit={this.props.handleAddNewUser}>
                    <label >New user email address:</label>
                    <input ref={(ref) => this.email = ref} name='email'  type='email' onChange={this.onChange}  required />
                    <label >Choose a role for new user:</label>
                    <DropdownList data={rolesList} value={this.state.selectedRole} name='rolesList' onChange={selectedRole => this.setState({ selectedRole })} /> 
                    <button type="submit" >Add user</button>
                </form>
            </div>
        );
    },
});

UPDATE: this is the code from parent component, handleChange() sets the states for parent component. handleAddNewUser() is supposed to use the states and make an ajax request to create new user. Right now it gets value for newUserEmail but not the newUserRole

handleChange(email, selectedRole){
    this.setState({newUserEmail: email})
    this.setState({newUserRole: selectedRole})
},

handleAddNewUser(e) {
    e.preventDefault();
    // using its state, it supposed to make an ajax request and create a new user
    }

Upvotes: 4

Views: 2718

Answers (2)

spirift
spirift

Reputation: 3062

You can get the values from the submit handler if you want. Here is an example.

Edit: The component DropdownList doesn't create a real select form element, it just creates a bunch of div elements. This is why the normal event.target solution don't work. You do need a custom onChange handler for the component. Try the below. It will only set the state locally but that should be enough to get this data to any parent container. You haven't posted the code for this.props.handleChange so there is no way to know what args it can take.

Edit2: Added submit handler to call 'this.props.handleChange' with correct data.

export const AddUser = React.createClass({
       getInitialState() {
           return {
               email: "",
               selectedRole: "",
           };
       },

       onChange(e) {
         this.setState({
           [e.target.name]: e.target.value
         })
       },

       onSubmit(e) {
         e.preventDefault();
         this.props.handleChange(this.state.email, this.state.selectedRole)
       },

       render() {
           var rolesList = [];
           for(var key in this.props.roles){
               rolesList.push(key);
           }
           return(
               <div >
                   <form onSubmit={this.onSubmit}>
                       <label >New user email address:</label>
                       <input ref={(ref) => this.email = ref} name='email'  type='email' onChange={this.onChange}  required />
                       <label >Choose a role for new user:</label>
                       <DropdownList ref={(ref) => this.role = ref} data={rolesList} value={this.state.selectedRole} name='rolesList' onChange={selectedRole => this.setState({ selectedRole })} /> 
                       <button type="submit" >Add user</button>
                   </form>
               </div>
           );
       },
   });

Note that this.setState({ [e.target.name]: e.target.value }) using square brackets like this is a way to set the object key without knowing the name ahead of time. In this case is will be whatever the name prop of the element is (email).

Upvotes: 3

vassiliskrikonis
vassiliskrikonis

Reputation: 596

You only call this.onChange() when email input value changes.

So even on the first character you type the this.onChange sends the email value and the this.role.value which is ''.

So add an if() to check if role has a valid value.

to check for role.value inside onChange()

if(email.length > 0 && role.length > 0)
    this.props.handleChange(email, role);

Upvotes: 0

Related Questions