Handling visibility of spinners / Using node show&hide in one handler #594
-
My idea is to use a Bootstrap spinner like <div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div> On my Lona view I have a @app.route('/')
class MyView(LonaView):
def handle_project_selection_changed(self, input_event):
print(f"Selected Project: {self.select_project.value}")
do_some_magic_stuff(self.select_project.value)
def handle_request(self, request):
self.select_project = Select2(
_class='form-select form-select-sm',
handle_change=self.handle_project_selection_changed
)
... Unfortunately I can't display and hide the spinner in one handler like def handle_project_selection_changed(self, input_event):
self.my_handler.show()
print(f"Selected Project: {self.select_project.value}")
do_some_magic_stuff(self.select_project.value)
self.my_handler.hide() Is there any way to get the view updated while such a handler is running and doing some heavy operations? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
Good question! First some background: In Lona, if you want to push HTML to a client, you need to invoke You can invoke import time
from lona.html import HTML, NumberInput, Div, Button, H1, Span
from lona import App, View
app = App(__file__)
app.settings.SESSIONS = False
@app.route('/')
class ExampleView(View):
def handle_request(self, request):
self.number_a = NumberInput(value=0)
self.number_b = NumberInput(value=0)
self.state = Span('Ready')
self.result = Span('0')
self.calculate_button = Button(
'Calculate',
handle_click=self.handle_calculate_button_click,
)
return HTML(
H1('Calculator'),
self.state,
Div(
self.number_a,
Span('x'),
self.number_b,
Span('='),
self.result,
),
Div(
self.calculate_button,
),
)
def handle_calculate_button_click(self, input_event):
# show our spinner
self.state.set_text('Calculating...')
self.show() # the line you are missing
# calculate result
result = self.calculate(
a=self.number_a.value,
b=self.number_b.value,
)
self.result.set_text(result)
# reset view
self.state.set_text('Ready')
def calculate(self, a, b):
time.sleep(3)
return a * b
if __name__ == '__main__':
app.run(port=8080) There is a catch with this approach though: In Lona, input events are queued and get handled in serial, not in parallel. That means, if you have an input event handler that does long-running calculations, no other input event can be handled until the handler finishes. import time
from lona.html import HTML, NumberInput, Div, Button, H1, Span, Br
from lona import App, View
app = App(__file__)
app.settings.SESSIONS = False
@app.route('/')
class ExampleView(View):
def handle_request(self, request):
self.number_a = NumberInput(value=0)
self.number_b = NumberInput(value=0)
self.state = Span('Ready')
self.result = Span('0')
self.calculate_button = Button(
'Calculate',
handle_click=self.handle_calculate_button_click,
)
return HTML(
H1('Calculator'),
self.state,
Div(
self.number_a,
Span('x'),
self.number_b,
Span('='),
self.result,
),
Div(
self.calculate_button,
),
)
def handle_calculate_button_click(self, input_event):
def _handle_calculate_button_click():
# show our spinner
self.state.set_text('Calculating...')
self.show()
# long running code
result = self.calculate(
a=self.number_a.value,
b=self.number_b.value,
)
# reset view
self.result.set_text(result)
self.state.set_text('Ready')
# we have to invoke `show()` ourself because the actual
# event handler already finished
self.show()
# run actual logic in a thread to free up the input event queue
self.server.run_function_async(_handle_calculate_button_click)
def calculate(self, a, b):
time.sleep(3)
return a * b
if __name__ == '__main__':
app.run(port=8080) |
Beta Was this translation helpful? Give feedback.
Hi @TheAxelander
Good question! First some background: In Lona, if you want to push HTML to a client, you need to invoke
View.show()
with an HTML element fromlona.html
. If you don't provide an HTML element, the previous HTML element gets resent, or rather all changes you did to it.When an input event handler ends, Lona checks whether you made changes to the last HTML element you sent. If so, the changes get sent implicitly. That's why, in your implementation, only the final HTML state is visible.
You can invoke
View.show()
anytime you want though. Look at this example: