Search code examples
javascripthtml

reference error in html button on click while referenced in script tag


I know I have the called function the HTML in a script tag as mentioned above, yet my code is still throwing

ReferenceError: createTask is not defined at HTMLButtonElement.onclick`

when I click the button.

The StackBlitz link (if needed): https://stackblitz.com/edit/stackblitz-starters-3xxvzunv?file=script.js,index.html

function createTask() {
  var x;
  x++;
  var value = 'task'.concat(toString(x));
  class Task {
    constructor(value) {
      super(value, value);
      this.task = {
        value: {
          title: '',
          desc: ''
        }
      };
    }
  }
  const task = new Task(Value);
}
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Home</title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width" />
  <link rel="stylesheet" href="styles.css" />
  <script src="script.js"></script>
</head>

<body>
  <textarea id='taskcontent'>
    </textarea>
  <button onclick='createTask()'>
      +
    </button>
  <div id='taskcontainer'>
  </div>
</body>

</html>


Solution

    1. Remove the super - it gives an error that results in your function not found
    2. Use eventListeners
    3. Delegate the delete click
    4. Be DRY (Don't Repeat Yourself)

    class Task {
      static nextId = 1;
      constructor(title) {
        this.id = Task.nextId++;
        this.title = title;
      }
    }
    
    window.addEventListener('load', () => {
      const tasks = []; // to hold all tasks
      const taskContent = document.getElementById('taskcontent');
      const addTaskButton = document.getElementById('addTaskButton');
      const taskContainer = document.getElementById('taskcontainer');
    
      // Render tasks into the container - I use template literals
      const renderTasks = () => {
        taskContainer.innerHTML = tasks
          .map(task => `
            <div class="task-item" data-id="${task.id}">
              <span>${task.title}</span>
              <button class="delete-btn">Delete</button>
            </div>`)
          .join('');
      };
    
      const createTask = () => {
        const title = taskContent.value.trim();
        if (!title) return;
        tasks.push(new Task(title));
        renderTasks();
        taskContent.focus(); // make it possible to rewrite the task
        taskContent.select();// and overwrite it too. 
      };
      // you COULD use a form and the submit event to not even need to click  - then you would use e.preventDefault() to stop the submission
      addTaskButton.addEventListener('click', createTask); // when clicked
      // Use event delegation to handle delete clicks
      taskContainer.addEventListener('click', e => {
        const tgt = e.target.closest('button.delete-btn'); // is it a delete button
        if (!tgt) return; // no it was not
        const task = tgt.closest('.task-item');
        const taskId = +task.dataset.id;
        const index = tasks.findIndex(task => task.id === taskId);
        if (index > -1) { // did we find the task in the array?
          tasks.splice(index, 1); // delete it
          renderTasks();
        }
      });
    });
    <textarea id='taskcontent'></textarea>
    <button id="addTaskButton" type="button">+</button>
    <div id='taskcontainer'>
    </div>