4

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
    }

2 Answers 2

3

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).

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

7 Comments

I just tried it. If I write onSubmitexactly the same as your answer, it adds the email address to the address bar and not the role: ?email=tes%40test.com. Also, I don't want it that way. I need it to send the data from form to the parent and set the parents states. I added e.preventDefault() to onSubmit and it still complains about not knowing value here: const role = e.target.role.value;
I forgot to add e.preventDefault() thanks for pointing that out. You need to use the same name you have for you form element, e.target.rolesList.value in this case. You should be able to the state of the parent in the handleAddNewUser method that you pass down as props. Something like data => this.setState(data), if you post the code for the parent it would help.
yeah, that's what I did, just made a mistake in my previous comment. Using const role = e.target.rolesList.value; returns this error: Uncaught TypeError: Cannot read property 'value' of undefined
Having had a look at react-widget the DropdownList component doesn't actually create a select box, it is a bunch of div's. That's why this does't work. I will update the answer.
I just added the parent component methods to the question. Can you please tell me what is happening here: this.setState({ [e.target.name]: e.target.value }) . I don't get it
|
0

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);

1 Comment

the problem is it doesn't understand this.role.value and I'm getting this error: Uncaught TypeError: Cannot read property 'value' of undefined

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.