Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using ContextMenu2 with table rows #4619

Closed
vladimir-djokic opened this issue Apr 5, 2021 · 9 comments
Closed

Using ContextMenu2 with table rows #4619

vladimir-djokic opened this issue Apr 5, 2021 · 9 comments
Assignees
Milestone

Comments

@vladimir-djokic
Copy link

vladimir-djokic commented Apr 5, 2021

With ContextMenu I had the ability to use "imperative" API when working with table rows:

Something like...

const handleContextMenu = (rowData: MyData) =>
  (): void => {
    // [1] Do something with rowData, like 'selectMyRow(rowData)' which then changes the rows color...
    // [2] Now show context menu
   ContextMenu.show(...)
};

<tr onContextMenu={handleContextMenu(rowData)}>
</tr>

How can I achieve something like that with ContextMenu2?

If I wrap entire table with ContextMenu2 then I would need to drill down using React/HTML API in order to get the data associated with the row I right-clicked on.

@adidahiya
Copy link
Contributor

did you try this?

const getRowContextMenuHandler = (rowData: MyData) => () => {
  // Do something with rowData, like 'selectMyRow(rowData)' which then changes the rows color...
};
const getRowContextMenu = (rowData: MyData) => {
  // return menu content here
};

return (
  <ContextMenu2 content={getRowContextMenu(rowData)} onContextMenu={getRowContextMenuHandler(rowData)}>
    <tr>{...}</tr>
  </ContextMenu2>
);

@vladimir-djokic
Copy link
Author

vladimir-djokic commented Apr 6, 2021

Given your example, and as I understand <ContextMenu2> from glancing at the source code - won't that produce invalid <table> markup, because each <tr> will be wrapped by <div>?

So instead of (which is valid HTML table markup):

<table>
  <tbody>
    <tr>...</tr> <!--  onContextMenu={handleContextMenu(rowData)} -->
    <tr>...</tr> <!--  onContextMenu={handleContextMenu(rowData)} -->
    <tr>...</tr> <!--  onContextMenu={handleContextMenu(rowData)} -->
    ...
  </tbody>
</table>

Your example would result in something like (which is invalid markup):

<table>
  <tbody>
    <div> <!-- This div is a result of `<ContextMenu2>` -->
      <tr>...</tr>
    </div>
    <div> <!-- This div is a result of `<ContextMenu2>` -->
      <tr>...</tr>
    </div>
    <div> <!-- This div is a result of `<ContextMenu2>` -->
      <tr>...</tr>
    </div>
    ...
  </tbody>
</table>

Also, wrapping each row with <ContextMenu2> fells like a overkill.

@adidahiya
Copy link
Contributor

Ok, then you can try flipping the DOM ordering:

<tr>
  <ContextMenu2 ...>
</tr>

Also, wrapping each row with fells like a overkill.

By what metric? Each context menu has different information about the row, so this is fairly idiomatic React IMO. There may be a separate feature request here for having ContextMenu2 not generate a wrapper element (similar to how Popover2's renderTarget prop lets you do the same), if you really want to simplify the DOM structure.

@vladimir-djokic
Copy link
Author

Ok, then you can try flipping the DOM ordering:

<tr>
  <ContextMenu2 ...>
</tr>

Won't that result in invalid HTML markup as well?

<tr>
  <div> <!-- This div is a result of `<ContextMenu2>` -->
    <td>Cell 1</td>
    <td>Cell 2</td>
    <td>Cell 3</td>
  </div>
</tr>

@adidahiya
Copy link
Contributor

Hm, you're right. I will need to spend some more time thinking about this... I'll make sure to figure out a way to support this use case before the final 4.0.0 release.

@adidahiya
Copy link
Contributor

I added a new API in #4635 which should address the problem here, it will allow you to omit the <div>. It will need to be ported from the v4 branch to develop.

@vladimir-djokic
Copy link
Author

Thank you! I'm personally fine with this being 4.0 only feature as <ContextMenu> + ContextMenu.show(...) still works fine for 3.x.

@adidahiya
Copy link
Contributor

ported to develop and fixed by #4640

@domehead100
Copy link

It is idiomatic React in one way of thinking, but it is also idomatic React that an event handler, such as onContextMenu is handled by a function or method such as ContextMenu.show(...).

Not having an imperative option adds inefficiency in the case of large collections (even in a virtualized table wrapping every cell in a ContextMenu2 increases scrolling jankiness because you're asking the virtual dom to do a lot more work).

I think it's a mistake not to have an imperative option, and seems that they way you've designed it that is truly not an option because the isOpen prop is gone and is only now passed to the content as a read-only prop rather than being controllable from the outside.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants