Home > database >  How do I get this div to show again using JavaScript
How do I get this div to show again using JavaScript

Time:07-08

I have made a TODO app and added a counter to keep a count of the items in the list. If the counter hits zero, I've set it to re-show a message 'You currently have no tasks. Use the input field above to start adding.'

if(count === 0){
  noTasksText.classList.remove('d-none');
}

In the console I print out the div and it doesn't have d-none in the class list any more which is what I want, however, in the actual DOM it does.

Here is a full example - https://codepen.io/tomdurkin/pen/LYdpXKJ?editors=1111

I really can't seem to work this out. I can't seem to interact with that div when the counter becomes zero, however I can get console logs etc to show when expected.

Any help would be appreciated!

const mainInput = document.querySelector('#main-input');
const todoContainer = document.querySelector('#todo-container');
const errorText = document.querySelector('#js-error');
const noTasksText = document.querySelector('.js-no-tasks')

let tasks = [];
let count = 0;

// focus input on load
window.onload = () => {
  mainInput.focus();

  const storedTasks = JSON.parse(localStorage.getItem('tasks'));

  if (storedTasks != null && storedTasks.length > 0) {

    // set count to number of pre-existing items
    count = storedTasks.length

    // hide the 'no tasks' text
    noTasksText.classList.add('d-none');

    // overwrite tasks array with stored tasks
    tasks = storedTasks;

    tasks.forEach(task => {
      // Build the markup
      const markup = `
        <div >
          <div >
            <div >
              <h5  data-title="${task}">${task}</h5>
            </div>
            <div >
              <button >Remove Item</button>
            </div>
          </div>
        </div>`;

      // Append it to the container
      todoContainer.innerHTML  = markup;
    });

  } else {
    if (noTasksText.classList.contains('d-none')) {
      noTasksText.classList.remove('d-none');
    }
  }

};

// event listener for 'enter on input' 
mainInput.addEventListener("keydown", e => {

  // if error is showing, hide it!
  if (!errorText.classList.contains('d-none')) {
    errorText.classList.add('d-none');
  }

  if (e.key === "Enter") {

    // Get the value of the input
    let inputValue = mainInput.value;

    if (inputValue) {

      // Build the markup
      const markup = `
        <div >
          <div >
            <div >
              <h5  data-title="${inputValue}">${inputValue}</h5>
            </div>
            <div >
              <button >Remove Item</button>
            </div>
          </div>
        </div>`;

      // hide 'no tasks' text 
      noTasksText.classList.add('d-none');

      // Append it to the container
      todoContainer.innerHTML  = markup;

      // Push value to 'tasks' array
      tasks.push(inputValue);

      // Put in localStorage
      textTasks = JSON.stringify(tasks);
      localStorage.setItem("tasks", textTasks);

      // Reset the value of the input field
      mainInput.value = '';

      // add 1 to the count 
      count  

    } else {
      // Some very basic validation
      errorText.classList.remove('d-none');
    }

  }
});

// remove task

todoContainer.addEventListener('click', (e) => {

  // Find the button in the row that needs removing (bubbling)
  const buttonIsDelete = e.target.classList.contains('js-remove-task');

  if (buttonIsDelete) {

    // Remove the HTML from the screen
    e.target.closest('.js-single-task').remove();

    // Grab the name of the single task
    let taskName = e.target.closest('.js-single-task').querySelector('.js-single-task-name h5').getAttribute('data-title');

    // filter out the selected word
    tasks = tasks.filter(item => item != taskName);

    textTasks = JSON.stringify(tasks);
    localStorage.setItem("tasks", textTasks);

    // update counter 
    count--

    // check if counter is zero and re-show 'no tasks' text if true
    if (count === 0) {
      noTasksText.classList.remove('d-none');
      console.log(noTasksText);
    }

  }

});
body {
  background: #e1e1e1;
}
<div >

  <div >
    <div >
      <div >
        <h2>To dos</h2>
        <p>
          Use this app to keep a list of things you need to do
        </p>
        <input  id="main-input" type="text" placeholder="Type your todo and hit enter..."  />
        <small id="js-error" >
        Please type a value and press enter
      </small>
        <hr />
        <h4 >Your 'To dos'</h4>
        <div id="todo-container">
          <!-- todos append in here -->
          <div >
            <small >
            <i>
              You currently have no tasks. Use the input field above to start adding
            </i>
          </small>
          </div>
        </div>
      </div>
      <!-- /card -->
    </div>
  </div>

</div>

CodePudding user response:

You can do the following, it will work (here innerHTML is changing the DOM, so I added an extra function to recalculate elements after DOM is changed due to innerHTML):

var mainInput = document.querySelector("#main-input");
var todoContainer = document.querySelector("#todo-container");
var errorText = document.querySelector("#js-error");
var noTasksText = document.querySelector(".js-no-tasks");

let tasks = [];
let count = 0;

function getAllElements() {
  mainInput = document.querySelector("#main-input");
  todoContainer = document.querySelector("#todo-container");
  errorText = document.querySelector("#js-error");
  noTasksText = document.querySelector(".js-no-tasks");
}
// focus input on load
window.onload = () => {
  mainInput.focus();

  var storedTasks = JSON.parse(localStorage.getItem("tasks"));

  if (storedTasks != null && storedTasks.length > 0) {
    // set count to number of pre-existing items
    count = storedTasks.length;

    // hide the 'no tasks' text
    noTasksText.classList.add("d-none");

    // overwrite tasks array with stored tasks
    tasks = storedTasks;

    tasks.forEach((task) => {
      // Build the markup
      const markup = `
        <div >
          <div >
            <div >
              <h5  data-title="${task}">${task}</h5>
            </div>
            <div >
              <button >Remove Item</button>
            </div>
          </div>
        </div>`;

      // Append it to the container
      todoContainer.innerHTML  = markup;
      getAllElements();
    });
  } else {
    if (noTasksText.classList.contains("d-none")) {
      noTasksText.classList.remove("d-none");
    }
  }
};

// event listener for 'enter on input'
mainInput.addEventListener("keydown", (e) => {
  // if error is showing, hide it!
  if (!errorText.classList.contains("d-none")) {
    errorText.classList.add("d-none");
  }

  if (e.key === "Enter") {
    // Get the value of the input
    let inputValue = mainInput.value;

    if (inputValue) {
      // Build the markup
      const markup = `
        <div >
          <div >
            <div >
              <h5  data-title="${inputValue}">${inputValue}</h5>
            </div>
            <div >
              <button >Remove Item</button>
            </div>
          </div>
        </div>`;

      // hide 'no tasks' text
      noTasksText.classList.add("d-none");

      // Append it to the container
      todoContainer.innerHTML  = markup;
      getAllElements();

      // Push value to 'tasks' array
      tasks.push(inputValue);

      // Put in localStorage
      textTasks = JSON.stringify(tasks);
      localStorage.setItem("tasks", textTasks);

      // Reset the value of the input field
      mainInput.value = "";

      // add 1 to the count
      count  ;
    } else {
      // Some very basic validation
      errorText.classList.remove("d-none");
    }
  }
});

// remove task

todoContainer.addEventListener("click", (e) => {
  // Find the button in the row that needs removing (bubbling)
  const buttonIsDelete = e.target.classList.contains("js-remove-task");

  if (buttonIsDelete) {
    // Remove the HTML from the screen
    e.target.closest(".js-single-task").remove();

    // Grab the name of the single task
    let taskName = e.target
      .closest(".js-single-task")
      .querySelector(".js-single-task-name h5")
      .getAttribute("data-title");

    // filter out the selected word
    tasks = tasks.filter((item) => item != taskName);

    textTasks = JSON.stringify(tasks);
    localStorage.setItem("tasks", textTasks);

    // update counter
    count--;

    // check if counter is zero and re-show 'no tasks' text if true
    if (count === 0) {
      noTasksText.classList.remove("d-none");
      console.log(noTasksText);
    }
  }
});
body {
  background: #e1e1e1;
}
<div >

  <div >
    <div >
      <div >
        <h2>To dos</h2>
        <p>
          Use this app to keep a list of things you need to do
        </p>
        <input  id="main-input" type="text" placeholder="Type your todo and hit enter..."  />
        <small id="js-error" >
        Please type a value and press enter
      </small>
        <hr />
        <h4 >Your 'To dos'</h4>
        <div id="todo-container">
          <!-- todos append in here -->
          <div >
            <small >
            <i>
              You currently have no tasks. Use the input field above to start adding
            </i>
          </small>
          </div>
        </div>
      </div>
      <!-- /card -->
    </div>
  </div>

</div>

CodePudding user response:

Upon setting innerHTML by using = innerHTML the node noTasksText is lost, because browser processes the whole new set innerHTML and creates new objects. You can either retrieve noTasksText again after that, or append nodes using todoContainer.appendChild. I forked your pen and solved it with the latter solution.

https://codepen.io/aghosey/pen/wvmGwWd

  • Related