DEV Community

Cover image for TodoList part 4/n
artydev
artydev

Posted on • Updated on

TodoList part 4/n

Let's enhance our TodoList.

TodoList

Three buttons have been added to the status bar. Here is the code to display and manage them :

 function createStatus () {
   selectBase(div("", cssStatus));

     function displayCompleted (isCompleted) {
       todos.forEach(todo => todo.dataset.completed == isCompleted 
          ? todo.style.display = "flex" : todo.style.display = "none");
      }

     button("active(s)", cssBtn).onclick = () => displayCompleted("false");
     button("completed", cssBtn).onclick = () => displayCompleted("true");
     button("all", cssBtn).onclick = 
        () => todos.forEach(todo => todo.style.display = "flex");

  unselectBase();    
 }
Enter fullscreen mode Exit fullscreen mode

Could it be simpler ?

See how we easily we reference and add events on our three created buttons.

You cant play with it here : TodoList

Here is the full code so far :

import { make, selectBase, unselectBase } from "./dml";

const TodoApp = function (target) {

  const blueblack = "rgb(40, 42, 54)"

  if (!target) {
    target = document.body;
  }

  const cType = function (type, content, attribs) {
    return (content, attribs) => make(type, attribs, content);
  };

  const div = cType("div");
  const h1 = cType("h1");
  const input = cType("input");
  const button = cType("button");

  let reflistTodos = null;
  let todos = [];

  const cssTodoApp = `
    width:75%;
    max-width:480px;
    min-width:360px;
    padding:10px;
    padding-bottom:5px;
    margin:0 auto;
    background:  white;
  `;

  const cssTodo = () => `
    padding:5px;
    display:flex;
    justify-content:space-around;
    margin-bottom:5px`;

  const cssEntryTodo = `
    margin-bottom: 10px;
    width:98%;
    padding:5px;
    border: 1px solid ${blueblack};
  `

  const cssStatus = `
    margin-top:10px;
    margin-bottom: 10px;
    color: ${blueblack};
    border: 1px solid ${blueblack};
    padding:5px;
    text-align:center;
  `;

  const cssBtn = `border:1px solid grey;margin:2px`;

  function createEntryTodo () {
    selectBase(div("", cssEntryTodo));
      let entry = input("", { 
        style: "width:99%; border:none", 
        placeholder: "input new todo and press Enter" 
      });
      entry.onkeypress = function (e) {
        if (e.which === 13) {
          addTodo(entry.value); 
          entry.value = "";
        }
      }
    unselectBase()
  }

  function createTodoItem(todo) {
  selectBase(reflistTodos)
    let divtodo = selectBase(div("", cssTodo()))
      let checktodo = input("", { type: "checkbox" });
      let inptodo = input("", { style: "flex:0.99", value: todo });
      let deltodo = input("", { type: "checkbox", style: "visibility:hidden" });
      divtodo.dataset.completed = "false"
      checktodo.onchange = () => checkTodo({divtodo, checktodo, inptodo});
      deltodo.onchange = () => deleteTodo(divtodo)
      divtodo.onmouseover = () => (deltodo.style.visibility = "visible");
      divtodo.onmouseout = () => (deltodo.style.visibility = "hidden");
    unselectBase();
   unselectBase();
   return divtodo
  }

  function createListTodos(todos = []) {
    reflistTodos = selectBase(div("", "padding:5px"))
    todos.map(addTodo);
    unselectBase()
  }

  function deleteTodo (todo) {
    todos = todos.filter(t => t != todo);
    todo.remove();
  }

  function addTodo(todo) {
    // calling createTodoItem update the view
    todos = [...todos, createTodoItem(todo)];
  }

  function checkTodo ({divtodo, checktodo, inptodo}) {
    let checked = checktodo.checked
    if (checked) {
      inptodo.style.color = 'red'
      inptodo.style.textDecoration = 'line-through';
      divtodo.dataset.completed = 'true';
    }
    else {
      inptodo.style.color = blueblack;
      inptodo.style.textDecoration = 'none';
      divtodo.dataset.completed = 'false';
    }
  }

  function createStatus () {
    function displayCompleted (isCompleted) {
      todos.forEach(todo => todo.dataset.completed == isCompleted 
        ? todo.style.display = "flex" : todo.style.display = "none");
    }

    button("active(s)", cssBtn).onclick = () => displayCompleted("false");
    button("completed", cssBtn).onclick = () => displayCompleted("true");
    button("all", cssBtn).onclick = 
      () => todos.forEach(todo => todo.style.display = "flex");
  }

  function initApp(todos) {
    target.style = cssTodoApp;
    let app = selectBase(target); 
      createEntryTodo();
      createListTodos(todos);
      selectBase(div("", cssStatus));
        createStatus();
      unselectBase();
    unselectBase();
    return app
  }

  return {
    init: initApp,
    addTodo: addTodo,
  };
};

export default TodoApp;
Enter fullscreen mode Exit fullscreen mode

Discussion (2)

Collapse
efpage profile image
Eckehard

As styles are most frequently used, you don´t need to set the style property explicitly. The two definitions are identical:
´´´js
button("all", {style: cssBtn}) // Properties as JSON-object
button("all", cssBtn) // style attributes as string only are converted
´´´
DML distinguishes the type of the second argument. Any string is automatically converted to a style property:
´´´js
"color: red;" ==> {style: "color: red;"}
´´´
This is just for convenience, but as in 95% of the cases only the style is set, this is a very handy abbreviation.

Collapse
artydev profile image
artydev Author • Edited

Thanks Eckehard☺
Very handy for sure, I have made the modification