2013-03-14 15 views
9

Używam sortowania jQuery UI do sortowania list połączonych. Wydarzenie aktualizacji wydaje się działać dwa razy.Dlaczego zdarzenie aktualizacji w jquery sortable wydaje się działać dwukrotnie podczas testowania dla ui.sender

Oto pełna sortable wezwanie:

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

Tutaj jest elementem, który wydaje się działać dwukrotnie:

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

spodziewam się dostać tylko jedną alert jak ui.sender jest null podczas sortowania pozostaje na tej samej liście. Gdy element opuści listę, aby przejść do innej, wówczas ui.sender nie będzie już null.

Problem polega na tym, że dostanę komunikaty ostrzegawcze po przeniesieniu elementu do nowej listy. Jest tak, jakby ui.sender został ustawiony po uruchomieniu funkcji aktualizacji, a następnie ponownie uruchamia funkcję aktualizacji. Oczywiście nie jest to dobre, ponieważ nadpisuję dane, które nie muszą być nadpisywane.

Jeśli tak, to w jaki sposób powinienem przepisać mój kod, aby uniknąć nadpisywania danych?

EDIT

wierzę zdarzenie aktualizacja jest wywoływana za każdym razem, gdy lista DOM ulega zmianie, nie tylko DOM w ogóle. Tak więc dla każdej listy, która ma zmianę DOM, uruchamiana jest aktualizacja. Kiedy przenosimy jeden element do nowej listy, aktualizuję dwie listy.

Więc domyślam się, że nowe pytanie brzmi: jak przerobić ten kod, wiedząc, że wystrzeli dwa razy? Czy istnieje kombinacja zdarzeń odbierania i usuwania, które mogą to osiągnąć?

Odpowiedz

42

Zrobiłem kilka badań w każdym wydarzenie sortable. Oto moje wnioski, wymienione w kolejności, w jakiej mają one miejsce:

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

W rozwiązaniu mojego problemu po prostu zmusić zawartość mojej funkcji aktualizacji, aby uruchomić tylko raz przez owinięcie go w oświadczeniu if else który sprawdza ui.sender. Zasadniczo mówi, że jeśli ui.sender nie istnieje, to jest to pierwszy raz za pośrednictwem funkcji aktualizacji i powinniśmy wykonać tę funkcję, w przeciwnym razie nic nie zrobimy.

+1

Niestety ale myślę, że istnieje co najmniej glitch w kolejności twoich wydarzeń: 'stop' nie jest ostatnim wydarzeniem, to "aktualizacja".Jeśli spojrzę na książkę [Dan Wellman's book "jQuery UI 1.8"] (http://my.safaribooksonline.com/book/-/9781849516525/the-sortables-component/ch13lvl1sec03) jako odniesienie do kopii zapasowej, to jest jasne że zdarzenie 'stop' występuje podczas sortowania, a zdarzenie' update' występuje, gdy sortowanie już się zakończyło, a DOM się zmienił ... Tak więc 'update' będzie się działo po' stop' i to całkiem logiczne, nie sądzisz? – Cholesterol

+3

@Cholesterol dziękuję za wkład, który ma więcej sensu. Ale informacja, którą tu otrzymałem, polegała na testowaniu każdego wydarzenia. Testowałem, wywołując console.log ("cokolwiek-to-zdarzenie-jest"), kiedy to zdarzenie jest uruchamiane. Moje wyniki to wydarzenie aktualizacji, które wysłało dziennik przed zdarzeniem stop. –

+6

Kod źródłowy nigdy nie leży: [sortable.js] (https://github.com/jquery/jquery-ui/blob/master/ui/sortable.js#L1281) - zdarzenie stop jest ostatnim wydarzeniem – tokarev

0

Mam wysłana odpowiedź tutaj: jquery Sortable connectWith calls the update method twice

można połączyć usuń i otrzymywania i utworzyć tablicę, która będzie trzymać zmiany i niż opublikować go na serwerze jako JSON.

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

Pełne wyjaśnienie rozwiązania: http://r2d2.cc/2014/07/22/jquery-sortable-connectwith-how-to-save-all-changes-to-the-database/

Powiązane problemy