3

I am using switch case for comparison for object key with string in below code:

import { TextField, Button } from "@material-ui/core";
import React, { Component, ReactNode } from "react";

import classes from "./Contact.module.scss";

class contactForm extends Component {
    state = {
        contactForm: {
            name: "",
            email: "",
            message: "",
            phone: ""
        }
    };

    render(): ReactNode {
        return (
            <form className={classes.ArticleBody}>
                <div className={classes.ContactForm}>
                    <TextField
                        value={this.state.contactForm.name}
                        onChange={event => this._inputChangeHandler(event, "name")}
                        label="Full Name"
                        required
                    />
                    <TextField
                        value={this.state.contactForm.email}
                        onChange={event => this._inputChangeHandler(event, "email")}
                        type="Email"
                        label="Email"
                        required
                    />
                    <TextField
                        value={this.state.contactForm.phone}
                        onChange={event => this._inputChangeHandler(event, "phone")}
                        type="phone"
                        label="Phone Number"
                        required
                    />
                    <TextField
                        type="textarea"
                        value={this.state.contactForm.message}
                        label="Comment/Message"
                        rows="4"
                        onChange={event => this._inputChangeHandler(event, "message")}
                        multiline
                        required
                    />
                </div>

                <div className={classes.Submit}>
                    <Button type="submit" onClick={this._submitContactForm}>
                        Submit
                    </Button>
                </div>
            </form>
        );
    }

    private _inputChangeHandler = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, key: string) => {
        const updatedFormData = { ...this.state.contactForm };
        switch (key) {
            case "email":
                updatedFormData.email = event.target.value;
                break;
            case "phone":
                updatedFormData.phone = event.target.value;
                break;
            case "message":
                updatedFormData.message = event.target.value;
                break;
            case "name":
                updatedFormData.name = event.target.value;
                break;
        }
        this.setState({ contactForm: updatedFormData });
    };

    private _submitContactForm = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
        event.preventDefault();
        console.log(this.state.contactForm);
    };
}

export default contactForm;

I don't want to compare my object keys with switch case. Is there any generic approach for changing values on input change for the defined state? e.g.: in below code I am trying to match key from parameter in method _inputChangeHandler but it throws error

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ name: string; email: string; message: string; phone: string; }'

const updatedFormData = { ...this.state.contactForm };
updatedFormData[key] = event.target.value;
this.setState({ contactForm: updatedFormData });

Thanks

3 Answers 3

4

try like this

this.setState({ contactForm: {...this.state.contactForm, [key]: event.target.value} });

@Ajay Verma

you could set the name attribute of the TextField and then you can get the key from the event.

like this

...
private _inputChangeHandler = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
    const key = event.target.name;
...
<TextField
    value={this.state.contactForm.phone}
    name="phone"
    onChange={this._inputChangeHandler}
    type="phone"
    label="Phone Number"
    required
/>
...
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your answer, I don't want to open another question but Can I use something generic for harcoded key value in onChange method: onChange={event => this._inputChangeHandler(event, "name")} here "name" is hardcoded.
2

The TextField has a name prop.

When you need to handle multiple controlled input elements, you can add a name attribute to each element and let the handler function choose what to do based on the value of event.target.name. React Docs

For example:

<TextField
  name="name"
  value={this.state.contactForm.name}
  onChange={this._inputChangeHandler}
  label="Full Name"
  required
/>

....

public _inputChangeHandler(e) {
  this.setState((prevState) => {
    return {
      contactForm: { 
        ...prevState.contactForm,     
        [e.target.name] : e.target.value
      }
    }
  });
}

1 Comment

okay.. thank you.. that'll remove my extra parameter from method. Thank you for the links
1

A general inputChangeHandler can be:

private _inputChangeHandler = (
  event: React.ChangeEvent<
    HTMLInputElement | HTMLTextAreaElement
  >,
  key: string
) => {
  this.setState({
    contactForm: {
      ...this.state.contactForm,
      [key]: event.target.value,
    },
  });
};

Your original code would work but you have to give typescript a hint when using bracket notation to access a property:

const contactForm: {
  [key: string]: string;
} = {
  ...this.state.contactForm,
};
contactForm[key] = event.target.value;

this.setState({
  contactForm,
});

6 Comments

Thank you for your response too. It is same as marked answer and both works perfectly. :)
@AjayVerma It probably is type inference problem, if you define a type for conatactForm your code would probably work as well.
Okay.. I didn't know that thank you for suggestion I'll definitely try to do that also, I don't want to open another question but Can I use something generic for harcoded key value in onChange method: onChange={event => this._inputChangeHandler(event, "name")} here "name" is hardcoded.
@AjayVerma Updated my answer, your code would have worked if you give typescript a hint to be ok with bracket notation (object[key])
Thank you. I'll give it a try and will also look into the interface problem that you mentioned earlier. Thank you for your help. I am learning React, so sorry if I seem confused.
|

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.