0

I have some data coming from my back-end by which I am rendering my table as well as my check-boxes as they are dynamic.

What I am trying to do is initially when page loads full data is shown up but when I check one checkbox I want to show that corresponding row only and again if i unchecked all data for all unchecked box should be shown,I am using react to do this

I have multiple check-boxes

This is my data

 const data = [
{
  ol_name: "delhi",
  ol_id: "123",
  ol_Amt: "2250",
  ol_Date: "12-04-2019",
  category: "A1"
},
{
  ol_name: "jaipur",
  ol_id: "1235",
  ol_Amt: "1520",
  ol_Date: "12-5-2018",
  category: "A2"
},
{
  ol_name: "kolkata",
  ol_id: "1234",
  ol_Amt: "1126",
  ol_Date: "14-02-2019",
  category: "A1"
},
{
  ol_name: "delhi",
  ol_id: "1263",
  ol_Amt: "5523",
  ol_Date: "03-03-2019",
  category: "A2"
}

];

by this I am making my table and check boxes both, I want to filter my table by these two.

I have google around a lot and found this solutions with j query as I am new to react not getting the way to do this

Please check working code sandbox

2
  • You want to store the visible row IDs in an array using state. When a checkbox is checked, that checkboxes' ID is added to the array, when it is unchecked, the ID is removed from the array. If the array contains some IDs, only show the rows that correspond to those IDs, else show all rows. Commented Apr 16, 2020 at 10:01
  • @JMadelaine Can you help me with little example please Commented Apr 16, 2020 at 10:05

2 Answers 2

3

If you want dynamically fetch data and filters from api refer to full dynamic section at the end of answer, there is an implementation that create everything dynamically.

Static Version: Create name and category as follow

let id = 0;
const unique = prop => {
    const res = [];
    data.forEach(v => {
      if (res.findIndex(i => i[prop] === v[prop]) === -1)
        res.push({ ol_id: id++, [prop]: v[prop] });
    });
    return res;
};
const checkBoxol_name = unique("ol_name");
const checkBoxol_category = unique("category");

Then write a filter

const [filters, setFilters] = useState({
    category: [],
    ol_name: []
  });
  const filterData = () => {
    let result = data;
    Object.keys(filters).forEach(key => {
      if (filters[key].length !== 0)
        result = result.filter(item => filters[key].indexOf(item[key]) !== -1);
    });
    return result;
  };

Your tableBody should be like this

<tbody>
    {filterData().map(item => (
         <tr>
           <td>{item.ol_name}</td>
           <td>{item.ol_id}</td>
           <td>{item.ol_Amt}</td>
           <td>{item.ol_Date}</td>
           <td>{item.category}</td>
         </tr>
       ))
    }
</tbody>

change your category checkboxes as follow

<input
       type="checkbox"
       className="custom-control-input"
       id={li.ol_id}
       name={li.category}
       filter="category"
       onChange={handleChange}
       />

change your name checkboxes as follow

 <input
       type="checkbox"
       className="custom-control-input"
       id={li.ol_id}
       name={li.ol_name}
       filter="ol_name"
       onChange={handleChange}
       />

Then add handleChange method

const handleChange = e => {
    let name = e.target.name;
    let filter = e.target.getAttribute("filter");
    let checked = e.target.checked;
    if (checked) {
      let newFilter = [...filters[filter]];
      newFilter.push(name);
      setFilters({ ...filters, [filter]: newFilter });
    } else {
      setFilters({
        ...filters,
        [filter]: filters[filter].filter(item => item !== name)
      });
    }
  };

Link to the sandbox (https://codesandbox.io/s/thirsty-edison-is6zy?file=/src/App.js:987-1269).

Full Dynamic Version: For a full dynamic version do as follow

const data = [....]; // Read from API
const filterBy = [...]; // Read from API

  let id = 0;
  const unique = prop => {
    const res = [];
    data.forEach(v => {
      if (res.findIndex(i => i[prop] === v[prop]) === -1)
        res.push({ ol_id: id++, [prop]: v[prop] });
    });
    return res;
  };

  const filterGroups = {};
  let init = {};
  filterBy.forEach(item => {
    init[item] = [];
    filterGroups[item] = unique(item);
  });

  const [filters, setFilters] = useState(init);

  const filterData = () => {
    let result = data;
    Object.keys(filters).forEach(key => {
      if (filters[key].length !== 0)
        result = result.filter(item => filters[key].indexOf(item[key]) !== -1);
    });
    return result;
  };

  const handleChange = e => {
    let name = e.target.name;
    let filter = e.target.getAttribute("filter");
    let checked = e.target.checked;
    if (checked) {
      let newFilter = [...filters[filter]];
      newFilter.push(name);
      setFilters({ ...filters, [filter]: newFilter });
    } else {
      setFilters({
        ...filters,
        [filter]: filters[filter].filter(item => item !== name)
      });
    }
  };

  return (
    <div className="App">
      {filterBy.map(item => (
        <div className="container-fluid">
          <hr />
          <h5>filter with {item}</h5>
          {filterGroups[item].map(li => (
            <div key={li.ol_id} className="custom-control custom-checkbox">
              <div className="form-group each_form_group">
                <input
                  type="checkbox"
                  className="custom-control-input"
                  id={li.ol_id}
                  filter={item}
                  name={li[item]}
                  onChange={handleChange}
                />
                <label className="custom-control-label" htmlFor={li.ol_id}>
                  {li[item]}
                </label>
              </div>
            </div>
          ))}
        </div>
      ))}
      <div className="table-responsive">
        <table className="table table-bordered">
          <thead className="table-secondary">
            <tr>
              <th>Ol name</th>
              <th>Ol Id</th>
              <th>Ol Amount</th>
              <th>Ol Date</th>
              <th>Ol category</th>
            </tr>
          </thead>
          <tbody>
            {filterData().map(item => (
              <tr>
                <td>{item.ol_name}</td>
                <td>{item.ol_id}</td>
                <td>{item.ol_Amt}</td>
                <td>{item.ol_Date}</td>
                <td>{item.category}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );

Link to full dynamic version: https://codesandbox.io/s/strange-kepler-w8lgl?file=/src/App.js

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

10 Comments

Hey I have been trying your answer but it is not showing properly, as I select A1then delhi it gives me A2 also please check
@viveksingh I've fixed the problem, go and check again :)
hey that is fine but here for example I have given two filters but in real I have 5 name,category and 3 more, so writing 2 or 5 function to handle change is not good practice, and these filters are dynamic, you got my point ?
@viveksingh I've fixed this too.
@viveksingh I've also added a full dynamic version at the end of answer.
|
0

You'll need to use controlled components for the checkboxes, and then filtering the data to render.

My approach was creating an array using useState hook containing filtered rows and show only the rows matching the criteria. If no filter selected, then all rows are shown.

Updated Code:

import React from "react";
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";

const App = () => {
  const [filterRows, setFilterRows] = React.useState([]);
  const data = [
    {
      ol_name: "delhi",
      ol_id: "123",
      ol_Amt: "2250",
      ol_Date: "12-04-2019",
      category: "A1"
    },
    {
      ol_name: "jaipur",
      ol_id: "1235",
      ol_Amt: "1520",
      ol_Date: "12-5-2018",
      category: "A2"
    },
    {
      ol_name: "kolkata",
      ol_id: "1234",
      ol_Amt: "1126",
      ol_Date: "14-02-2019",
      category: "A1"
    },
    {
      ol_name: "delhi",
      ol_id: "1263",
      ol_Amt: "5523",
      ol_Date: "03-03-2019",
      category: "A2"
    }
  ];
  let i = 0;
  const checkBoxol_name = Array.from(new Set(data.map(s => s.ol_name))).map(
    test => {
      return {
        ol_name: test,
        ol_id: test + i
      };
    }
  );
  const checkBoxol_category = Array.from(
    new Set(data.map(s => s.category))
  ).map(test => {
    return {
      category: test,
      ol_id: test + i
    };
  });
  console.log(checkBoxol_name);

  const handleToggleFilter = event => {
    const id = event.target.name;
    if (filterRows.includes(id)) {
      return setFilterRows(filterRows.filter(_id => id !== _id));
    }
    return setFilterRows([...filterRows, id]);
  };

  console.log(filterRows);

  const hasRowBeenFiltered = (row) => {
    if(filterRows.length === 0) {
      return true;
    }

    return filterRows.includes(`${row.ol_name}${i}`) || filterRows.includes(`${row.category}${i}`)
  }

  return (
    <div className="App">
      <div className="container-fluid">
        <hr />
        <h5>filter with category</h5>
        {checkBoxol_category.map(li => (
          <div key={li.ol_id} className="custom-control custom-checkbox">
            <div className="form-group each_form_group">
              <input
                type="checkbox"
                className="custom-control-input"
                id={li.ol_id}
                name={li.ol_id}
                checked={filterRows.includes(li.ol_id)}
                onChange={handleToggleFilter}
              />
              <label className="custom-control-label" htmlFor={li.ol_id}>
                {li.category}
              </label>
            </div>
          </div>
        ))}
        <hr />
        <h5>filter with ol name</h5>
        {checkBoxol_name.map(li => (
          <div key={li.ol_id} className="custom-control custom-checkbox">
            <div className="form-group each_form_group">
              <input
                type="checkbox"
                className="custom-control-input"
                id={li.ol_id}
                name={li.ol_id}
                checked={filterRows.includes(li.ol_id)}
                onChange={handleToggleFilter}
              />
              <label className="custom-control-label" htmlFor={li.ol_id}>
                {li.ol_name}
              </label>
            </div>
          </div>
        ))}
      </div>
      <div className="table-responsive">
        <table className="table table-bordered">
          <thead className="table-secondary">
            <tr>
              <th>Ol name</th>
              <th>Ol Id</th>
              <th>Ol Amount</th>
              <th>Ol Date</th>
              <th>Ol category</th>
            </tr>
          </thead>
          <tbody>
            {data
              .filter(hasRowBeenFiltered)
              .map(item => (
                <tr>
                  <td>{item.ol_name}</td>
                  <td>{item.ol_id}</td>
                  <td>{item.ol_Amt}</td>
                  <td>{item.ol_Date}</td>
                  <td>{item.category}</td>
                </tr>
              ))}
          </tbody>
        </table>
      </div>
    </div>
  );
};

export default App;

https://codesandbox.io/s/loving-perlman-dshsr

3 Comments

I fixed it! Sorry, it didn't save.
Hey it shows wrong data .. please check when I click on kolkata it shows all other then kolkata , you are doing it totally opposite like on click of A1 i should see A1 only you are showing all others rather then A1
hey when I select A1 and then select delhi the output is giving me delhi of A2 also, this is not I am trying to do

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.