State management of a todo list

when in main branch It could look like this
todo

import panel as pn
import param
from panel.reactive import ReactiveHTML
pn.extension()

class CustomInputTodoList(ReactiveHTML):
    
    value = param.String()
    
    enter_event = param.Event()
    
    _template = """
        <div class="bk bk-input-group">
            <input class="bk bk-input" id="input" value="${value}" style="margin: 5px;" onkeydown="${_input_keydown}"></input>
        </div>
    """
    
    _dom_events = {"input": ["input"]}
    
    def __init__(self, todolist, **params):
        self._todolist = todolist
        super().__init__(**params)
    
    def _input_keydown(self, event):
        if event.data['key'] == "Enter":
            self._todolist.todo = self.value
            self.value = ""
 

class TodoList(param.Parameterized):
    """ Class to manage state of a List of items """
    @param.depends("todo", watch=True)
    def _record_todo(self):
        # Record new item if its unique and non-empty
        value = self.todo.strip()
        if len(value) > 0 and value not in [i.todo for i in self.todo_list]:
            new_item = TodoListItem(parent=self, todo=value, name="")
            new_item.param.watch(self._delete_item, ['done'])
            self.todo_list.append(new_item)
            self.param.trigger('todo_list')
    
    def _delete_item(self, *events):
        for event in events:
            if event.name == 'done':
                self.todo_list.remove(event.obj)
                self.param.trigger('todo_list')
    
    todo_list = param.List([])
    todo = param.String()

    
class TodoListItem(param.Parameterized):
    """ Class to manage a a single list element """
    done = param.Event()
    todo = ""
    
todo_list = TodoList()
input_todo_list = CustomInputTodoList(todo_list, width=300)

@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(input_todo_list, width=300),
    view_list,
).servable()
6 Likes