2

Before implementing the custom filter options, the temperature (of type Number) was displayed as a string with the "° C" appended to it, but still held the value, as it was able to be sorted accordingly (ascending and descending). After implementing the custom filter options, I am no longer able to filter based on the value but it filters based on the string that is returned from customBodyRender. For example, if I specify a minimum value as 3, values like 20 and 10 will not be returned, as it seems like it's now sorting alphanumerically. When I remove the customBodyRender, it works perfectly.

How can I get the MUI Data table to render the way I'd like it to, while preserving the sorting of the actual value itself? I pasted the code below. Being that I'm new to react, I will continue to do more research and update the question over time.

const columns = [
    {name: "Temperature", options:{
      filter: true,
      customBodyRender: (value) => {
        return (value + "° C")
      },
      filterType: 'custom',
      filterList: [],
      customFilterListOptions: {
        render: value => {
          if (value[0] && value[1]) {
            return `Min Temp: ${value[0]}, Max Temp: ${value[1]}`;
          } else if (value[0]) {
            return `Min Temp: ${value[0]}`;
          } else if (value[1]) {
            return `Max Temp: ${value[1]}`;
          }
          return false;
        },
        update: (filterList, filterPos, index) => {
          console.log('customFilterListOnDelete: ', filterList, filterPos, index);

          if (filterPos === 0) {
            filterList[index].splice(filterPos, 1, '');
          } else if (filterPos === 1) {
            filterList[index].splice(filterPos, 1);
          } else if (filterPos === -1) {
            filterList[index] = [];
          }

          return filterList;
        },
      },
      filterOptions: {
        names: [],
        logic(value, filters) {
          if (filters[0] && filters[1]) {
            return (value < filters[0]) || value > filters[1];
          } else if (filters[0]) {
            return value < filters[0];
          } else if (filters[1]) {
            return value > filters[1];
          }
          return false;
        },
        display: (filterList, onChange, index, column) => (
          <div>
            <FormLabel>Temperature</FormLabel>
            <FormGroup row>
              <TextField
                label="min"
                value={filterList[index][0] || ''}
                onChange={event => {
                  filterList[index][0] = event.target.value;
                  onChange(filterList[index], index, column);
                }}
                style={{ width: '45%', marginRight: '5%' }}
              />
              <TextField
                label="max"
                value={filterList[index][1] || ''}
                onChange={event => {
                  filterList[index][1] = event.target.value;
                  onChange(filterList[index], index, column);
                }}
                style={{ width: '45%' }}
              />
            </FormGroup>
          </div>
        ),
      },
    }}
]

2 Answers 2

1

I found two little problems in your code.

First one: The render function in customFilterListOptions should return a string or string[] (see documentation). Second one: In the logic function of filterOptions it was necessary to convert values and filters to numbers before comparing them.

If you have any questions, let me know.

This shall work now:

import React from "react";
import ReactDOM from "react-dom";
import MUIDataTable from "mui-datatables";
import { TextField, FormLabel, FormGroup } from "@material-ui/core";
import { toNumber } from "lodash";

import "./styles.css";

const TEMPERATURE_PREFIX = "° C";

function App() {
  const columns = [
    {
      name: "city",
      label: "City",
      options: {
        filter: true,
        sort: false
      }
    },
    {
      name: "temp",
      label: "Temperature",
      options: {
        sort: true,
        customBodyRender: value => {
          return value + TEMPERATURE_PREFIX;
        },
        filter: true,
        filterType: "custom",
        filterList: [],
        customFilterListOptions: {
          render: value => {
            if (value[0] && value[1]) {
              return `Min Temp: ${value[0]}, Max Temp: ${value[1]}`;
            } else if (value[0]) {
              return `Min Temp: ${value[0]}`;
            } else if (value[1]) {
              return `Max Temp: ${value[1]}`;
            }
            return [];
          },
          update: (filterList, filterPos, index) => {
            console.log(
              "customFilterListOnDelete: ",
              filterList,
              filterPos,
              index
            );

            if (filterPos === 0) {
              filterList[index].splice(filterPos, 1, "");
            } else if (filterPos === 1) {
              filterList[index].splice(filterPos, 1);
            } else if (filterPos === -1) {
              filterList[index] = [];
            }

            return filterList;
          }
        },
        filterOptions: {
          names: [],
          logic(value, filters) {
            const temperature = toNumber(
              value.replace(TEMPERATURE_PREFIX, "")
            );
            const lower = toNumber(filters[0]);
            const upper = toNumber(filters[1]);
            if (lower && upper) {
              return temperature < lower || temperature > upper;
            } else if (lower) {
              return temperature < lower;
            } else if (upper) {
              return temperature > upper;
            }
            return false;
          },
          display: (filterList, onChange, index, column) => (
            <div>
              <FormLabel>Temperature</FormLabel>
              <FormGroup row>
                <TextField
                  label="min"
                  value={filterList[index][0] || ""}
                  onChange={event => {
                    filterList[index][0] = event.target.value;
                    onChange(filterList[index], index, column);
                  }}
                  style={{ width: "45%", marginRight: "5%" }}
                />
                <TextField
                  label="max"
                  value={filterList[index][1] || ""}
                  onChange={event => {
                    filterList[index][1] = event.target.value;
                    onChange(filterList[index], index, column);
                  }}
                  style={{ width: "45%" }}
                />
              </FormGroup>
            </div>
          )
        }
      }
    }
  ];

  const data = [
    { city: "Yonkers", temp: 3 },
    { city: "Hartford", temp: 11 },
    { city: "Tampa", temp: 25 },
    { city: "Dallas", temp: 30 }
  ];

  const options = {
    filterType: "checkbox"
  };

  return (
    <div className="App">
      <MUIDataTable
        title={"Employee List"}
        data={data}
        columns={columns}
        options={options}
      />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

(https://codesandbox.io/s/competent-kirch-uc01b)

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

2 Comments

Awesome, this worked! Thank you. Understand what went wrong now
is the returning value of render() string or JSX.Element?
0

in the options add the code below.

options={{
  sort: true,
  sortOrder: { name: 'id', direction: 'desc' },
}}

Comments

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.