Working on a Shiny app where the user can press a button and receive all tests that evaluate to False. I'm able to successfully insert these test messages into the UI; however, every time I press the button to rerun these tests, the UI adds onto the test results from before. How can I properly remove UI before inserting more UI?
from shiny import App, reactive, ui, run_app
# for reference, I run itertools.filterfalse over this to obtain a list of messages whose conditions evaluate to False
test_results = {'Test message #1':True, 'Test message #2':False, 'Test message #3': False}
test_results_output = ['Test message #2', 'Test message #3']
app_ui = ui.page_fluid(
ui.input_action_button('button_scan_directory', 'Scan directory'),
ui.output_ui('output_scan_report')
)
def server(input, output):
@reactive.Effect
@reactive.event(input.button_scan_directory, ignore_init=True, ignore_none=True)
def output_scan_report():
for test in test_results_output:
ui.remove_ui(selector="p:has(> #App Error)")
ui.insert_ui(
ui.p(f"App Error :: {test}"),
selector='#output_scan_report',
where='afterEnd'
)
app = App(app_ui, server)
run_app(app)
As long as you don't need each new line to have its own UI, a solution is to return the new UI object directly. This is maybe what you where trying to do as you created a ui.output_ui
object.
### app ui
ui.output_ui('output_scan_report')
### server function
@output
@render.ui
@reactive.event(input.button_scan_directory, ignore_init=True, ignore_none=True)
def output_scan_report():
message = '<br>'.join(f"- {test}" for test in test_results_output)
return ui.HTML(message)