I am new to the Textual library and I was trying to make widgets to update whenever data changes. This is a simple example of what I've tried:
class TestBody(Static):
data = reactive("")
def compose(self) -> ComposeResult:
yield Input()
yield Label(f"Data: {self.data}")
def on_input_submitted(self, message):
self.data = message.value
print("New data:", self.data)
class MyApp(App):
def compose(self) -> ComposeResult:
yield Header()
yield TestBody()
yield Footer()
if __name__ == "__main__":
app = MyApp()
app.run()
In this example, I can type anything in the input component, and when submitted, it should be displayed by the label. But what actually happens is nothing; the label always displays "Data: ".
By using the textual console
tool, I can see that the submit message is definitely being sent and picked up by my handler. I can even see the data changing in the log, but the display does not update.
I understand from the docs that I shouldn't need to use the refresh() method since I am using a reactive attribute. In any case, I tried to add self.refresh()
inside on_input_submitted
and it still did not work.
I have the feeling that I am missing something about this library, but I couldn't find any similar examples.
Thanks in advance.
As someone explained to me in the Textualize discord server:
A reactive will cause a refresh of a render of a widget it's defined as part of; but in your code you're trying to get the Label to update. In the code posted over on that site you'd need to be using a watch method that then calls the update of the Label.
So, this would be the updated code:
class TestBody(Static):
data = reactive("")
def compose(self) -> ComposeResult:
yield Input()
yield Label()
def watch_data(self) -> None:
self.query_one(Label).update(f"Data: {self.data}")
def on_input_submitted(self, message):
self.data = message.value
class MyApp(App):
def compose(self) -> ComposeResult:
yield Header()
yield TestBody()
yield Footer()
if __name__ == "__main__":
MyApp().run()