1

When I click on the button under Show column, for example Potato Soup it selects in gray all the row, and when I click on Apply button then the row is hidden (ok this is what I want). BUT when I tried to do, after, the same trick with Pea Soup, the row doesn't turn into gray, it is directly hidden. But I want the gray line to appear also for my second selection.

It just goes away when you click on the Apply button. Do you see why is it working for the first selection and not the second one ?

export default function MenuDisplay() {
  const { menuId } = useParams();
  const { match } = JsonData;

  const [hideSelected, setHideSelected] = useState(false);
  const [selected, setSelected] = useState({});

  const rowSelectHandler = (id) => (checked) => {
    setSelected((selected) => ({
      ...selected,
      [id]: checked
    }));
  };

  const toggleShow = () => setHideSelected((hide) => !hide);

  const matchData = (
    match.find((el) => el._id_menu === menuId)?._ids ?? []
  ).filter(({ _id }) => {
    if (hideSelected) {
      return !selected[_id];
    }
    return true;
  });

  const getRowProps = (row) => {
    return {
      style: {
        backgroundColor: selected[row.values.id] ? "lightgrey" : "white"
      }
    };
  };

  const data = [
    {
      Header: "id",
      accessor: (row) => row._id
    },
    {
      Header: "Name",
      accessor: (row) => (
        <Link to={{ pathname: `/menu/${menuId}/${row._id}` }}>{row.name}</Link>
      )
    },
    {
      Header: "Description",
      //check current row is in hidden rows or not
      accessor: (row) => row.description
    },
    {
      Header: "Dishes",
      //check current row is in hidden rows or not
      accessor: (row) => row.dishes,
      id: "dishes",
      Cell: ({ value }) => value && Object.values(value[0]).join(", ")
    },
    {
      Header: "Show",
      accessor: (row) => (
        <Toggle
          value={selected[row._id]}
          onChange={rowSelectHandler(row._id)}
        />
      )
    }
  ];

  const initialState = {
    sortBy: [
      { desc: false, id: "id" },
      { desc: false, id: "description" }
    ],
    hiddenColumns: ["dishes", "id"]
  };

  return (
    <div>
      <Button primary onClick={toggleShow}>
        {hideSelected ? "Cancel" : "Apply"}
      </Button>
      <Table
        data={matchData}
        columns={data}
        initialState={initialState}
        withCellBorder
        withRowBorder
        withSorting
        withPagination
        rowProps={getRowProps}
      />
    </div>
  );
}

Here a picture to get the idea: enter image description here

Here is the CodeSandbox

Zokulko
  • 211
  • 4
  • 25
  • 1
    Your CodeSandbox does not work. When I click the table items, the page breaks. – Gasim Jun 17 '22 at 10:26
  • Yeah, work on your CodeSandbox - the Apply button doesn't even render. – Squiggs. Jun 17 '22 at 10:30
  • Sorry I've modified the [link](https://codesandbox.io/s/react-table-hide-rows-in-table-reset-button-to-display-hidden-rows-yq8vur?file=/src/MenuDisplay.jsx) – Zokulko Jun 18 '22 at 13:09
  • 1
    @Zokulko The desired logic is unclear, and it is also unclear how your app is not working as expected. You should edit your question to clarify so we can help you – Son Nguyen Jun 20 '22 at 11:40
  • @SonNguyen, thank you I've modified the question – Zokulko Jun 20 '22 at 12:00

2 Answers2

1

This is a working solution of what you want to achieve: Codesanbox.

Basically, you need two states for each of your items to determine if it is selected, and if it is hidden. An item is only selected when it is, well, selected by clicking the button in the last column. Only when you press Apply is it actually hidden (and as an extra, clear all selection).

const [hidden, setHidden] = useState({});
//...

const handleClick = () => {
  if (/* Hide item */) {
    // Hide currently selected items
    const currentlySelected = {};
    Object.entries(selected).forEach(([id, isSelected]) => {
      if (isSelected) {
        currentlySelected[id] = isSelected;
      }
    });
    setHidden({ ...hidden, ...currentlySelected });

    // Clear all selection
    const newSelected = {};
    Object.keys(selected).forEach((id) => {
      newSelected[id] = false;
    });
    setSelected(newSelected);
  }
};

When you need to show the hidden items, you do the reverse: Change their state from hidden to selected (pre-select them for easy toggling).

const handleClick = () => {
  if (/* Show item */) {
    // Select all currently hidden items
    const currentlyHidden = {};
    Object.entries(hidden).forEach(([id, isHidden]) => {
      if (isHidden) {
        currentlyHidden[id] = isHidden;
      }
    });
    setSelected({ ...selected, ...currentlyHidden });

    // Clear all hidden items
    const newHidden = {};
    Object.keys(hidden).forEach((id) => {
      newHidden[id] = false;
    });
    setHidden(newHidden);
  }
};

With these two states, you don't need the hideSelected flag anymore, so remove it. Now the question becomes, when should the button becomes Apply, and when should it be Cancel? In my example, the button displays Apply (and hide the selected rows) only if at least one row is selected, else it would display Cancel (and show the hidden rows on click).

// If any row is selected, the button should be in the Apply state
// else it should be in the Cancel state
const buttonMode = Object.values(selected).some((isSelected) => isSelected)
  ? 'apply'
  : 'cancel';

Now we have the final solution. If you are still confused about this, leave a comment and I will reply.

Son Nguyen
  • 1,472
  • 8
  • 16
  • Hello, thank you very much for this explanation, it has been days I was on it...I've opened other [issue1](https://stackoverflow.com/questions/72686224/react-post-data-not-working-when-i-submit) related to the same jsx file and [here](https://stackoverflow.com/questions/72672391/react-display-data-in-table-with-condition). I also have an [issue bounty](https://stackoverflow.com/questions/72517068/not-able-to-display-data-string-from-api-with-react-wysiwyg). If you have time to check please thanks again! – Zokulko Jun 20 '22 at 17:07
  • I've also opened a [bounty issue 1](https://stackoverflow.com/questions/72656682/react-how-to-set-enddate-same-as-startdate-by-default-but-control-if-enddate-no) and [bounty issue 2](https://stackoverflow.com/questions/72686224/react-post-data-not-working-when-i-submit) – Zokulko Jun 28 '22 at 17:05
1

It is happening because of the value of hideSelected. When you click on show for first time hideSelected is false. The id of the item is stored as selected={ [id]: true }. Now when you click Apply the hideSelected becomes true and your selected row is hidden. Now when you click on show for second time value of hideSelcted is already true so your matchData function will directly filter that row out and it will be hidden.

Kalpesh
  • 51
  • 3