Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gshotwell/eed0bda3ac0e7fa7a7a862cff094cf0d to your computer and use it in GitHub Desktop.
Save gshotwell/eed0bda3ac0e7fa7a7a862cff094cf0d to your computer and use it in GitHub Desktop.
Shiny todo with insert/remove modules
from shiny import App, render, ui, reactive, module
from htmltools import TagList
app_ui = ui.page_fluid(
ui.row(
# add space from the left
ui.column(3),
# center with content
ui.column(
6,
# title
ui.h1("The to-do list"),
# will show the text output from the
# function cleared_tasks()
ui.output_text("cleared_tasks"),
# line
ui.hr(),
# input_text can be accessed using the id, here "todo_input_text"
# using input.todo_input_text(), see later
ui.input_text("todo_input_text", "", placeholder="Todo text"),
# clicking will increment input.add()
ui.input_action_button("add", "Add to-do"),
# will show UI output from the function tasks()
ui.div(id="tasks", style="margin-top: 0.5em"),
),
# add space from the right
ui.column(3),
),
# seen on the tab
title="To-do",
)
# everything is wrapped inside one function
def server(input, output, session):
# reactive/stateful variables
finished_tasks = reactive.Value(0)
task_counter = reactive.Value(0)
# This will define what is going to be shown
# at the component with id "cleared_tasks" because
# the function name is the same.
# Since finished_tasks() is called inside it,
# it will be called if this variable is changed.
@output
@render.text
def cleared_tasks():
return f"Finished tasks: {finished_tasks()}"
# This function will add a to-do to the list.
# It will only react to when input.add() is changed
# which happens when the button with id="add" is clicked
@reactive.Effect
@reactive.event(input.add)
def add():
counter = task_counter.get() + 1
task_counter.set(counter)
id = "task_" + str(counter)
ui.insert_ui(
selector="#tasks",
where="afterBegin",
ui=task_ui(id, text=input.todo_input_text(), remove_id=id),
)
task_server(id, remove_id=id, task_list=finished_tasks)
ui.update_text("todo_input_text", value="")
@module.ui
def task_ui(text, remove_id):
out = ui.row(
{"id": remove_id},
ui.column(2, ui.input_action_button("remove", "Finish")),
ui.column(
5,
ui.h5(text),
),
)
return out
@module.server
def task_server(input, output, session, remove_id, task_list):
@reactive.Effect
@reactive.event(input.remove)
def finish_task():
task_list.set(task_list.get() + 1)
ui.remove_ui(selector=f"div#{remove_id}")
# Finally, to run everything create an App object and assign it to app
app = App(app_ui, server)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment