-
-
Save FerusAndBeyond/9c6144bb57f477521e1608f18feefc9f to your computer and use it in GitHub Desktop.
shiny5.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from shiny import App, render, ui, reactive | |
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.output_ui("tasks") | |
), | |
# 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) | |
todo_counter = reactive.Value(0) | |
todos = reactive.Value([]) | |
# 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(): | |
# add todo | |
# and increment a count to keep track of them | |
count = todo_counter.get() | |
todo_counter.set(count+1) | |
# each todo is a dict with text and a button_key to know which one is which | |
todos.set(todos() + [dict(button_key=f"finish_{count}", text=input.todo_input_text())]) | |
# reset input | |
ui.update_text("todo_input_text", value="") | |
# This function will remove a to-do item | |
# It will react to changes in todos() and button clicks | |
# in buttons with id = t["button_key"] | |
@reactive.Effect | |
@reactive.event(lambda: [input[t["button_key"]]() for t in todos()]) | |
def finish(): | |
items = todos() | |
key = None | |
# find button that has value above 0, i.e. it was clicked | |
for t in items: | |
v = input[t["button_key"]]() | |
if v > 0: | |
key = t["button_key"] | |
break | |
# if None, no button was clicked | |
if key is not None: | |
# remove the to-do that was clicked | |
todos.set([t for t in items if t["button_key"] != key]) | |
# increment finished tasks | |
finished_tasks.set(finished_tasks() + 1) | |
# this function will update the interface when todos() | |
# is updated, i.e. an item is added or removed | |
@output | |
@render.ui | |
def tasks(): | |
return ui.div(children=[ | |
ui.row( | |
ui.column(2, ui.input_action_button(t["button_key"], "Finish")), | |
ui.column(5, ui.h5(t["text"])) | |
) | |
for t in todos() | |
# you can also add inline style to elements | |
], style="margin-top: 0.5em") | |
# 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