10

jQuery UI sortable を使用して、接続されたリストをソートしています。更新イベントが 2 回実行されているようです。

完全なソート可能な呼び出しは次のとおりです。

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

2回実行されるように見える部分は次のとおりです。

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

並べ替えが同じリスト内にとどまる場合、 1つalertだけui.senderを取得することを期待しています。null項目が別の項目に移動するためにリストを離れると、それui.senderはなくなりますnull

問題は、アイテムを新しいリストに移動すると、 2 つの警告メッセージが表示されることです。更新関数が一度実行された後に ui.sender が設定されているかのように、更新関数が再度実行されます。必ずしも上書きされるべきではないデータを上書きしているので、明らかにこれは良くありません。

その場合、データを上書きしないようにコードを書き直すにはどうすればよいですか?

編集

一般的なDOMだけでなく、リストDOMが変更されるたびに更新イベントが呼び出されると思います。したがって、DOM の変更があるリストごとに更新が実行されます。1 つのアイテムを新しいリストに移動すると、2 つのリストが更新されます。

したがって、新しい問題は次のようになると思います: 2 回起動することを知っているこのコードをどのように書き直せばよいでしょうか? これを達成できる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私の問題を解決するには、 update 関数の内容を、をチェックするステートメントでラップして、一度だけ実行するように強制しますui.sender。基本的に、ui.senderが存在しない場合は update 関数を初めて使用するため、関数を実行する必要があり、それ以外の場合は何もしません。

于 2013-03-15T16:37:38.120 に答える
1

私はここに答えを投稿しました:jquery Sortable connectWithは更新メソッドを2回呼び出します

remove と receive を組み合わせて、変更を保持する配列を作成し、それを 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 に答える