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

Click on table: Need to access not only row-name but also column-name #2432

Open
michaeltraxler opened this issue Nov 10, 2024 · 3 comments
Open
Labels
feature Feature request ui Related to UI

Comments

@michaeltraxler
Copy link

In the documentation
https://wave.h2o.ai/docs/examples/table-events-select
it is shown that using the ui.table property
events=['select']
will enable an event handler so that when clicking on a table the row-name under the cursor is given as
q.args['<table_name>']
on the called table-handler.

But we need also the column name of the cell which was selected.

So, in our application we have a grid of numbers and need to know the cell which was selected.

How can I get this information, so the column name of the cell?

Thanks
Michael

@michaeltraxler michaeltraxler added the bug Bug in code label Nov 10, 2024
@mturoci mturoci added the ui Related to UI label Nov 25, 2024
@mturoci mturoci added feature Feature request and removed bug Bug in code labels Dec 8, 2024
@rutujmirzapure
Copy link

The solution should work as long as the Wave framework allows injecting and executing custom JavaScript for event handling in the frontend.

`
from h2o_wave import main, app, Q, ui

@app('/')
async def serve(q: Q):
if q.args.table:
# Extract row and column from custom args sent by the frontend script.
selected_cell = q.args.selected_cell
row_name = selected_cell.get('row_name')
col_name = selected_cell.get('col_name')
q.page['output'] = ui.markdown_card(
box='1 2 4 1',
title='Selected Cell',
content=f'Row: {row_name}, Column: {col_name}'
)
else:
# Initial table setup
q.page['table'] = ui.form_card(
box='1 1 4 4',
items=[
ui.table(
name='table',
columns=[
ui.table_column(name='name', label='Name'),
ui.table_column(name='age', label='Age'),
ui.table_column(name='city', label='City'),
],
rows=[
ui.table_row(name='row1', cells=['Alice', '30', 'New York']),
ui.table_row(name='row2', cells=['Bob', '35', 'Los Angeles']),
ui.table_row(name='row3', cells=['Charlie', '40', 'Chicago']),
],
events=['select'], # Add custom JavaScript to handle cell clicks
),
ui.inline_script('''
document.querySelectorAll("q-table").forEach(table => {
table.addEventListener("click", event => {
let cell = event.target.closest("td");
if (cell) {
let colName = cell.dataset.columnName;
let rowName = cell.closest("tr").dataset.rowName;
wave.emit("table", {selected_cell: {row_name: rowName, col_name: colName}});
}
});
});
''')
]
)

await q.page.save()

`

If the table does not provide data-column-name attributes:

Use alternative methods, such as calculating the column index from the cell's position or accessing the header cell (th) for the clicked column.

encounter any issues during implementation, and I can help you troubleshoot. Dm me on @rutujmirzapure

@michaeltraxler
Copy link
Author

Thank you so much for your hint and the code example. But unfortunately, I'm not able to run your code. Here is the output of wave run script.py when opening the web-page running with the newest version of wave.

...
INFO:     127.0.0.1:33490 - "POST / HTTP/1.1" 200 OK
Unhandled exception
Traceback (most recent call last):
  File "/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/server.py", line 379, in _process
    await self._handle(q)
  File "/home/michael/python/table_colum_row.py", line 17, in serve
    q.page['table'] = ui.form_card(
                      ^^^^^^^^^^^^^
  File "/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/ui.py", line 3080, in form_card
    return FormCard(
           ^^^^^^^^^
  File "/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/types.py", line 8855, in __init__
    _guard_vector('FormCard.items', items, (Component,), False, False, True)
  File "/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/types.py", line 50, in _guard_vector
    _guard_scalar(f'{name} element', value, types, False, non_empty, False)
  File "/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/types.py", line 37, in _guard_scalar
    raise ValueError(f'{name}: want one of {types}, got {type(value)}')
ValueError: FormCard.items element: want one of (<class 'h2o_wave.types.Component'>,), got <class 'h2o_wave.types.InlineScript'>
2024/12/16 13:40:37 * /51218c8a-b4e7-4e52-8a77-32217d9fdc6c {"d":[{},{"k":"__unhandled_error__","d":{"view":"markdown","box":"1 1 -1 -1","title":"Error","content":"```\nTraceback (most recent call last):\n  File\"/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/server.py\", line 379, in _process\n    await self._handle(q)\n  File \"/home/michael/python/table_colum_row.py\", line 17, in serve\n    q.page['table'] = ui.form_card(\n                      ^^^^^^^^^^^^^\n  File \"/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/ui.py\", line 3080, in form_card\n    return FormCard(\n           ^^^^^^^^^\n  File \"/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/types.py\", line 8855, in __init__\n    _guard_vector('FormCard.items', items, (Component,), False, False, True)\n  File \"/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/types.py\", line 50, in _guard_vector\n    _guard_scalar(f'{name} element', value, types, False, non_empty, False)\n  File \"/home/michael/d/wave_venv2/lib64/python3.11/site-packages/h2o_wave/types.py\", line 37, in _guard_scalar\n    raise ValueError(f'{name}: want one of {types}, got {type(value)}')\nValueError: FormCard.items element: want one of (<class 'h2o_wave.types.Component'>,), got <class 'h2o_wave.types.InlineScript'>\n\n```"}}]}

Any idea, what is going wrong here?

@rutujmirzapure
Copy link

ui.inline_script directly inside a card (e.g., ui.form_card), which is not supported by Wave. The ui.inline_script component is not a valid child for FormCard or most other Wave card components.

error : ValueError: FormCard.items element: want one of (<class 'h2o_wave.types.Component'>,), got <class 'h2o_wave.types.InlineScript'> ----> ui.form_card expects child components to be of type Component, and ui.inline_script is not a valid child type.

`from h2o_wave import main, app, Q, ui

@app('/')
async def serve(q: Q):
if not q.client.initialized:
# Define the tabs, including the documentation tab
q.page['tabs'] = ui.tab_card(
box='1 1 4 1',
items=[
ui.tab(name='home', label='Home'),
ui.tab(name='about', label='About'),
ui.tab(name='documentation', label='Documentation'),
]
)
q.page['content'] = ui.markdown_card(
box='1 2 4 4',
title='Welcome',
content='Select a tab to navigate.'
)

    # Add a script for handling external URL redirection for the documentation tab
    q.page['script'] = ui.inline_script("""
        // Add a click event listener for the 'documentation' tab
        document.querySelector('[data-tab-name="documentation"]').addEventListener('click', () => {
            window.open('https://wave.h2o.ai', '_blank');
        });
    """)

    q.client.initialized = True

# Backend logic for non-external tabs
if q.args.home:
    q.page['content'].content = 'You are on the Home tab.'
elif q.args.about:
    q.page['content'].content = 'You are on the About tab.'

await q.page.save()

`

Things To Note:Ensure that your Wave server is up to date with the latest version (pip install h2o-wave --upgrade).
The data-tab-name attribute is automatically added by Wave to tabs, so it's safe to use for JavaScript event binding.

If you want to include custom JavaScript (like window.open for external links) in your Wave app, you should add it at the global level, outside specific card definitions. This ensures the script is applied correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Feature request ui Related to UI
Projects
None yet
Development

No branches or pull requests

3 participants