0

I'm currently new in react js and I want to implement a Search in react on array. What I'm trying to do is implement search functionality so that when the user enters in 'E' in "textbox", he/she should see only the names that contain the character 'E' and luckily its working fine till here. Ideally I want that When a user start taking a step back by pressing Backspace or Deleting entered character(s), the list of names should get loaded back with all non matching values and vice versa. Apart, I also I want to disable spacebar in textbox with an alert message when entering spacebar in textbox. And on clicking 'OK' of an alert message the screen that comes after should be same like as it was before entering spacebar(With all names loaded and "textbox" asking user to enter something).

What my code is providing only names matching with the first character even "textbox" is empty and In case of spacebar, its allowing to take next input(just after spacebar) after clicking on alert message's 'OK'. I think its taking spacebar as input.

My code's functionality is neither rolling back of names on Backspace or Deleting a character nor a screen is setting to the same as it was before entering spacebar. I'm getting my desired results by refreshing a tab which I don't want to do. Please help me to resolve the issue

My code is something like as below:

import React from 'react';
import NameItem from "./component/NameItem";

class App extends React.Component {
    constructor(props) {
    super(props)
    this.state = { term: '', names: ["Elon Musk","Bill Gates","Tim Cook","Richard Branson","Jeff Bezos","Warren Buffet","The Zuck","Carlos Slim","Bill Gates","Larry Page","Harold Finch","Sergey Brin","Jack Ma","Steve Ballmer","Phil Knight","Paul Allen","Woz"], filteredData:[] };
}
    renderData(filteredData) {
        if(filteredData) {
            this.setState({names: filteredData});
        }
        return filteredData.map(item => <NameItem item={item}></NameItem>);

    }

    filterNames(namePass) {
         if(namePass && this.state.names) {
             if(namePass === ' ') {
            alert('please dont enter space.')
            return;             
            }
             let filteredData = this.state.names.filter((item) => {
                return  item.toLowerCase().startsWith(namePass.toLowerCase())
             });
             console.log(filteredData);
             this.setState({filteredData: filteredData});
             if (filteredData) {
                 this.renderData(filteredData);
             }
         }
         }
        render() {
        return (
            <>
                <div>
                    <label>Search Person: </label>
                    <input type="text" id="searchEmp"
                           placeholder="Enter Person's Name"
                           onChange={(event) => {
                               this.setState({term: event.target.value});
                               this.filterNames(event.target.value);
                    }}/><br/>
                </div>
                <ul>
                    <NameItem item={this.state.names}></NameItem>
                    {
                    }
                </ul>
            </>
        );
    }
}
export default App;
2
  • You are manipulating the main array that's why you are not getting results Don't manipulate the original Array name Make a copy of that array and try maniplation then it will work Commented Feb 28, 2021 at 17:40
  • or just comment these lines if(filteredData) { this.setState({names: filteredData}); } Commented Feb 28, 2021 at 17:41

1 Answer 1

1

I would recommend that you don't store the filteredData in the state but that's just a preference. You already have the term stored so you can map to the filtered values in your render().

What you absolute cannot do is override this.state.names with just the filtered names, which you are doing here:

if(filteredData) {
  this.setState({names: filteredData});
}

When you do that you lose every name which isn't in the filtered array, so you cannot possibly go backwards and show the full list again.

There's no point in setting this.state.name to filteredData because you just render filteredData directly.

class App extends React.Component {
  // don't actually need a constructor if there are no props
  // can initialize state like this
  state = {
    term: "",
    names: ["Elon Musk","Bill Gates","Tim Cook","Richard Branson","Jeff Bezos","Warren Buffet","The Zuck","Carlos Slim","Larry Page","Harold Finch","Sergey Brin","Jack Ma","Steve Ballmer","Phil Knight","Paul Allen","Woz"]
  };

  render() {
    const filteredData = this.state.names.filter(
      (name) =>
        // match all names if term is empty
        this.state.term === "" ||
        // otherwise see if the name starts with the term
        name.toLowerCase().startsWith(this.state.term.toLowerCase())
    );
    return (
      <>
        <div>
          <label>Search Person: </label>
          <input
            type="text"
            id="searchEmp"
            placeholder="Enter Person's Name"
            value={this.state.term} // make this a controlled input, prevents space from showing
            onChange={(event) => {
              if ( event.target.value.endsWith(' ')) {
                alert('Please don\'t enter space.');
              } else {
                this.setState({ term: event.target.value });
              }
            }}
          />
        </div>
        <div>Showing {filteredData.length} Matches</div>
        <ul>
          {filteredData.map((name) => (
            <li
              key={name} // should have a key when using map
            >
              {name}
            </li>
          ))}
        </ul>
      </>
    );
  }
}

Note: I had some strange behavior due to using the name as the key because you had "Bill Gates" in the list twice. I deleted the duplicate item and now it's fine. But keys must be unique, so do not use the name as the key if there is a chance of duplicates.

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

1 Comment

@LindaPaiste-many thanks for the help. It worked well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.