user13856242
user13856242

Reputation:

Filter Table using Javascript ES6

I need some help actually I am using Material UI & React and need to have two implementation that is

  1. I need to have a Filter that filter out all the rows that is present (I need filter for each Column) Image is attached below.
  2. I need a button that adds the same in the row (Image attached )

Code are as follow

import React from 'react';
import {
  Typography,
  Table,
  TableHead,
  TableRow,
  TableCell,
  TableContainer,
  TableBody,
  Button
} from '@material-ui/core';


const Table = props => {
  const { columnHeaders, data } = props;
  return (
    <>
      <TableContainer >
        <Table>
          <TableHead>
            <TableRow >
              {columnHeaders.map((k, index) => (
                <TableCell
                  key={k}
                  className={'product-line-tablehead '}
                  style={{
                    width: `${100 / columnHeaders.length}%`
                  }}
                >
                  {k.title}
                </TableCell>
              ))}
            </TableRow>
          </TableHead>
          <TableBody>
            {data.map((k, index) => (
              <TableRow key={index}>
                <TableCell>
                  <Typography variant='body1'
                  >
                    {k.Product}
                  </Typography>
                </TableCell>
                <TableCell>
                  <Typography
                  >
                    {k.Code}
                  </Typography>
                </TableCell>
                <TableCell>
                  <Typography
                  >
                    {k.Branding}
                  </Typography>
                </TableCell>
                <TableCell align='center'>
                  <Typography
                  >
                    <img
                      src={DeleteIcon}
                    />
                    <Button                          
                    >
                      Clear
                    </Button>
                  </Typography>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    </>
  );
};

export default Table;

where i am getting the value and the parent component is something like this

 import React, { useEffect } from 'react';
    import { Grid, Typography } from '@material-ui/core';
    import Table from './Table';
    
    const mocklabels = [
      {
        title: 'Teacher',
        link: ''          },
      {
        title: 'Student',
        link: ''          }
    ];
    
    const columnHeaders = [
      {
        title: 'Name'
      },
      {
        title: 'Class'
      },
      {
        title: 'Gender'
      },
      {
        title: ''
      }
    ];
    const data = [
      {
        Product: 'Lorum Ipsum Dolar',
        Code: 'Lorum Ipsum Dolar',
        Branding: 'Lorum Ipsum Dolar'
      },
      {
        Product: 'Lorum Ipsum Dolar',
        Code: 'Lorum Ipsum Dolar',
        Branding: 'Lorum Ipsum Dolar'
      }
    ];
    
        
      );
    };
    

;

Image 1

enter image description here

Image 2

enter image description here

Image 3

enter image description here

Image 4

enter image description here

Upvotes: 1

Views: 732

Answers (1)

Mujeeb Qureshi
Mujeeb Qureshi

Reputation: 500

Starting out, whenever you want to 'filter' an array of items in a React App based on a condition(s). Please make sure to save an original copy of the data. This is absolutely important since once the filters are removed, you'd probably want to go back to display the original data.

const [mainData, setMainData] = useState(data); //orignial array
const [appData, setAppData] = useState(data.slice()); //copied array that is rendered

With that being said, your use case requires you to toggle a filtering option on the table headers and based on which column the filter is applied to, you need to filter the items on that property.

You seemed to have used an array of columns to render the table headers, so I just added an additional property of 'key' on each object. This property's value should match the property on the object that is rendered out as a table row.

const columnHeaders = [
    {
        title: "Product Name",
        key: "Product", //should match your data's object key
        value: ""
    },
    {
        title: "Product Name",
        key: "Code", //should match your data's object key
        value: ""
    },
    {
        title: "Product Name",
        key: "Branding", //should match your data's object key
        value: ""
    },
    {
        title: ""
    }
];

Table headers should now render like this:

<TableRow>
  {props.tableHeaders.map((k, index) => (
    <TableCell
      key={index}
      className={"product-line-tablehead "}
      style={{
        width: `${100 / props.tableHeaders.length}%`
      }}
    >
      {k.title ? (
        <>
          <h3>{k.title}</h3>
          {props.isSearching && (
            <Input
              value={k.value}
              onChange={(e) => {
                props.handleHeaderChange(e, index, k.key);
              }}
            />
          )}
        </>
      ) : props.isSearching ? (
        <CancelIcon
          onClick={() => {
            props.setSearching(false);
          }}
        />
      ) : (
        <SearchIcon
          onClick={() => {
            props.setSearching(true);
          }}
        />
      )}
    </TableCell>
  ))}
</TableRow>

Next, the onChange handler handleHeaderChange(e, index, k.key); is responsible to trigger the filtering on the table's records. The implementation should be as follows:

const handleHeaderChange = (e, index, prop) => {
    
    tableHeaders[index].value = e.target.value;
    
    setTableHeaders(tableHeaders);
    
    let _newAppData = mainData.filter((f) => {
      let _condition = tableHeaders
        .filter((h) => h.value)
        .map((a) => {
          let _obj = f[a.key];
          return (
            _obj !== undefined &&
            _obj.toString().toLowerCase().indexOf(a.value.toLowerCase()) >= 0
          );
        });
      return _condition.indexOf(false) >= 0 ? false : true;
    });

    setAppData(_newAppData);
};

So in here, we are just filtering the original data by iterating over header input values and associating to the respective object property value. f is each item in the data array, a is each item on the header array which has key (that is the name of the property on f) and value that is the filter input of that column.

_condition is an array of boolean values and _condition.indexOf(false) >= 0 ? false : true; simply signifies an AND condition.

full code can be found here: https://codesandbox.io/s/trusting-sound-5lo12z?file=/src/App.js:564-667

Upvotes: 1

Related Questions