Build a Todo App#
In this section, we will work on building a Todo App together so that our wind turbine technicians can keep track of their tasks. As a team, we will collaborate to create an app that provides the following functionality:
Adding, removing, and clearing all tasks
Marking a task as solved
Keeping track of the number of completed tasks
Disabling or hiding buttons when necessary
Note
When we ask everyone to run the code in the sections below, you may either execute the code directly in the Panel docs via the green run button, in a cell in a notebook, or in a file app.py
that is served with panel serve app.py --dev
.
Requirements
panel
Code
import panel as pn
pn.extension(sizing_mode="stretch_width", design="material")
BUTTON_WIDTH = 125
state_changed_count = pn.widgets.IntInput()
tasks = pn.Column()
def update_state_changed_count(*args):
state_changed_count.value += 1
def remove_task(task, *args):
index = tasks.index(task)
tasks.pop(index)
def remove_all_tasks(*args):
tasks.clear()
def create_task(text):
state = pn.widgets.Checkbox(align="center", sizing_mode="fixed")
content = pn.pane.Markdown(text)
remove = pn.widgets.Button(width=BUTTON_WIDTH, icon="trash", sizing_mode="fixed")
task = pn.Row(state, content, remove, sizing_mode="stretch_width")
pn.bind(remove_task, task, remove, watch=True)
# We have to bind the below after the above!
pn.bind(update_state_changed_count, state, remove, watch=True)
return task
def add_task(text, *args):
if not text:
return
new_task = create_task(text)
tasks.append(new_task)
return tasks
def get_state(*args):
total_tasks = len(tasks)
completed_tasks = sum(check[0].value for check in tasks)
return f"{completed_tasks} of {total_tasks} tasks completed"
def can_add(value_input):
return not bool(value_input)
def has_tasks(*args):
return len(tasks) > 0
add_task("Inspect the blades")
add_task("Inspect the nacelle")
add_task("Tighten the bolts")
text_input = pn.widgets.TextInput(name="Task", placeholder="Enter a task")
submit_task = pn.widgets.Button(
name="Add",
align="center",
button_type="primary",
width=BUTTON_WIDTH,
sizing_mode="fixed",
disabled=pn.bind(can_add, text_input.param.value_input)
)
clear = pn.widgets.Button(
name="Remove All",
button_type="primary",
button_style="outline",
width=BUTTON_WIDTH,
sizing_mode="fixed",
visible=pn.bind(has_tasks, state_changed_count)
)
def reset_text_input(*args):
text_input.value = text_input.value_input = ""
pn.bind(add_task, text_input, submit_task, watch=True)
pn.bind(reset_text_input, text_input, submit_task, watch=True)
pn.bind(remove_all_tasks, clear, watch=True)
# We have to bind the below after the above!
pn.bind(update_state_changed_count, text_input, submit_task, clear, watch=True)
status_report = pn.bind(get_state, state_changed_count, tasks.param.objects)
pn.Column(
"## WTG Task List",
status_report,
pn.Row(text_input, submit_task),
tasks,
pn.Row(pn.Spacer(), clear),
max_width=500,
).servable()
Install the Requirements#
pip install panel
conda install -y -c conda-forge panel
Explanation#
COMING UP
Let’s perform the following actions:
Remove one task
Remove all tasks
Add 3 Tasks
Check 1 of 3 tasks and see the
status_message
update accordingly.
Note
A todo app can be built in many other ways. The main purpose of this example is for all of us to acquire the basic skills needed to develop stateful, dynamically updating apps like this one.
Recap#
In this section, we have built a Todo App with many features. We needed to combine many of the things we have learned so far.