3

I am making something like a clicker in Javascript and the "onclick" only works once unless I refresh the page.

My HTML code :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
    <div id="main">
        <button id="o"> Click Me</button>
    </div>
    <script type="module" src="/main.js"></script>
</body>
</html>

JS code :

import './style.css';

let x = 0;

document.querySelector('#main').innerHTML = `
    <button id="o">Click Me</button>
    <p>${x}</p>
`;

document.querySelector("#o").onclick = function() {
    x++;
    console.log(x);
    document.querySelector('#main').innerHTML = `
        <button id="o">Click Me</button>
        <p>${x}</p>
    `;
};

When I open the console, I only see the log "1" when I first click the button, not afterwards. There is no CSS styling.

I am using Vite to make this.

Cal1um Y30
  • 31
  • 1
  • 5
    That's because you're reinserting elements into the DOM, the initial event is no longer attached to those new buttons. Now, it all depends on what is the task you want to accomplish. Reinserting a new button all over again seems quite an odd thing to do. – Roko C. Buljan Jun 29 '23 at 11:00
  • 1
    Don't use `innerHTML` to set a new button, use `appendchild`. – 0stone0 Jun 29 '23 at 11:00
  • Is there any reason you're not including the `

    ` element in the initial markup?

    – Andy Jun 29 '23 at 11:17

1 Answers1

0

You're adding the click event only to the existing button.
Then, you're (for some unknown reason) reinserting a similar element and expecting it to have the event attached to. What you need is Event delegation, where the listener is attached to a static element, and only within the function you check the actual event.target.
Also, keep your code DRY (Don't repeat yourself) and keep your template creation within a single function:

let x = 0;
const elMain = document.querySelector('#main');
const updateMainHTML = () => elMain.innerHTML = `
  <button id="o">Click Me</button>
  <p>${x}</p>
`;

elMain.addEventListener("click", (evt) => {
  if (!evt.target.closest("#o")) return; // Do nothing. Not our button
  x++;
  updateMainHTML();
});

updateMainHTML();
<div id="main">
  <button id="o"> Click Me</button>
</div>

I have no clue why you would want to dynamically insert elements after every click all over again.
This is all it takes for the exact same UI:

let x = 0;

const elMain = document.querySelector('#main');

const elResult = Object.assign(document.createElement("p"), {
  textContent: x
});

const elBtn = Object.assign(document.createElement("button"), {
 type: "button",
 textContent: "Click me",
 onclick() {
   x += 1;
   elResult.textContent = x;
 }
});

elMain.append(elBtn, elResult);
<div id="main"></div>

or the super-basic - without any dynamic elements insertion:

let x = -1;

const elButton = document.querySelector('#o');
const elResult = document.querySelector('#result');
const incrementX = () => {
  x += 1;
  elResult.textContent = x;
};

incrementX(); // Do it immediately
elButton.addEventListener("click", incrementX); // and on btn click
<div id="main">
  <button type="button" id="o">Click me</button>
  <p id="result">0</p>
</div>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
  • A site question: What is the difference between ``and ``? – Reporter Jun 29 '23 at 11:19
  • 2
    There is no difference in this case. But if you use it inside a form, the button will not submit. https://stackoverflow.com/questions/41904199/whats-the-point-of-button-type-button – Wimanicesir Jun 29 '23 at 11:23
  • @Reporter as Wimanicesir said; ` – Roko C. Buljan Jun 29 '23 at 11:32