Skip to content

Conversation

@evnchn
Copy link
Collaborator

@evnchn evnchn commented Jan 1, 2026

Motivation

Fix #3033, in which we find it is not possible to read data off client-side AGGrid if it is unmounted.

Implementation

This is a decent approach:

  • move the element to client.content to force it to render
  • Do our JS
  • move it back

Now that we are doing it in the client-side, stuff is much better (check before force-push to see what I did 🤡)

Progress

  • I chose a meaningful title that completes the sentence: "If applied, this PR will..."
  • The implementation is complete.
  • Pytests 50949d0
  • Documentation 437d902

@evnchn evnchn force-pushed the aggrid-move-trick branch from 0889fc4 to 1adacbd Compare January 1, 2026 16:24
@evnchn
Copy link
Collaborator Author

evnchn commented Jan 1, 2026

Note: It may be desirable to have getElementEnsured on nicegui.js which does this, or even bake this into getElement. This way all other elements's JS API can be accessed despite not yet mounted.

@evnchn evnchn added the bug Type/scope: Incorrect behavior in existing functionality label Jan 1, 2026
@evnchn
Copy link
Collaborator Author

evnchn commented Jan 2, 2026

Actually is this PR a good idea?

The point of get_client_data is to get the client's data after all, but if we are simply rendering a new AGGrid just for its data, the data we get might be the same as server-side data (awaiting verification)

Maybe we should modify the component to emit the data before unmount instead. That would be more practical.

@evnchn
Copy link
Collaborator Author

evnchn commented Jan 3, 2026

We need the new functionality because the user-edited data persists in the hidden tab. The element may be not unmounted but just hidden from DOM? Anyways just minor terms issue.

from nicegui import ui

with ui.tabs().classes('w-full') as tabs:
    one = ui.tab('One')
    two = ui.tab('Two')
with ui.tab_panels(tabs, value=one).classes('w-full'):
    with ui.tab_panel(one):
        async def get_data():
            ui.notify(await grid.get_client_data())
        ui.button('Get data (offscreen)', on_click=get_data)
    with ui.tab_panel(two):
        grid = ui.aggrid({
            'columnDefs': [{'headerName': 'Name', 'field': 'name', 'editable': True}],
            'rowData': [{'name': 'Alice'}, {'name': 'Bob'}],
        })
        ui.button('Get data (onscreen)', on_click=get_data)

ui.run()

Get data (offscreen) works with this PR and breaks without.

@evnchn
Copy link
Collaborator Author

evnchn commented Jan 9, 2026

what would happen if we store the API object of the element somewhere in window? This way we would not need to swap-in the element just for the API object

Or, is there already some reference stored somewhere to allow me to access it?

@evnchn
Copy link
Collaborator Author

evnchn commented Jan 11, 2026

store the API object of the element somewhere in window

So something like

        result = await self.client.run_javascript(f'''
            const rowData = [];
            __nicegui_aggrid_api__["{self.html_id}"].{API_METHODS[method]}(node => rowData.push(node.data));
            return rowData;
        ''', timeout=timeout)
      this.api = AgGrid.createGrid(this.$el, this.gridOptions);
      if (window.__nicegui_aggrid_api__ === undefined) window.__nicegui_aggrid_api__ = {};
      window.__nicegui_aggrid_api__[this.$el.id] = this.api;

It works, but the AG Grid must be already rendered once.

  • The technique can NOT help if the AG Grid was never rendered, which the technique in this PR will still be needed in that edge case
  • The technique CAN help if the AG Grid was rendered beforehand, which reduces the need of the technique in this PR

Considering the use case of fetching user-edited data from AG Grid, it may be advisable to just let get_client_data calls fail if the AG Grid was never rendered before. This way, we avoid this rather hacky hack of await mounted_app.$nextTick();, which may cause side-effects due to how it manipulates the childrens and triggers rendering next-tick.

@falkoschindler We should carefully consider this before merging the PR because we don't want to enable something at the cost of poor code decisions.

@falkoschindler
Copy link
Contributor

Thanks @evnchn! This is an interesting approach.

But it feels a bit fragile:

  1. Race condition risks: What happens if:
    • Multiple get_client_data() calls happen concurrently on the same offscreen grid?
    • User navigates to the tab while the operation is in progress?
    • The parent element is modified during this temporary move?
  2. Visual artifacts: Does temporarily moving the element to client.content cause any visual flicker, layout shift, or briefly render the grid visibly?
  3. Missing cleanup on error: If an exception occurs between the splice operations (e.g., $nextTick() times out), the element could be left in an inconsistent state. Consider using try/finally logic.

@falkoschindler falkoschindler added the review Status: PR is open and needs review label Jan 14, 2026
@evnchn
Copy link
Collaborator Author

evnchn commented Jan 14, 2026

Exactly

Hence why in #5615 (comment) I recommend against doing this element-swap trick, and just store the API object to enable mounted elements to read the API off-screen while unmounted elements remain inaccessible

@falkoschindler
Copy link
Contributor

Ok, which brings us to #5612 (review): a client-side memory leak, unless we make sure to prune the storage when the element is deleted.

@falkoschindler falkoschindler added in progress Status: Someone is working on it and removed review Status: PR is open and needs review labels Jan 14, 2026
@evnchn
Copy link
Collaborator Author

evnchn commented Jan 14, 2026

Well then, I am thinking, instead of all elements writing to window with unclear lifetimes and high risk of client-side memory leak if something is done wrong, should nicegui.js offer some helpers?

@falkoschindler
Copy link
Contributor

Let's discuss the broader picture over at #3033 (comment).

@falkoschindler falkoschindler added analysis Status: Requires team/community input and removed in progress Status: Someone is working on it labels Jan 15, 2026
@evnchn
Copy link
Collaborator Author

evnchn commented Jan 15, 2026

I don't like this anymore. You will know why shortly.

@evnchn evnchn closed this Jan 15, 2026
evnchn added a commit to evnchn/nicegui that referenced this pull request Jan 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

analysis Status: Requires team/community input bug Type/scope: Incorrect behavior in existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AG Grids inside hidden tabs don't get mounted

2 participants