CarlosNZ / json-edit-react

React component for editing/viewing JSON/object data
https://carlosnz.github.io/json-edit-react/
MIT License
183 stars 18 forks source link

Missing "onCollapse/onExpand" events #99

Closed MattChowski closed 3 months ago

MattChowski commented 4 months ago

We have the collapse prop at the moment which renders the JSON viewer either collapsed or expanded or to user's liking depth.

I tried to create a "hide all" and "expand all" button, and I kinda have it working, here's the scenario that fails to work:

  1. Render the json viewer
  2. Press "expand all", everything expands, all good here
  3. Collapse some random json objects/properties
  4. Press "expand all" again, nothing happens because the state is already in expanded state, even though I collapsed a few values.

Here's my short code for this mechanism:

  const [collapsed, setCollapsed] = useState<number | boolean>(collapse);

  const handleCollapse = () => {
    setCollapsed(true);
  };

  const handleExpand = () => {
    setCollapsed(false);
  };

Would you have any solution for this as well?

Workaround: force a re-render of the component on button click.

Potential solution: Add a onCollapse/onExpand event where we could set the state to be "indeterminate"

Thanks in advance!

CarlosNZ commented 4 months ago

I think I see what you mean. You should be able to set the collapse prop to either 0 or Infinity to get it to collapse or expand everything. I just tried it, and it mostly works, except for the situation you describe when inner nodes have been closed after expanding all, they don't get re-expanded.

This is just because the Infinity value doesn't change, so doesn't trigger a re-render.

What I did as a quick workaround is instead of setting Infinity on Expand, I just set a very large random number (anything higher than the depth of your data) and that works nicely:

2024-07-25 00 07 03

It's slightly hacky, but I think it does the job. I'd have to think a bit more as to how I'd like to make this "less hacky" without cluttering it up with more and more obscure props.

CarlosNZ commented 4 months ago

What I did as a quick workaround is instead of setting Infinity on Expand, I just set a very large random number (anything higher than the depth of your data) and that works nicely

Slightly more elegant would be to just set the collapse value to a high number, then just increment that number every time it's clicked again (then reset it after a collapse all).

<Button onClick={() => setCollapseDepth(0)}>
  Collapse all
</Button>
<Button onClick={() => setCollapseDepth(collapseDepth > 0 ? collapseDepth + 1 : 1000 )}
>
  Expand all
</Button>
CarlosNZ commented 4 months ago

Good to point this out though. I might add this to the online Demo to show how it can be done.

MattChowski commented 4 months ago

thanks again for the tip! That works for me for now.

Wouldn't it be overall better for the final library to expose an onCollapseExpand event that would fire each time a user collapses or expands something?

CarlosNZ commented 4 months ago

Wouldn't it be overall better for the final library to expose an onCollapseExpand event that would fire each time a user collapses or expands something?

Maybe, but I'm not sure how that would help in this situation. The onCollapseExpand could tell you when something changed, but you'd still need to modify the collapse prop to actually change the component from outside it.