0

I have checked another questions like this one on stackoverflow, but it doesn't solved my problem.

My problem is that whenever I add events to dynamic added elements. but it doesn't work in case I click on that element. It means that it doesn't work properly.

Here is what I have implemented:

function init() {
    let promptMessage = 'Enter the number of rows and columns'
    let promptDefault = '1 1';
    let prompt = this.prompt(promptMessage, promptDefault);
    if (prompt) {
        prompt = prompt.split(" ")
        console.log(prompt);
        prompt[0] = Number(prompt[0]);
        prompt[1] = Number(prompt[1]);
        return prompt;
    }
    return init()
}

function selected(i, j) {
    return console.log(`You clicked on row ${i} and column ${j}`)
}

var gameSize = init(),
    rows = gameSize[0],
    cols = gameSize[1],
    boardGame = document.querySelector('.board');

for (var i = 0; i < rows; i++) {
    for (var j = 0; j < cols; j++) {
        let div = document.createElement('div');
        div.className = `block cell-${i}-${j}`;
        div.addEventListener("click", selected(i, j));
        boardGame.appendChild(div);
    }
}

Problem: I expect that after entering numbers in prompt whenever I inspect the document see onclick="selected(i, j)" for each of elements. But it doesn't work so. Since the browser render the html file, it console.log all the elements, in case I didn't click on them. Where is the problem?

Somehow
  • 41
  • 7
  • 2
    `addEventListener` doesn't add on* attributes to the elements so you wouldn't see them on the Elements tab view of developers tools. Also you are setting the event function wrong, `selected(i, j)` executes the function immediately not set it to be called – Patrick Evans Nov 03 '18 at 18:38
  • @PatrickEvans How can I add a function that executes whenever I click on it? – Somehow Nov 03 '18 at 18:38

3 Answers3

0

From what I see, div.addEventListener("click", selected(i, j)); is the problematic line.

You're invoking the function selected here (this is why you see the logging on load) and assigning its value as the handler (which in this case is undefined). You're actually intending to assign the function.

Change

function selected(i, j) {
    return console.log(`You clicked on row ${i} and column ${j}`)
}

to

function selected(i, j) {
    return function(){
         console.log(`You clicked on row ${i} and column ${j}`);
    }
}

This use of higher order functions lets you close over i and j to build a function that, once invoked, logs the appropriate values

mistahenry
  • 8,554
  • 3
  • 27
  • 38
  • It works correctly, would you please explain what was the problem? and how it works in this way? – Somehow Nov 03 '18 at 18:40
  • `div.addEventListener("click", selected(i, j))` assigns whatever `selected()` returns as the event handler because the compiler sees `functionName` + `()` as function invocation. `div.addEventListener("click", selected)` would have assigned the selected function as the handler (as you though it would), but it wouldn't have worked like you wanted because you are not able to pass `i` and `j`. I modified it so that you could assign the return value of `selected(i,j)` as the handler, which in this case is a function that has access to `i` and `j` – mistahenry Nov 03 '18 at 18:46
  • Alternatively, you could have simply changed the behavior to `div.addEventListener("click", function(){ selected(i,j):})` and it would have worked all the same. – mistahenry Nov 03 '18 at 18:48
  • Thanks for your complete explanation :) <3 – Somehow Nov 03 '18 at 18:50
  • happy to help :) – mistahenry Nov 03 '18 at 18:51
0

You did bind the function wrong, it is executed the instantly, and the return value (null) is now your event listener. You need to bind it like a function.

ES5

div.addEventListener("click", function(){ selected(i, j) });

ES6

div.addEventListener("click", _ => selected(i, j));

You have another bug as well if you use the variables in the bind function as I showed, when you use var in your loop, the last value will the executed value when the event listener is executed, that bug can be solved if let is used instead

Benjaco
  • 303
  • 3
  • 11
0

As sunrize920 and Benjaco wrote, you have you eventListener wrong. What you probably need is a closure, like this:

div.addEventListener("click", function() {
  return selected(i, j)
});
HynekS
  • 2,738
  • 1
  • 19
  • 34
  • Would you please explain why it was wrong and explain what does this closure really do? – Somehow Nov 03 '18 at 18:47
  • By creating a closure you assign the value of **i** and **j** to when they are when the event listener is created. Otherwise, they are evaluated when the loops ends, so if you loop 3 times, they will be all 3 (events are asynchronous, which means they will "wait" for all other synchronous code to evaluate). – HynekS Nov 03 '18 at 18:52