Filth
Filth

Reputation: 3228

React JS Filters not rendering items in table

enter image description here

I have a table onLoad that renders my data fine, it's when I interact with the inputs above each column that handle the filtering is the problem. If I enter any value nothing displays.

I'm handling the onChange for the inputs in a single function called filterBySearch which captures the event.

Here's my function and filtering logic - I suspect this is where I'm doing wrong:

const filterBySearch = (e) => {
  const { name, value } = e.target;
  setFilters({ ...filters, [name]: value });

  //Take copy of current list
  let updatedList = [...data];
  //Filter logic
  updatedList = rows.filter((document) => {
    return (
      document.documentAuthor
        ?.toLowerCase()
        .includes(filters.documentAuthor.toLowerCase()) &&
      document.documentName
        ?.toLowerCase()
        .includes(filters.documentName.toLowerCase()) &&
      document.documentSource
        ?.toLowerCase()
        .includes(filters.documentSource.toLowerCase()) &&
      document.featureId?.includes(filters.featureId)
    );
  });

  // Trigger render with updated values
  setRows(updatedList);
};

Edit Testing filters logic

Upvotes: 0

Views: 623

Answers (2)

Apostolos
Apostolos

Reputation: 10463

Many issues here

  1. You want to use the newly created filters but since react is asynchronous, you are filtering with previously typed value. I used a local variable for that.
  2. I changed the checks to include also empty spaces.
  3. You filter the data but then you assign the value inside updatedList so filter is done in a non-reversible list. You should use the original data always.

updatedList = rows.filter((document) => { and then setRows(updatedList);

    const filterBySearch = (e) => {
    const { name, value } = e.target;

    let newFilters = { ...filters, [name]: value };
    setFilters(newFilters);

    console.log(data);
    //Take copy of current list
    let updatedList = data.filter((document) => {
      return (
        (newFilters.documentAuthor === "" ||
          (newFilters.documentAuthor &&
            document.documentAuthor
              ?.toLowerCase()
              .includes(newFilters.documentAuthor.toLowerCase()))) &&
        (newFilters.documentName === "" ||
          (newFilters.documentName &&
            document.documentName
              ?.toLowerCase()
              .includes(newFilters.documentName.toLowerCase()))) &&
        (newFilters.documentSource === "" ||
          document.documentSource
            ?.toLowerCase()
            .includes(newFilters.documentSource.toLowerCase())) &&
        (newFilters.featureId === "" ||
          document.featureId?.includes(newFilters.featureId))
      );
    });

    // Trigger render with updated values
    setRows(updatedList);
    };

demo

Upvotes: 2

user20386762
user20386762

Reputation: 177

You don't want to overwrite your original data, so instead do this:

const Component = ({ rows }) => {
  const [rowState, setRowState] = useState(rows)
  const [cachedRows, setCachedRows] = useState(rows)
  // Rest of the implementation
}

and when filtering, you'll want to do this:

const filteredList = cachedRows.filter(...)
setRowState(filteredList)

Then, just give rowState to the table. This way, you'll always filter the original list without modifying it.

Upvotes: -1

Related Questions