Home > Back-end >  I am trying to render a filtered list of objects
I am trying to render a filtered list of objects

Time:08-03

I have a sample list of which is an array of objects with three fields in the App component. The list is passed as a prop to an "booksearch" component which handles the logic to search and filter the list based on search text. below is the JSX which renders the book. I am doubting issue is with the "matcheBook" method.

<div className="output-container">
    {this.props.books
        .filter((e) => this.matchesBook(e))
        .map((b) => (
            <div className="output-card" key={b.title}>
                {Object.entries(b).map(([k, v]) => (
                    <div key={v} className="out-section">
                        <span className="heading">
                            <b>{k}</b>
                        </span>
                       <span className="details">{v}</span>
                    </div>
                ))}
          </div>
       ))}
</div>

method for handling the search text

handleChange(evt, name) {
    let searchText = evt.target.value;
        this.setState((state) => ({
            ...state,
            fields: {
                ...state.fields,
                [name]: searchText
        }
    }));
}

filtering logic

matchesBook(book) {
    const { fields } = this.state;
        return Object.entries(book).some(
            ([k, v]) =>
                !fields[k] ||
                v.toString()
                 .toLowerCase()
                 .includes(fields[k].toString().trim().toLowerCase())
           );
}

State shape

this.state = {
    fields: initialFields
};

"initialFields" comes from below

const fieldsArray = ["author", "title", "year"];

const initialFields = fieldsArray.reduce(
    (a, e) => ({
        ...a,
        [e]: ""
      }),
    {}
 );

codesandbox

CodePudding user response:

I've never tried some() function, but doing the search function code on my own way I modified your matchesBook function into this one:

matchesBook(book) {
  const { fields } = this.state;

  let matching = 0;

  for (let i = 0; i < Object.entries(fields).length; i  ) {
    if (Object.entries(fields)[i][1] === "") {
      matching  ;
    } else {
      if(String(Object.entries(book)[i][1]).toLowerCase().includes(String(Object.entries(fields)[i][1]).toLowerCase())){
        matching  ;
      }
    }
  }
  return matching === Object.entries(fields).length;
}

Try it, it'll work!

CodePudding user response:

According to MDN some() method executes the callbackFn function once for each element present in the array until it finds the one where callbackFn returns a truthy value (a value that becomes true when converted to a Boolean). If such an element is found, some() immediately returns true.

In your case !fields[k] always return true when its value is "" and so it never have to compare succeeding values in the array which contains the field we are checking, in this case year. Please see example below.

const book = {
    author: "Charles Dickens",
    title: "The Pickwick Papers",
    year: "1837"
  };

const fields = {author: "", title: "", year: "lookinforthisstringinbook"};

const checkValue = Object.entries(book).some(
    ([k, v]) =>
        !fields[k] || // --> always returns true
        v.toString()
         .toLowerCase()
         .includes(fields[k].toString().trim().toLowerCase())
   );

console.log(checkValue)

  • Related