2012-11-03 18 views
9

Jak byś to zrobił?Lista do posortowania metodą przeciągnij i upuść w Meteorzie

Pozycje na liście mogą odpowiadać zapisom w kolekcji, a ich pozycja na liście może odpowiadać polu w każdym rekordzie (być może "rangi"), która musiałaby zostać zaktualizowana po wystąpieniu zdarzenia "stop" .

Czy Meteor dobrze gra z jQueryUI Sortable? Co by się stało, gdyby wielu użytkowników próbowało przeciągnąć i posortować tę samą listę jednocześnie? Czy Meteor wymagałby niestandardowego zachowania podczas sortowania?

+1

Myślę, że można go wdrożyć dość łatwo. Tworzysz listę danych za pomocą typowych szablonów Meteor, a następnie użyjesz wywołania zwrotnego 'Template.name.render()', aby zastosować '$(). Sortable()'. Następnie można skonfigurować programy obsługi zdarzeń w tym samym miejscu, które mogłyby zaktualizować kolekcję po wywołaniu. – bento

+0

w przypadku, gdy ludzie nie czytają wszystkich odpowiedzi, na liście sortowalnej 0.9.0 z .system działa dobrze. mają przykład na ich repo tutaj https://github.com/meteor/meteor/blob/devel/examples/unfinished/reorderable-list – daxiangCODE

Odpowiedz

6

EDYCJA: Poniższa odpowiedź jest nieaktualna, odpowiedź @ cutemachine lub http://blog.differential.com/sortable-lists-in-meteor-using-jquery-ui jest znacznie bliżej stanu techniki.


Krótka odpowiedź brzmi: nie jest to łatwe, jeśli chcesz, aby była reaktywna. Aby utworzyć niereaktywną wersję, po prostu umieść szablon w znaczniku {{#constant}} i podłącz jquery-ui do sortowania w render jako sugerowany @bento.

Aby utworzyć wersję reaktywną, Twój widget do sortowania będzie musiał poradzić sobie z rzeczami zmieniającymi się pod nim (pomyśl o tym, by przeciągać w połowie, gdy dane same się zamieniają). Oto kilka myśli o tym, jak byś go o to:

  1. Niestety, to nie będzie to łatwe, aby go ożywić, który będzie prowadzić do słabego UX. Zostawmy to na razie na bok.

  2. Render elementy z czymś takim: {{#each items}} {{> item}} {{/item}}

    Ta sama będzie zmieniać kolejność gdy dane zstępuje z serwera (bez animacji).

  3. Ustaw każdy element tak, aby był renderowalny podczas przeciągania. Możesz albo

    i. Użyj czegoś podobnego do jquery-ui przeciągalnego i podpnij go w render na szablonie item. Możesz mieć problem z tym, ponieważ element bazowy może zniknąć podczas przeciągania, jeśli kolejność zmieni się z wcześniejszego.

    ii. zaimplementuj własny kod przeciągania, być może używając biblioteki niższego poziomu.

  4. Kiedy element jest przeciągany na pozycję, natychmiast zmieniaj kolejność na liście lokalnie (w ten sposób użytkownik powinien zobaczyć właściwą rzecz, mam nadzieję, że serwer będzie respektował zmianę .. ale nie wchodźmy też w to).

Myślę, że istnieje duża potrzeba takiego widgetu, wykonanego w błyskawiczny sposób. Jest na moim osobistym radarze (ale tak samo jest z wieloma rzeczami, w tym fajny sposób na ponowne zamówienie z animacją).

+0

Wygląda na to, że zawijanie {{#each}} za pomocą {{#constant} } nie ma żadnego efektu i umożliwia jquery sortable modyfikować dom powoduje, że meteor usuwa węzły lub wprowadza nieskończoną pętlę. –

+0

Nawet jeśli stała zadziałała, potrzebowałbym jakiegoś sposobu dodawania/usuwania elementów z listy, co, jak sądzę, musiałbym zaimplementować ręcznie? –

+0

Tak, dokładnie. Właśnie dlatego nie jestem wielkim fanem podejścia "{{#constant}}". Możesz to zrobić za pomocą polecenia "obserwuj". –

0

Udało mi się zaimplementować listę "przeciągnij i upuść", sortowalną i edytowalną, używając odpowiednio jQuery UI sortable i Meteor Collection Hooks i contentEditable. Aby zobaczyć częściowo działający przykład, sprawdź: this demo.

Moje wdrożenia jest w następujący sposób (niestety to nie będzie proste wtyczki i iść przykład, ale mam nadzieję dostać się demo i działa na tym konkretnym przykładzie wkrótce ):

Client JS do przeciągania, drop i zapisać:

Template.templateName.rendered = -> 
    Deps.autorun -> 
    $('#list').sortable 
     handle: '.handle' 
     stop: (event, ui) -> 
     _.each $(event.target).children('div'), (element, index, list) -> 
      Elements.update { _id: element.getAttribute('data-element-id') }, 
      $set: position: index + 1 

Niewiele rzeczy zauważyć tutaj, używam „uchwytu”, aby przeciągnąć element wokół, jak wewnątrz każdy dział istnieją inne przyciski i edycji treści. Po przeciągnięciu elementu przez użytkownika i upuszczeniu go na miejsce rozpoczyna się zdarzenie "stop" i aktualizuję każdy element na tej liście z nowym pozycjonowaniem.

Mam również możliwość dodawania elementów do strony, która zostanie umieszczona na dole listy. W przeciwnym razie prawdopodobnie uciekniesz z użyciem pakietów Meteor Collection Behaviours i/lub Mongo Counter. Jednak ja wykorzystane Meteor Collection Hooks#.before.insert następująco:

Collection przed hakiem

@Elements.before.insert (userId, doc) -> 
    highestElement = Elements.findOne({}, 
        sort: { position: -1 } 
        limit: 1 
        ) 
    position = if highestElement? then highestElement.position else 0 
    doc.position = position + 1 

Tutaj mamy po prostu coraz najwyższy dokument, sortowanie na atrybutem pozycji. Jeśli nie istnieje (np. Pierwszy element, który ma zostać utworzony), inicjalizujemy pozycje na początek 1.

PS: jeśli nie rozumiesz CoffeeScript, wykonaj kopię tego kodu do tego incredible tool (Js2coffee).

Edit: proszę zobaczyć autonomiczną wersję tutaj: demo (bardzo powolny na serwerach Meteor) i nowy silnik renderowania source code

1

** Aktualizacja do 1.0

Odjazd MeteorPad: http://meteorpad.com/pad/TzQTngcy7PivnCCjk/sortable%20demo

Oto wersja I wdrożone - bardzo podobny do @ tomsabin-tych, ale nie Zachowania Kolekcja potrzebne. To działa dobrze dla mnie z wieloma użytkownikami i jest reaktywne.

HTML (Prawdopodobnie nie jest to dobry pomysł, aby div id samo jak _id, jestem pewien, że znajdziesz lepsze obejścia.)

<template name="myList"> 
    <div class="step_list"> 
    {{#each card}} 
     {{> card_template}}   
    {{/each}} 
    </div> 
</template> 

<template name="card_template"> 
    <div class="card" id="{{_id}}">    
     <h3>{{name}}</h3> 
    </div> 
</template> 

JS

Template.myList.helpers ({ 
    card : function() { 
     return Cards.find({}, {sort: {pos: 1}} 
    )} 
}) 

Template.myList.rendered = function(){ 

    $(".step_list").sortable({ 
     items: ".card", 
     delay: 100, 
     refreshPositions: true, 
     revert: true, 
     helper: "clone", 
     scroll: true, 
     scrollSensitivity: 50, 
     scrollSpeed: 35, 
     start: function(event, ui) { 
     $(ui.helper).addClass("dragging"); 
     }, // end of start 
     stop: function(event, ui) { 
     $(ui.item).removeClass("dragging"); 
     }, // end of stop 
     update: function(event, ui) { 
     var index = 0;     
     _.each($(".card"), function(item) { 
      Cards.update({_id: item.id}, { 
      $set:{ 
       pos: index++, 
      } 
      }); 
     }); 
     } 
    }).disableSelection(); 

} 
+0

Czy możesz to potwierdzić po [zmianach API] (http://differential.com/blog/sortable-lists-in-meteor-using-jquery-ui)? Może zrobić dla niego Meteorpad? –

+0

Nadal działa, w zasadzie. Nie musisz już usuwać pomocnika. Oto Meteorpad: http://meteorpad.com/pad/TzQTngcy7PivnCCjk/sortable%20demo Chociaż bardziej podoba mi się podejście Blaze.getData. Nie ma potrzeby sadzić _id każdego rekordu w domenie. –