当脚本只运行一次时,它会运行很多次

时间:2012-12-04 18:03:41

标签: php javascript ajax

我有一个唠叨的问题,我花了很多时间试图解决没有运气。我有一个表单用于从我们的数据库中删除项目。这是表格: 编辑:我已将代码更新为更合理的内容,但我仍有问题。

    <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>

处理这个的js是:

        $("#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是:

    <?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();
?>

问题在于,当我尝试运行它时,即使只删除一条记录,它也会运行数百次。 知道我可能做错了什么,以及如何解决它?

2 个答案:

答案 0 :(得分:3)

A comment you made表明至少部分问题是客户端问题。

您可能已多次添加'click'事件侦听器。如果您添加事件侦听器的代码在循环中,那么您几乎肯定已经多次添加它。例如,如果页面上有多个表单并以下列方式附加侦听器,则只要按下提交按钮,就会多次触发它。

// 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
    });
});

当您使用与button上的form直接关联的事件侦听器时,您可能应该从事件侦听器函数return false;或调用e.preventDefault();(您必须将e参数添加到您的点击侦听器功能中,以避免按钮提交form。 (也许你已经在做类似的事了,但没有包含代码?)我假设你不打算重定向页面,否则你不会更新<div id="returnsNotice"></div>元素的内容。 / p>

另一个可能导致问题的方法是,您用于查找和添加单击侦听器的选择器是否不够具体。如果是这种情况,您可能一次将事件侦听器添加到多个按钮,因此按钮可能最终会有多个事件侦听器。

此外,在处理表单时,我认为通常最好避免将事件侦听器附加到特定表单元素(如按钮),以便触发提交,因为在各种提交方案中事情会变得复杂,例如当用户在文本输入字段具有焦点时命中enter键。作为替代方案,您可以使用附加到form元素的jQuery.submit()方法,并且应该由导致表单提交的任何情况触发。这将允许您执行一个函数(提交侦听器)并以更高的可靠性停止自动提交。这也将允许您在将required属性应用于表单元素(detailscompatibility)时利用内置的浏览器表单验证功能。

$("#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;

关于如何解决这个问题,我要做的第一件事是注释掉表单提交语句,以便将其排除在外。然后,在它的位置,添加一个console.log()语句来查看a)是否多次调用它并且b)尝试弄清楚如果多次调用它只执行一次。您还可以添加console.log()语句,以便在添加单击事件侦听器时执行,以确保您只添加一个单击事件侦听器。我在下面列出了这些更改。

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>");

我刚注意到的其他内容是arr变量实际上是Object,而不是Array。不确定这是否会影响PHP中的内容。而且,我注意到您的x值为1。这也意味着,如果arr被创建为Array,您将拥有undefined第一个元素。

另外,counter是什么?如果您基于此循环,可能需要查看。

作为解决问题的中间步骤,以下版本的JavaScript代码将取消在最近提交的未被阻止的1.2秒内进行的任何提交调用。我推荐这个作为解决方案(这是非常可怜的),但它可能有助于解决问题存在的问题。

(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>");

如果这不能让你在任何地方,你可能想要在你的问题中详细说明。包含其他代码会很有帮助。也许更长的PHP / HTML摘录将至少显示整个form元素。此外,包括更全面的JavaScript摘录也可能有所帮助。例如,表单提交按钮的单击事件侦听器永远不会在帖子中提供的摘录中关闭。这使得很难看到真正发生的事情。

如果你要做很多JS,那么这可能值得一读。它有点过时,但它是浏览器调试工具的精彩介绍:

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

答案 1 :(得分:2)

如果没有看到完整的上下文,我猜测点击是由一些重复触发的。这个小小的黑客可能会解决它:

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;
    }
});