简体   繁体   中英

script runs many times when it should only run once

I have a nagging problem that I have spent many hours trying to resolve with no luck. I have a form that is used to remove items from our database. Here is the form: EDIT: I have updated the code to something that is a little more reasonable, however I still have my problem.

    <div id="tabs-3">
            <p>Select Replenish for Books that will be for sale again.<br/>Select Remove for Books that will NOT be for sale again.</p>
            <br/>
            <table>
            <tr>
                <td><input type="radio" name="returnType" value="replenish" checked>Replenish<br></td>
                <td><input type="radio" name="returnType" value="remove">Remove<br></td>
            </tr>
            <tr>
                <td>&nbsp</th>
                <td>&nbsp</th>
            </tr>
            <tr>
                <th>SKU</th>
                <th>Order ID</th>
                <th>Quantity</th>
                <th>Location</th>
            </tr>
            <?php $numberofrow = 10;?>
<!--create the for loop-->
<?php for($counter = 1;$counter<=$numberofrow;$counter++){ ?>
<!--create 1 row for repeating-->
            <tr>
                <td><input type="text" id="sku<?php echo   $counter;?>"/></td>
                <td><input type="text" id="order<?php echo $counter;?>"/></td>
                <td><input type="text" id="reEnterQty<?php echo $counter;?>"/></td>
                <td>
                    <select id="reEnterLocation<?php echo $counter;?>" name="reEnterLocation" class="Location">
                        <option value="">--Select Location--</option>
                        <?php
                        $query = "SELECT location_id, location FROM location ORDER BY location";
                        $result = $conn->query($query);
                        while ($row = $result->fetch_assoc()) {
                            echo '<option value="' . $row['location_id'] . '" >' . $row['location'] . '</option>';
                        }
                        ?>
                    </select>
                </td>
            </tr>
            <?php }?>
            </table>
            <br/>


            <br/>
            <input type="button" id="reEnterSKU" value="Process Returns" /> <br/>

            <div id="returnsNotice"></div>
        </div>

The js to handle this is:

        $("#reEnterSKU").on('click', function() {

    if($("input[name=returnType]:checked").val() == "remove"){ //executes when Remove radio button is checked
        var arr = {};
        var counter = 0;

        for(var x=1;x<11;x++)
        {
            if($("#sku"+x).val() != "" && $("#order"+x).val() != ""){
            arr[x] ={sku: $("#sku"+x).val(), order: $("#order"+x).val(), quantity: $("#reEnterQty"+x).val()};   
            }
        }   
                $.ajax({
                    type: "POST",
                    async:false,
                    url: "invReturnsRemove.php",
                    dataType: "json",
                    data: {data: JSON.stringify(arr)},//({sku: $("#sku"+x).val(), order: $("#order"+x).val(), quantity: quantity}),
                    success: function(data){

                    }
                });



        $("#returnsNotice").html("<h3>" + x + " return(s) removed.</h3>");

invReturnsRemove.php is:

    <?php
require_once ('../db.php');
$conn = db_connect();
$n=0;

$data =json_decode($_POST['data'], true); 

foreach($data as $value){

$conn->query("UPDATE order_sold SET quantity = (quantity - {$data[$n]['quantity']}) WHERE sku = {$data[$n]['sku']} AND order_id = {$data[$n]['order']}");
$n++;}


$conn->close();
?>

The issue is that when I try to run it, even with only one record to remove, it runs hundreds of times. Any idea what I may be doing wrong, and how to fix it?

A comment you made suggests that at least part of the issue is client-side.

You may have added the 'click' event listener multiple times. If the code you add the event listener with is in a loop then you almost certainly have added it multiple times. For instance, if you have several forms on the page and are attaching listeners in the following manner, any time your submit button is pressed it will be triggered several times.

// THIS IS BAD
$('form').each(function() {
    $("#reEnterSKU").on('click', function(e) {
         // details of listener for form1
    });
    $("#reEnterSKU2").on('click', function(e) {
         // details of listener for form2
    });
    $("#reEnterSKU3").on('click', function(e) {
         // details of listener for form3
    });
});

As you're using an event listener directly associated with the button on the form , you should probably either return false; from the event listener function or call e.preventDefault(); (you will have to add the e parameter to your click listener function) to avoid the button submitting the form . (Maybe you're already doing something like that but did not include the code?) I'm assuming you're not intending to redirect the page, otherwise you wouldn't update the content of the <div id="returnsNotice"></div> element.

Another thing that could cause problems is if the selectors you're using to find and add click listeners to your buttons are not specific enough. If this is the case, you may be adding event listeners to more than one button at a time, and therefore a button might end up with more than one event listener.

Also, when working with forms, I believe it's generally best to avoid attaching event listeners to particular form elements, such as buttons, for the purposes of triggering submission as things can get complicated in the various submission scenarios, like when a user hits the enter key while a text input field has the focus. As an alternative, you can use the jQuery.submit() method which is attached to the form element and should be triggered by any situation that will cause the form to submit. This will allow you to execute a function (the submit listener) and halt the automatic submission with greater reliability. This will also allow you to leverage the browser's form validation functionality that comes built-in when you apply the required attribute to form elements ( details and compatibility ).

$("#your-form-id").submit(function() {

    if($("input[name=returnType]:checked").val() === "remove") { //executes when Remove radio button is checked
        var arr = [];
        var counter = 0;

        for(var x = 1; x < 11; x++)
        {
            if( $("#sku"+x).val() !== "" && $("#order"+x).val() !== ""){
                arr[x] = {
                    sku: $("#sku"+x).val(), 
                    order: $("#order"+x).val(), 
                    quantity: $("#reEnterQty"+x).val()
                };   
            }
        }
        console.log('FORM SUBMIT');

        $.ajax({
            type: "POST",
            async:false,
            url: "invReturnsRemove.php",
            dataType: "json",
            data: {data: JSON.stringify(arr)},//({sku: $("#sku"+x).val(), order: $("#order"+x).val(), quantity: quantity}),
            success: function(data){
                console.log('SUCCESS'); // how many times do you see this per button click?
            }
        });

        $("#returnsNotice").html("<h3>" + x + " return(s) removed.</h3>");

        // ... anything that remains in your function
        return false;

Regarding how to fix the issue, the first thing I would do is comment out the form submission statement to just take that out of the equation. Then, in its place, add a console.log() statement to see a) if it gets called multiple times and b) try to figure out how to have it execute only once if it is being called multiple times. You can also add a console.log() statement that gets executed when you're adding the click event listener to make sure you're only adding one click event listener. I've include these changes below.

console.log('ADDING FORM SUBMISSION click listener -- you should only see this once.');

$("#reEnterSKU").on('click', function(e) {

    e.preventDefault();

    if($("input[name=returnType]:checked").val() === "remove") { //executes when Remove radio button is checked
        var arr = [];
        var counter = 0;

        for(var x = 1; x < 11; x++)
        {
            if( $("#sku"+x).val() !== "" && $("#order"+x).val() !== ""){
                arr[x] = {
                    sku: $("#sku"+x).val(), 
                    order: $("#order"+x).val(), 
                    quantity: $("#reEnterQty"+x).val()
                };   
            }
        }
        console.log('FORM SUBMIT');
        /* 
        $.ajax({
            type: "POST",
            async:false,
            url: "invReturnsRemove.php",
            dataType: "json",
            data: {data: JSON.stringify(arr)},//({sku: $("#sku"+x).val(), order: $("#order"+x).val(), quantity: quantity}),
            success: function(data){
                console.log('SUCCESS');
            }
        }).fail(function(data) {
            console.log('FAIL');
        });
        */
        $("#returnsNotice").html("<h3>" + x + " return(s) removed.</h3>");

Something else I just noticed is the arr variable is actually an Object , not an Array . Not sure if that would affect things in PHP or not. And, I noticed you're starting x at a value of 1 . That also means, in the case that arr is created as an Array , you will have a undefined first element.

Also, what is counter ? If you're looping based on that, it could be something to look at.

As an intermediate step in trouble shooting thigns, the following version of the JavaScript code will cancel any submission calls made within 1.2 seconds of the most recent submission that was not blocked. I do not recommend this as a solution (it's quite wretched), but it might be helpful in trouble shooting where the problem(s) exist.

(function(undefined) { 
    if (window.blockSubmission === undefined) {
        window.blockSubmission = false;
    }
})();

$("#reEnterSKU").on('click', function() {

    // this will make sure your listener only gets called at most once every 1.2 seconds
    if (window.blockSubmission) {
        return false;
    } else {
        window.blockSubmission = true;
        setTimeout(function() { 
            window.blockSubmission = false;
        }, 1200);
    }

    if($("input[name=returnType]:checked").val() == "remove") { //executes when Remove radio button is checked
        var arr = [];
        var counter = 0;

        for(var x = 1; x < 11; x++)
        {
            if( $("#sku"+x).val() != "" && $("#order"+x).val() != ""){
                arr[x] = {
                    sku: $("#sku"+x).val(), 
                    order: $("#order"+x).val(), 
                    quantity: $("#reEnterQty"+x).val()
                };   
            }
        }
        console.log('FORM SUBMIT');

        $.ajax({
            type: "POST",
            async:false,
            url: "invReturnsRemove.php",
            dataType: "json",
            data: {data: JSON.stringify(arr)},//({sku: $("#sku"+x).val(), order: $("#order"+x).val(), quantity: quantity}),
            success: function(data){
                console.log('SUCCESS'); // how many times do you see this per button click?
            }
        });

        $("#returnsNotice").html("<h3>" + x + " return(s) removed.</h3>");

If that doesn't get you anywhere you might want to elaborate a bit in your question. Including additional code would be helpful. Maybe longer excerpts of your PHP / HTML that will show at least the entire form element. Also, including a more comprehensive excerpt of JavaScript might help, too. For instance, the click event listener for the form submission button is never closed in the excerpt provided in your post. That makes it tough to see what's really going on.

If you're going to be doing a lot of JS, then this might be worth a read. It's a little dated, but it's a fantastic intro to browser debug tools:

http://jtaby.com/2012/04/23/modern-web-development-part-1.html

Without seeing the full context, I'm guessing the click is being triggered by some duplication. This little hack may get around it:

var e = false;
$("#reEnterSKU").on('click', function() {
    if (e) return;

    if ($("input[name=returnType]:checked").val() == "remove") { //executes when Remove radio button is checked
        e = true;
        var arr = {};
        var counter = 0;

        for(var x=1;x<11;x++)
        {
            if ($("#sku"+x).val() != "" && $("#order"+x).val() != "") {
                arr[x] ={sku: $("#sku"+x).val(), order: $("#order"+x).val(), quantity: $("#reEnterQty"+x).val()};   
            }
        }  

        $.ajax({
            type: "POST",
            async:false,
            url: "invReturnsRemove.php",
            dataType: "json",
            data: {data: JSON.stringify(arr)},//({sku: $("#sku"+x).val(), order: $("#order"+x).val(), quantity: quantity}),
            success: function(data) {}
        });

        $("#returnsNotice").html("<h3>" + x + " return(s) removed.</h3>");
        e = false;
    }
});

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