10

我正在使用可排序的 jQuery UI 对连接列表进行排序。更新事件似乎运行了两次。

这是完整的可排序调用:

$(".pageContent").sortable({
    handle: ".quesText",
    connectWith: ".pageContent",
    containment: "section",
    start: function(e, ui){
        ui.placeholder.height(ui.item.height());
    },
    placeholder: "sortable-placeholder",
    opacity: 0.5,
    cursor: "move",
    cancel: "input, select, button, a, .openClose",
    update: function(e, ui){
        var thisItem = ui.item;
        var next = ui.item.next();
        var prev = ui.item.prev();

        var thisNumber = thisItem.find(".quesNumb");
        var nextNumber = next.find(".quesNumb");
        var prevNumber = prev.find(".quesNumb");

        var tn = parseInt(thisNumber.text());
        var nn = parseInt(nextNumber.text());
        var pn = parseInt(prevNumber.text());

        var quesNumbs = $(".quesNumb");

        var newItemId = thisItem.attr("id").replace(/_\d+$/, "_");

        //test if we are dragging top down
        if(ui.position.top > ui.originalPosition.top){
            quesNumbs.each(function(i){
                var thisVal = parseInt($(this).text());
                var grandparent = $(this).parent().parent();
                var grandId = grandparent.attr("id").replace(/_\d+$/, "_");
                if(thisVal > tn && (thisVal <= pn || thisVal <= (nn - 1))){
                    $(this).text(thisVal - 1 + ".");
                    grandparent.attr("id",grandId + (thisVal - 1));
                }
            });
            if(!isNaN(pn) || !isNaN(nn)){
                if(!isNaN(pn)){
                    //for some reason when there is a sender pn gets updated, so we check if sender exists
                    //only occurs sorting top down
                    if($.type(ui.sender) !== "null"){
                        var senderId = ui.sender.attr("id");
                        thisNumber.text(pn + 1 + ".");
                        thisItem.attr("id",senderId + "_" + (pn + 1));
                        alert(thisItem.attr("id"));
                    }
                    else {
                        thisNumber.text(pn + ".");
                        thisItem.attr("id",newItemId + pn);
                        alert(thisItem.attr("id"));
                    }
                }
                else {
                    thisNumber.text(nn - 1 + ".");
                }
            }
            else {
                   //something will happen here
            }
        }
        //otherwise we are dragging bottom up
        else {
            quesNumbs.each(function(i){
                var thisVal = parseInt($(this).text());
                if(thisVal < tn && (thisVal >= nn || thisVal >= (pn + 1))){
                    $(this).text(thisVal + 1 + ".");
                }
            });
            if(!isNaN(pn) || !isNaN(nn)){
                if(!isNaN(pn)){
                    thisNumber.text(pn + 1 + ".");
                }
                else {
                    thisNumber.text(nn + ".");
                }
            }
            else {
               //something will happen here
            }
        }
    }
});

这是似乎运行两次的部分:

                if($.type(ui.sender) !== "null"){
                    var senderId = ui.sender.attr("id");
                    thisNumber.text(pn + 1 + ".");
                    thisItem.attr("id",senderId + "_" + (pn + 1));
                    alert(thisItem.attr("id"));
                }
                else {
                    thisNumber.text(pn + ".");
                    thisItem.attr("id",newItemId + pn);
                    alert(thisItem.attr("id"));
                }

当排序保持在同一个列表alertui.sender时,我希望只得到一个。null当一个项目离开一个列表去另一个然后ui.sender将不再是null

问题是当我将项目移动到新列表时会收到2条警报消息。好像 ui.sender 在更新函数运行一次后设置,然后再次运行更新函数。显然这不好,因为我正在覆盖不一定应该被覆盖的数据。

如果是这种情况,我应该如何重写我的代码以避免覆盖数据?

编辑

我相信每次更改列表 DOM 时都会调用更新事件,而不仅仅是一般的 DOM。因此,对于每个具有 DOM 更改的列表,更新都会运行。当我将一个项目移动到一个新列表时,我正在更新两个列表。

所以我想新的问题是:我如何重写这段代码,知道它会触发两次?是否有可以实现此目的的 Receive 和 Remove 事件的组合?

4

2 回答 2

46

我对每个可排序的事件进行了一些调查。以下是我的发现,按它们发生的顺序列出:

$(".pageContent").sortable({
    start: function(e,ui){
        //Before all other events
        //Only occurs once each time sorting begins
    },
    activate: function(e,ui){
        //After the start event and before all other events
        //Occurs once for each connected list each time sorting begins
    },
    change: function(e,ui){
        //After start/active but before over/sort/out events
        //Occurs every time the item position changes
        //Does not occur when item is outside of a connected list
    },
    over: function(e,ui){
        //After change but before sort/out events
        //Occurs while the item is hovering over a connected list
    },
    sort: function(e,ui){
        //After over but before out event
        //Occurs during sorting
        //Does not matter if the item is outside of a connected list or not
    },
    out: function(e,ui){
        //This one is unique
        //After sort event before all drop/ending events unless **see NOTE
        //Occurs, only once, the moment an item leaves a connected list
        //NOTE: Occurs again when the item is dropped/sorting stops 
        //--> EVEN IF the item never left the list
        //--> Called just before the stop event but after all other ending events
    },
    beforeStop: function(e,ui){
        //Before all other ending events: update,remove,receive,deactivate,stop
        //Occurs only once at the last possible moment before sorting stops
    },
    remove: function(e,ui){
        //After beforeStop and before all other ending events
        //Occurs only once when an item is removed from a list
    },
    receive: function(e,ui){
        //After remove and before all other ending events
        //Occurs only once when an item is added to a list
    },
    update: function(e,ui){
        //After receive and before all other ending events
        //Occurs when the DOM changes for each connected list
        //This can fire twice because two lists can change (remove from one
        //list but add to another)
    },
    deactivate: function(e,ui){
        //After all other events but before out (kinda) and stop
        //Occurs once for each connected list each time sorting ends
    },
    stop: function(e,ui){
        //After all other events
        //Occurs only once when sorting ends
    }
});

在解决我的问题时,我只是通过将更新函数的内容包装在if else检查ui.sender. 基本上它说如果ui.sender不存在,那么这是第一次通过更新功能,我们应该做这个功能,否则什么也不做。

于 2013-03-15T16:37:38.120 回答
1

我在这里发布了答案:jquery Sortable connectWith call the update method两次

您可以组合删除和接收并创建一个包含更改的数组,然后将其作为 JSON 发布到服务器。

演示:http: //jsfiddle.net/r2d3/p3J8z/

HTML:

<div class="container">
    <div class="step" id="step_1">
        <h2 class="title">Step 1</h2>
        <div class="image" id="image_10">Image 10</div>
        <div class="image" id="image_11">Image 11</div>
        <div class="image" id="image_12">Image 12</div>
    </div>
    <div class="step" id="step_2">
        <h2 class="title">Step 2</h2>
        <div class="image" id="image_21">Image 21</div>
        <div class="image" id="image_22">Image 22</div>
        <div class="image" id="image_23">Image 23</div>
    </div>

JS:

   $(function(){

        /* Here we will store all data */
        var myArguments = {};   

        function assembleData(object,arguments)
        {       
            var data = $(object).sortable('toArray'); // Get array data 
            var step_id = $(object).attr("id"); // Get step_id and we will use it as property name
            var arrayLength = data.length; // no need to explain

            /* Create step_id property if it does not exist */
            if(!arguments.hasOwnProperty(step_id)) 
            { 
                arguments[step_id] = new Array();
            }   

            /* Loop through all items */
            for (var i = 0; i < arrayLength; i++) 
            {
                var image_id = data[i]; 
                /* push all image_id onto property step_id (which is an array) */
                arguments[step_id].push(image_id);          
            }
            return arguments;
        }   

        /* Sort images */
        $('.step').sortable({
            connectWith: '.step',
            items : ':not(.title)',
            /* That's fired first */    
            start : function( event, ui ) {
                myArguments = {}; /* Reset the array*/  
            },      
            /* That's fired second */
            remove : function( event, ui ) {
                /* Get array of items in the list where we removed the item */          
                myArguments = assembleData(this,myArguments);
            },      
            /* That's fired thrird */       
            receive : function( event, ui ) {
                /* Get array of items where we added a new item */  
                myArguments = assembleData(this,myArguments);       
            },
            update: function(e,ui) {
                if (this === ui.item.parent()[0]) {
                     /* In case the change occures in the same container */ 
                     if (ui.sender == null) {
                        myArguments = assembleData(this,myArguments);       
                    } 
                }
            },      
            /* That's fired last */         
            stop : function( event, ui ) {                  
                /* Send JSON to the server */
                $("#result").html("Send JSON to the server:<pre>"+JSON.stringify(myArguments)+"</pre>");        
            },  
        });
    });

解决方案的完整说明: http ://r2d2.cc/2014/07/22/jquery-sortable-connectwith-how-to-save-all-changes-to-the-database/

于 2014-07-22T19:58:27.530 回答