Hi all! I am trying to understand state management in panel, and what better way than creating a todo list!
I am able to use parameterized classes to create a stateful list that can be added to or deleted from.
It looks like this:
I’ve created two components, the todo list itself and a component for the individual element in the list. Each individual list element has its own delete button, but I can’t figure out a clean way to pass the the action of deleting an individual element up to the parent list. I’ve had to resort to adding a “delete” button and a “remove” Select widget to the list object itself, but that is not my preference.
Any experts out there know how to enable the delete buttons on each of the list items?
The code to create the above todo list:
import panel as pn
import param
pn.extension()
class TodoList(param.Parameterized):
""" Class to manage state of a List of items """
def _record_todo(self):
# Record new item if its unique and non-empty
if len(self.todo) > 0 and self.todo not in [i.todo for i in self.todo_list]:
self.todo_list = (
[i for i in self.todo_list if len(i.todo) > 0] +
[TodoListItem(todo=self.todo, name="")])
self.todo = ''
self.param.remove.objects = [todo.todo for todo in self.todo_list]
self.remove = self.param.remove.objects[0]
record_todo = param.Action(_record_todo)
def _delete_todo(self):
self.todo_list = [i for i in self.todo_list if i.todo != self.remove]
self.param.remove.objects = [todo.todo for todo in self.todo_list]
self.remove = self.param.remove.objects[0]
delete_todo = param.Action(_delete_todo)
todo_list = param.List([])
todo = param.String()
remove = param.ObjectSelector('', objects=[])
class TodoListItem(param.Parameterized):
""" Class to manage a a single list element """
def delete_todo(self):
print("How can I signal to the TodoList that I want to be deleted?")
done = param.Action(delete_todo)
todo = ""
todo_list = TodoList()
@pn.depends(todo_list.param.todo_list)
def view_list(todo_list):
todo_text = lambda x : pn.pane.Markdown("###" + x, width=200)
delete_button = lambda x : pn.Param(
x, widgets={'done': {'widget_type' : pn.widgets.Button,
'button_type': 'danger', 'name':'x', 'width':15}})
return pn.Column(*[pn.Row(todo_text(todo.todo), delete_button(todo.param.done))
for todo in todo_list])
pn.Column(
pn.pane.Markdown('## My To-Do List'),
pn.Row(pn.Param(todo_list.param.todo,
widgets={'todo': {'widget_type' : pn.widgets.TextInput, 'name': "",
'placeholder': 'Enter a Todo...'}}),
pn.Param(todo_list.param.record_todo,
widgets={'record_todo': {'widget_type' : pn.widgets.Button,
'button_type': 'primary', 'name':'+', 'width':15}})),
view_list,
pn.Row(
pn.Param(todo_list.param.remove),
pn.Param(todo_list.param.delete_todo,
widgets={'delete_todo': {'widget_type' : pn.widgets.Button,
'button_type': 'danger', 'name':'x', 'width':15, 'margin': (20, 10,20,10)}}))
).servable()