TODO List

A complete todo application demonstrating component communication, state management, and reactive lists with WatchList.

Live Demo

📝 Total: {{count}} ✅ Done: {{done}} ⏳ Left: {{left}}

HTML Template

<x-todo-form>
  <input type="text" placeholder="What needs to be done?"
         value="{{todo}}" x-enter-pressed="add"/>
  <button x-click="add">Add Task</button>
</x-todo-form>

<x-todo-list>
  <div>Total: {{count}} | Done: {{done}} | Left: {{left}}</div>
  <div x-list="items"></div>
</x-todo-list>

JavaScript Components

function TodoItem(self, name) {
  self.name = name;
  self.done = false;

  self.delete = () => self.emit('del-todo', self);

  self.changed = () => {
    self.done = !self.done;
    self.emit('task-changed');
  };

  self.template = `
    <div class="todo-item">
      <input type="checkbox" x-change="changed" />
      <div class="task-text" x-class="done:done">{{name}}</div>
      <button x-click="delete" class="delete-btn">Delete</button>
    </div>`;
}

function TodoForm(self) {
  self.todo = "";

  self.add = () => {
    if (!self.todo) {
      alert("Task cannot be empty");
      return;
    }
    self.emit("new-todo", self.todo);
    self.todo = "";
  }
}

function TodoList(self) {
  self.items = new WatchList([$(TodoItem, "Example task")]);
  self.left = self.done = self.count = 0;

  self.countTasks = () => {
    self.count = self.items.count();
    self.done = self.items.count(x => x.done);
    self.left = self.count - self.done;
  };

  self.on('new-todo', todo => {
    self.items.add($(TodoItem, todo));
    self.countTasks();
  });

  self.on('del-todo', todo => {
    self.items.delete(x => x === todo);
    self.countTasks();
  });

  self.on('task-changed', self.countTasks);

  // Initialize counts
  self.countTasks();
}

$([TodoForm, TodoList, TodoItem]);

Key Concepts