简体   繁体   中英

Method fired multiple times on click event

I'm building a web app in which the user can type in any key word or statement and get in return twenty results from wikipedia using the wikipedia API. AJAX works just fine. When the web app pulls data from wikipedia it should display each result in a DIV created dynamically.

What happens is that, when the click event is fired, the twenty DIVs are created five times, so one hundred in total. I don't know why but, as you can see in the snippet below, the web app creates twenty DIVs for each DOM element that has been hidden (through .hide) when the click event is fired.

Here's is the code:

 function main() { function positive() { var bar = document.getElementById("sb").childNodes[1]; var value = bar.value; if (!value) { window.alert("Type in anything to start the research"); } else { var ex = /\\s+/g; var space_count = value.match(ex); if (space_count == null) { var new_text = value; } else { new_text = value.replace(ex, "%20"); //console.log(new_text); } url = "https://en.wikipedia.org/w/api.php?action=query&format=json&prop=&list=search&continue=-%7C%7C&srsearch=" + new_text + "&srlimit=20&sroffset=20&srprop=snippet&origin=*"; var request = new XMLHttpRequest(); request.open("GET", url); //request.setRequestHeader("Api-User-Agent", "Example/1.0"); request.onload = function() { var data = JSON.parse(request.responseText); render(data); //console.log(data); } request.send(); } } function render(data) { $("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow", function() { $("#sb input").css({ "float":"left", "margin-left":"130px" }); $("#first_btn").css({ "float":"left" }); var title = data.query.search[0].title; var new_text = document.createTextNode(title); var new_window = document.createElement("div"); new_window.appendChild(new_text); new_window.setAttribute("class", "window"); var position = document.getElementsByTagName("body")[0]; position.appendChild(new_window); //} }); } var first_btn = document.getElementById("first_btn"); first_btn.addEventListener("click", positive, false); } $(document).ready(main); 
 html { font-size: 16px; } * { margin: 0; padding: 0; box-sizing: border-box;ù } .align { text-align: center; } #first_h1 { margin-top: 30px; } #first_h3 { margin-bottom: 30px; } #sb { margin-bottom: 10px; } #second_h1 { margin-top: 30px; } #second_h3 { margin-bottom: 30px; } .window { width: 70%; height: 150px; border: 3px solid black; margin: 0 auto; margin-top: 20px; } 
 <!DOCTYPE html> <html lang="en"> <head> <title>Wikipedia Viewer</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="css/main.css"> </head> <body> <h1 class="align" id="first_h1">Wikipedia Viewer</h1> <h3 class="align" id="first_h3">Type in a key word about the topic you are after<br>and see what Wkipedia has for you..</h3> <p class="align" id="sb"> <input type="text" name="search_box" placeholder="Write here"> <label for="search_box">Your search starts here...</label> </p> <p class="align" id="first_btn"> <input type="submit" value="SEND"> </p> <h1 class="align" id="second_h1">...Or...</h1> <h3 class="align" id="second_h3">If you just feel eager of random knowledge,<br>punch the button below and see what's next for you...</h3> <p class="align" id="second_btn"> <input type="submit" value="Enjoy!"> </p> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script> window.jQuery || document.write('<script src="js/jquery-3.2.1.min.js"><\\/script>') </script> <script type="text/javascript" src="js/script.js"></script> </body> </html> 

I made the code easier to read by erasing the for loop. As you can see, even with just one result, it is displayed five times.

Do you know guys why it happens? thanks

The line:

$("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow", function() {})

Says, for every element in this "list", hide the element and run this block of code after hidden.

This code is the culprit:

$("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow", 
function() {...});

The callback function is called five times, one for each ID listed, not once for all of them, as you might expect.

A workaround is to create a class (say, "hideme"), apply it to each element you want to hide, and write:

$('.hideme').hide("slow", function() {...});
function render(data) {

    $("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow", function() {
        $("#sb input").css({
            "float":"left",
            "margin-left":"130px"
        });
        $("#first_btn").css({
            "float":"left"
        });
    });  // Finish it here..
          var title = data.query.search[0].title;
          var new_text = document.createTextNode(title);
            var new_window = document.createElement("div");
          new_window.appendChild(new_text);
          new_window.setAttribute("class", "window");

            var position = document.getElementsByTagName("body")[0];
            position.appendChild(new_window);

      //}
  //  });   Move this line..

}

As described in the docs :

complete : A function to call once the animation is complete, called once per matched element.

Which means this line will call the handle function 5 times with 5 matched elements.

$("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow", function() {

The easiest solution is moving the render codes outside of the hide event handler

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