1

In my project, there is an input field to add email tags. which I created using react js. That file working properly, when I convert the file into type script I can't type or paste values to the input field, but there is no error showing in the terminal

js file

import React from "react";
import ReactDOM from "react-dom";
import Chip from "@material-ui/core/Chip";
import "./styles.css";
import TextField from "@material-ui/core/TextField";

class App extends React.Component {
  state = {
    items: [],
    value: "",
    error: null,

  };

  handleKeyDown = evt => {
    if (["Enter", "Tab", ","].includes(evt.key)) {
      evt.preventDefault();

      var value = this.state.value.trim();

      if (value && this.isValid(value)) {
        this.setState({
          items: [...this.state.items, this.state.value],
          value: ""
        });
      }
    }
  };

  handleChange = evt => {
    this.setState({
      value: evt.target.value,
      error: null
    });
  };

  handleDelete = (item) => {
    this.setState({
      items: this.state.items.filter(i => i !== item),
    });
  };
  
  handleItemEdit = item =>{
      const result = this.state.items.filter(values=>values!==item)
      this.setState({
        value: item,
        error: null,
        items: result
      });
  }

  handlePaste = evt => {
    evt.preventDefault();

    var paste = evt.clipboardData.getData("text");
    var emails = paste.match(/[\w\d\.-]+@[\w\d\.-]+\.[\w\d\.-]+/g);

    if (emails) {
      var toBeAdded = emails.filter(email => !this.isInList(email));

      this.setState({
        items: [...this.state.items, ...toBeAdded]
      });
    }
  };

  isValid(email) {
    let error = null;

    if (this.isInList(email)) {
      error = `${email} has already been added.`;
    }

    if (!this.isEmail(email)) {
      error = `${email} is not a valid email address.`;
    }

    if (error) {
      this.setState({ error });

      return false;
    }

    return true;
  }

  isInList(email) {
    return this.state.items.includes(email);
  }

  isEmail(email) {
    return /[\w\d\.-]+@[\w\d\.-]+\.[\w\d\.-]+/.test(email);
  }

  render() {
    return (
      <>
        {/* {this.state.items.map(item => (
          <div className="tag-item" key={item} onClick={() => this.handleItemEdit(item)}>
            {item}
            <button
              type="button"
              className="button"
              onClick={(e) => this.handleDelete(e,item)}
            >
              &times;
            </button>
          </div>
        ))} */}

        <TextField id="outlined-basic" variant="outlined"
        InputProps={{
          startAdornment: this.state.items.map(item => (
            <Chip
              key={item}
              tabIndex={-1}
              label={item}
              onDelete={() => this.handleDelete(item)}
              onClick={() => this.handleItemEdit(item)}
            />
          )),

        }}
          ref={this.state.items}
          className={"input " + (this.state.error && " has-error")}
          value={this.state.value}
          placeholder="Type or paste email addresses and press `Enter`..."
          onKeyDown={this.handleKeyDown}
          onChange={this.handleChange}
          onPaste={this.handlePaste}
        />

        {this.state.error && <p className="error">{this.state.error}</p>}
      </>
    );
  }
}

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

ts file

import React, { useRef, useState } from "react";
import ReactDOM from "react-dom";
import Chip from "@material-ui/core/Chip";
import TextField from "@material-ui/core/TextField";

interface details{
    item: string
}

// type Props = {
//     test: string,
//     // error: string,
//   };
  

export const TagActions = () => {
    // var { test } = props
    const [items, setItem] = useState<string[]>([]);
    const [value, setValue] = useState('')
    const [error, setError]= useState('')
    const divRef = useRef<HTMLDivElement>(null)

    const handleDelete = (item:any) => {
        const result = items.filter(i => i !== item)
        setItem(result)
      };
    
    const handleItemEdit = (item:any) =>{
        const result = items.filter(i => i !== item)
        setItem(result)
        setValue(value)
        
    };

    const handleKeyDown = (evt:any) => {
        if (["Enter", "Tab", ","].includes(evt.key)) {
          evt.preventDefault();

          var test = value.trim();
    
          if (test && isValid(test)) {
            items.push(test)
            setValue("")
           
          }
        }
    };

    const isValid = (email:any)=> {
        let error = null;
    
        if (isInList(email)) {
          error = `${email} has already been added.`;
        }
    
        if (!isEmail(email)) {
          error = `${email} is not a valid email address.`;
        }
    
        if (error) {
            setError(error);
    
          return false;
        }
    
        return true;
    }

    const isInList = (email:any)=> {
        return items.includes(email);
      }
    
    const isEmail = (email:any)=> {
        return /[\w\d\.-]+@[\w\d\.-]+\.[\w\d\.-]+/.test(email);
    }

    const handleChange = (evt:any) => {
        setValue(evt.target.value)
        // setError("")
        
    };

    const handlePaste = (evt:any) => {
        evt.preventDefault();
    
        var paste = evt.clipboardData.getData("text");
        var emails = paste.match(/[\w\d\.-]+@[\w\d\.-]+\.[\w\d\.-]+/g);
    
        if (emails) {
          var toBeAdded = emails.filter((email:any) => !isInList(email));
            
            setItem(toBeAdded)
        
        }
    };
    


    return (
        <>
          
          <TextField id="outlined-basic" variant="outlined"
          InputProps={{
            startAdornment: items.map(item => (
              <Chip
                key={item}
                tabIndex={-1}
                label={item}
                onDelete={() => handleDelete(item)}
                onClick={() => handleItemEdit(item)}
              />
            )),
  
          }}
            ref={divRef}
            value={value}
            placeholder="Type or paste email addresses and press `Enter`..."
            onKeyDown={(e) => handleKeyDown}
            onChange={(e) => handleChange}
            onPaste={(e) => handlePaste}
          />
  
          {error && <p className="error">{error}</p>}
        </>
      );
}


I am a beginner in react typescript. So I don't know what's going on. At first, I referred some documents and applied some solutions, but the expected result did not come. Please share some suggestions to solve this problem

1 Answer 1

3

That's a very good start - but there are a few simple issues.

The first big difference between JS and TS is of course the typing - so your functions should definetely be checking that the correct values are being passed! For example:

const isEmail = (email:any)=> {
    return /[\w\d\.-]+@[\w\d\.-]+\.[\w\d\.-]+/.test(email);
}

should be:

const isEmail = (email:string)=> {
    return /[\w\d\.-]+@[\w\d\.-]+\.[\w\d\.-]+/.test(email);
}

This ensures that you can only pass a string to isEmail function.

The same goes for the event handlers - one trick I like to use when figuring out the function signature is hovering over the declaration in TSX: enter image description here

If you hover over onChange in TSX, it will tell you that its of type React.ChangeEventHandler<HTMLTextAreaElement | HTMLInputElement>, so to get the type of event evt in your function, just remove the handler bit:

const handleChange = (evt: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
   // code here 
}

Another thing ythat's wrong currently is the way you call the function. In your code you do:

<TextField 
  id="outlined-basic" 
  variant="outlined"
  ...
  onChange={e => handleChange}
/>

You aren't actually invoking the handleChange function, so you could do this:

<TextField 
  id="outlined-basic" 
  variant="outlined"
  ...
  onChange={e => handleChange(e)}
/>

Or this instead:

<TextField 
  id="outlined-basic" 
  variant="outlined"
  ...
  onChange={handleChange}
/>

I made a codesandbox with a working example (but I omitted some parts for simplicity).

But it definetely works, you're on the right tracks: enter image description here

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

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.