zauberzeug / nicegui

Create web-based user interfaces with Python. The nice way.
https://nicegui.io
MIT License
10.06k stars 599 forks source link

@ui.refreshable refreshes 1 session from multiple diffrent sessions #2535

Closed Ezbaze closed 9 months ago

Ezbaze commented 9 months ago

Description

  1. Im trying to have a refreshable outside the @ui.page decorator so it can be reused on different pages.
from nicegui import ui

class Test:
    @ui.refreshable
    def ui(self, name):
        ui.notify(f"Refreshing {name}")

@ui.page("/other_page")
def page_layout():
    _ui = Test().ui
    ui.input("INPUT", on_change=lambda event: _ui.refresh(event.value))
    _ui("START")

if __name__ in {"__main__", "__mp_main__"}:
    ui.run(
        host="0.0.0.0",
        port=4040,
)
  1. I expect each session to have a seperate refreshable that will only refresh for the session it was asked to refresh from
  2. The refreshable refreshes the elements from any session but only for 1 session (see video)

https://github.com/zauberzeug/nicegui/assets/68749104/38f8049c-b509-4195-9360-c2b4f4c2eae8

Additional notes:

  1. Having the @ui.refreshable on it's own without a Class enclosing it makes every session refresh instead of just one.
  2. Having the function that will be refreshed outside of the @ui.page and then wrapping it in a function inside the @ui.page + decorating it with @ui.refreshable does give the desired effect but you'd have to do this for every page / every refreshable you'd want to use ._.

Thank you

falkoschindler commented 9 months ago

Hi @Ezbaze,

I'm not 100% sure why your code doesn't work as expected. I think it has to do with the way @refreshable keeps track of the current instance that needs to be refreshed when calling refresh(). By holding a reference _ui to Test().ui, this mechanism fails.

It's better to keep a reference to the Test instance:

class Test:
    @ui.refreshable
    def ui(self, name):
        ui.notify(f"Refreshing {name}")

@ui.page("/")
def page_layout():
    test = Test()
    ui.input("INPUT", on_change=lambda event: test.ui.refresh(event.value))
    test.ui("START")
Ezbaze commented 9 months ago

Hi @falkoschindler ,

I didnt think of that, but that does solve the issue I was facing :)

Thank you