frameworkless-render

by cnhhoang850

HTML

<html>
    <body>
        <section class="app">
            <header class="header">
                <h1>Notes</h1>
                <input
                    type="text"
                    class="new_note"
                    placeholder="Input new note here"
                    autofocus=""
                />
            </header>
            <section class="main">
                <input type="checkbox" class="show-all" id="show-all" />
                <label for="show-all"> Show all notes </label>
                <ul class="todo-list"></ul>
            </section>
            <footer class="footer">
                <span class="todo-count"></span>
                <ul class="filters">
                    <li><a href="#/">All</a></li>
                    <li><a href="#/active">Active</a></li>
                    <li><a href="#/completed">Completed</a></li>
                </ul>
                <button class="clear-all">Clear completed</button>
            </footer>
        </section>
    </body>
</html>

JavaScript

const state = {
  todos: [
    {
      done: false,
      value: "nội dung 1",
    },
    {
      done: true,
      value: "nội dung 2",
    },
  ],
  filter: "All",
};

const root = document.querySelector(".app");

window.requestAnimationFrame(() => {
  const virtualRoot = render(root, state);
  root.replaceWith(virtualRoot);
});

const renderTodo = (todo) => {
  const { done, value } = todo;

  return `
  <li ${done ? 'class="done"' : ""}>
    <div class="view">
      <input ${done ? "checked" : ""}
          type="checkbox" class="toggle" />
      <label>${value}</label>
      </div>
      <input type="text" class="edit" value="${value}" />
  </li>
  `;
};

const countTodo = (todos) => {
  const notDone = todos.filter((todo) => !todo.done);

  const numberOfTodos = notDone.length;

  return `${numberOfTodos} Todos left`;
};

const render = (renderTarget, state) => {
  const { todos, filter } = state;

  // Phải xác định DOM node thủ công
  const targetElement = renderTarget.cloneNode(true);
  const todoListElement = targetElement.querySelector(".todo-list");
  const counterElement = targetElement.querySelector(".todo-count");
  const filterElement = targetElement.querySelector(".filters");

  // Logic nằm ở cùng một nơi
  todoListElement.innerHTML = todos.map(renderTodo).join("");
  counterElement.textContent = countTodo(todos);

  Array.from(filterElement.querySelectorAll("li a")).forEach((a) => {
    if (a.textContent === filter) {
      a.classList.add("selected");
    } else {
      a.classList.remove("selected");
    }
  });

  return targetElement;
};