Behaviour of BindableProperty and lists #5088
Unanswered
BlankAdventure
asked this question in
Q&A
Replies: 2 comments 4 replies
-
I did come up with the following work-around: import random
from nicegui.binding import BindableProperty, bind_from
from nicegui import ui
class Customlist(list):
def __init__(self, iterable):
self.toggle = False
super().__init__(iterable)
def append(self,item):
super().append(item)
self.toggle = not self.toggle
class Model():
def __init__(self):
self.y = Customlist([])
def update(self, val):
self.y.append(val)
print(f'{app.y_tracker=}' )
model = Model()
class App():
y_tracker = BindableProperty(on_change=lambda sender,value : sender.changed(value))
def __init__(self):
self.y_tracker = None
def changed(self,value):
print(f'{value=} | {model.y=}')
app = App()
bind_from(self_obj=app, self_name='y_tracker',other_obj=model.y, other_name='toggle', backward=lambda t: t)
ui.button(icon='refresh', on_click=lambda: model.update(random.randint(0,30)))
ui.run() I moved things around a bit, but the main idea is that I created a custom |
Beta Was this translation helpful? Give feedback.
0 replies
-
Hi @BlankAdventure, I think you're already on the right track: Is
In conclusion, we have to use the long form class App:
y = BindableProperty(lambda _, value: print('Y changed', value))
def __init__(self):
self.y = []
app = App()
class Model:
def __init__(self):
self.y = []
def update(self):
self.y = self.y + [1]
print(f'{app.y=}')
model = Model()
bind_from(app, 'y', model, 'y')
ui.button('Update', on_click=model.update) |
Beta Was this translation helpful? Give feedback.
4 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
First Check
Example Code
Description
I have a situation where I'm trying to detect changes to a list that exists in particular class from another library. See the attached code as a stripped down example.
In this code, I want to bind to changes in the attributes x and y of Model. The refresh button serves to simulate an external call that modifies these values. Model.x has been included simply as a baseline to show that everything is working as expected. The list attribute of Model.y is what we're interested in.
If you run the code and click the refresh button a few times, you'll see something like this:
This shows that the binding is operating correctly -- the appended list values are getting propagated into App.y_tracker. However, notice that only the x_tracker callback (x_func) gets called, NOT the y_tracker callback. This is puzzling to me.
I know that only assignments trigger the
__set__()
method in a descriptor, not list mutations; but I think this is a red herring as the append operation only happens in Model, and the new value is in fact assigned to the attribute in App. This can be checked with the second button 'setattr', where I explicitly call setattr and see the following result:So, with setattr, the callback (y_func) is indeed called. An in fact, we see it gets 'reset' to its previous value right after, presumably as the loop cycles through and syncs with model.y. This in my mind confirms an assignment is taking place.
So, I'm confused with what exactly is happening in the binding module: an assignment certainly seems to be taking place, and therefore ought to trigger the
__set__()
method, and ultimately the callback.NiceGUI Version
2.16.0
Python Version
3.11.11
Browser
Chrome
Operating System
Windows
Additional Context
No response
Beta Was this translation helpful? Give feedback.
All reactions