简体   繁体   中英

Eventlistener wont register click

I've come accross something quite odd which I can't really figure out how to solve.

I'm working on a project at the university where we are tasked with making a game to meassure the intelligence of the user. Each game is it's own module.

The one I'm working on now basically displays a bunch of flags for a second before turning them over using window.setTimeout . This works absolutely fine, the transition and everything looks smooth. During the time I'm setting up the board (displaying the flags) I'm also giving each flag an eventListener , that listens to clicks , which flips a flag over on its Y-axis.

However the last part of the assignment is to create and display a list of the flags. I'm using a separate function called set_list which simply adds an ordered list to the innerHTML of the gameboard.

But whenever I add the list the eventListener breaks (ie. it simply wont active when clicking the overturned flags).

Here is a JSFiddle that might help describe the issue

The game itself is started when a button is clicked. So basically there is a button with its own eventListener which needs to be pressed for the gameboard to initiate:

document.getElementById('start').addEventListener('click', function(){
    setup_cards();
    create_cards();
    set_list(); 
});

And these are the two functions that seem to be making a mess of things:

function create_cards() {
    for (i = 0; i < cards_arr.length; i++) {
        if (i == 3 || i == 6) {
            flag_divs += "</div><div class='row flag-buffer'>"
        }
        if (flags[cards_arr[i]].name == 'Colombia' || flags[cards_arr[i]].name == 'Chile' || flags[cards_arr[i]].name == 'Japan') {
            flag_divs += "<div id='flag_" + i + "' class='flip-container col-xs-2 col-xs-offset-1'>" +
                        "<div class='front'>" +
                        "</div>" +
                        "<div class='back'>" +
                        specialflag(flags[cards_arr[i]].name) +
                        "</div>" +
                        "</div>";
        } else {
            flag_divs += "<div id='flag_" + i + "' class='flip-container col-xs-2 col-xs-offset-1'>" +
                            "<div class='front'>" +
                            "</div>" +
                            "<div class='back'>" +
                            "<div id='" + flags[cards_arr[i]].class + "' class='flag'> </div>" +
                            "</div>" +
                            "</div>";
        }
    }
    board.innerHTML = '<h3 class="text-center"> Memorize the flags </h3><div class="container-fluid"> <div class="row">' + flag_divs + '</div></div>';
    var myNodeList = document.getElementsByClassName('flip-container');



    for (var iterator = 0; iterator < myNodeList.length; iterator++) {

        var el = document.getElementById(myNodeList["flag_" + iterator].id);
        el.id = iterator;
        //console.log(el); 
        el.style.transform = 'rotateY(180deg)';
        el.classList.add('flipper');
        el.addEventListener('click', function () {
            animate(this);
        });
        var animate = function (sender) {
            sender.style.transform = "rotateY(0deg)";
            console.log("animating");
            sender.style.transform = "rotateY(180deg)";
            sender.classList.add('flipper');

        };
    }
    window.setTimeout(() => {
        for (var iterator = 0; iterator < myNodeList.length; iterator++) {
            var el = document.getElementById(myNodeList[iterator].id);
            el.id = iterator;
            el.style.transform = 'rotateY(0deg)';
            console.log("I'm done!");
        }
    }, 1000);
}

function set_list() {
    console.log("I'm in");
    var flag_list = "<ol>";
    for (var i = 0; i < cards_arr.length; i++) {
        flag_list += "<li>" + flags[cards_arr[i]].name + "</li>";
    }
    flag_list += "</ol>";
    board.innerHTML += flag_list;
    console.log(board.innerHTML);
}

Could you add some null tests after your getElementById() calls, eg:

if ( el == null ) { 
    // Error handler.
} else {
    // Your existing code.
}

Your problem is here:

board.innerHTML += flag_list;

What this is doing is asking for the contents of the board element as a HTML string, adding some more HTML to the end of that string, then deleting the contents of board and replacing them with the parsed string. The newly created start-button node doesn't have any event listener attached, so nothing happens.

Using element.innerHTML += some_html is a bad idea for many reasons, this being one of them. It is best to avoid using .innerHTML whenever you can.

  • Put as much of the text/HTML of your game as you can (in this case, the start button in particular, and also the instructional text) into the original static HTML instead of using JS to add it.
  • To manipulate existing HTML, use DOM node manipulation operations like document.createElement and element.appendChild which work in terms of the DOM tree instead of text.
  • A relatively safe use for .innerHTML is to set the initial contents of a newly created element.

That said, the simplest fix for your existing code is to change the order in which things happen so that you do the addEventListener after the last time you use innerHTML . That is, take the event listener code out of create_cards and put it (in a function or not, as you like) where it will be called after set_list() .


Also, constructing HTML by string concatenation, like you're doing

... + "<div id='" + flags[cards_arr[i]].class + "' class='flag'> </div>" + ...

is very bad practice because — not in this case but in others — it leads to XSS security bugs. Consider what happens if the string you're inserting contains a quote character.

Using the DOM methods ( createTextNode , setAttribute or properties, etc) to construct nodes is a good way to avoid XSS risks because you don't need to make sure text is quoted or sanitized.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM