skip to Main Content

I set up a webpage with two headings, and two buttons. The webpage looks exactly like the following before pressing on anything:

Counter-1 : (somenumber)
[button]

Counter-2: (somenumber)
[button]


If I click on the first button, the somenumber increments by 1.
If I click on the second button, the somenumber decrements by 1.

In addition, when I click on the first button(increment-button), a list-item gets added to the webpage. When I click on the second button(decrement-button), the last added list-item gets removed from the webpage.

Both buttons work and do their purpose (incrementing/decremnting wise), and when I click on the first button, a list-item indeed gets added to the webpage.

The problem occurs when I try to remove the last added list item, by pressing the second button, as described.

This is the html section. Nothing out of the ordinary. Two headings, and two buttons.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Counter-1: <span id="counter-one">0</span></h1>
    <button id="increment">click me</button>

    <h1>Counter-2: <span id="counter-two">0</span></h1>
    <button id="decrement">click me</button>

    <ul id="list-items"></ul>

    <script src="script.js" type="text/javascript"></script>
  </body>
</html>

This is the JavaScript section. I get the two buttons from the HTML document, I set up an empty list on the HTML document, which I wanted to fill with one list-item per click on the first button (using javascript, hence making the button interactive).

const incrementButton = document.getElementById("increment");
const decrementButton = document.getElementById("decrement");
const ulElement = document.getElementById("list-items");

let counter = 0;

function incrementCounter() {
  const counterInc = document.getElementById("counter-one");
  counter++;
  counterInc.innerText = counter;

  //create an element
  const li = document.createElement("li");
  li.setAttribute("data-counter", counter);
  li.innerHTML = "<b>Something</b> " + counter;
  console.log(li);

  //append it to the list
  ulElement.appendChild(li);
}

function decrementCounter() {
  //remove an element
  const li = ulElement.querySelector("[data-counter = " + counter + "]");
  li.remove();

  const counterDec = document.getElementById("counter-two");
  counter--;
  counterDec.innerText = counter;
}

incrementButton.addEventListener("click", incrementCounter);
decrementButton.addEventListener("click", decrementCounter);

The mechanism of incrementing and decrementing the value is working properly, and the appending of the list-items works as well, as mentioned.

But the line:
const li = ulElement.querySelector("[data-counter = " + counter + "]");

used to "catch" the last added list-item,

is causing the following error:
Uncaught DOMException: Failed to execute 'querySelector' on 'Element': '[data-counter = 4]' is not a valid selector. at HTMLButtonElement.decrementCounter

And I don’t understand why the querySelector is invalid. I am certain that I have written something incorrect, or perhaps, an obsolete statement. How can I fix it?

3

Answers


  1. The counter should be wrapped in quotes (and no blank spaces!) when used in data attribute selector. Use instead Template Literals:

    ulElement.querySelector(`[data-counter="${counter}"]`);
    

    or, if you insist in double quotes escape them with backslash like:

    ulElement.querySelector("[data-counter=""+ counter +""]");
    

    or, use single quotes to preserve double quotes like:

    ulElement.querySelector('[data-counter="'+ counter +'"]');
    
    Login or Signup to reply.
  2. Adding quotation marks before and after the counter variable appears to fix the query selector error. Change the line to 1 of the 3 lines below:

    const li = ulElement.querySelector('[data-counter = "' + counter + '"]');
    
    const li = ulElement.querySelector("[data-counter = '" + counter + "']");
    
    const li = ulElement.querySelector("[data-counter = "" + counter + ""]");
    

    You could also use a template literal, as mentioned by Roko C. Buljan above.

    Login or Signup to reply.
  3. Your selector is off just a bit. You had

    ulElement.querySelector("[data-counter = " + counter + "]")
    

    but it needs to have quotes around the value added like this, and probably remove the spaces around the = as well

    ulElement.querySelector("[data-counter='" + counter + "']")
    
    const incrementButton = document.getElementById("increment");
    const decrementButton = document.getElementById("decrement");
    const ulElement = document.getElementById("list-items");
    
    let counter = 0;
    
    function incrementCounter() {
      const counterInc = document.getElementById("counter-one");
      counter++;
      counterInc.innerText = counter;
    
      //create an element
      const li = document.createElement("li");
      li.setAttribute("data-counter", counter);
      li.innerHTML = "<b>Something</b> " + counter;
      console.log(li);
    
      //append it to the list
      ulElement.appendChild(li);
    }
    
    function decrementCounter() {
      //remove an element
      const li = ulElement.querySelector("[data-counter='" + counter + "']");
      li.remove();
    
      const counterDec = document.getElementById("counter-two");
      counter--;
      counterDec.innerText = counter;
    }
    
    incrementButton.addEventListener("click", incrementCounter);
    decrementButton.addEventListener("click", decrementCounter);
    <h1>Counter-1: <span id="counter-one">0</span></h1>
    <button id="increment">click me</button>
    
    <h1>Counter-2: <span id="counter-two">0</span></h1>
    <button id="decrement">click me</button>
    
    <ul id="list-items"></ul>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search