2013-01-12 15 views
9

Chcę utworzyć strukturę podobną do drzewa, w której użytkownik może przeciągać i upuszczać liście. Mam punkt wyjścia w następujący sposób:AngularJS - Jak utworzyć drzewo przeciągalne?

HTML

<div ng:controller="controller"> 
    <ul ui-sortable ng-model="items" ui-options="{connectWith: '.item'}" class="item"> 
    <li ng-repeat="item in items" class="item"> 
     {{ item.name }} 
     <ul ui-sortable ng-model="item.children" ui-options="{connectWith: '.item'}" class="item"> 
     <li ng-repeat="item in item.children" class="item">{{ item.name }}</li> 
     </ul> 
    </li> 
    </ul> 

    <pre>{{ items | json }}</pre> 
</div> 

<script src="http://code.angularjs.org/1.0.2/angular.min.js"></script> 
<script src="https://raw.github.com/angular-ui/angular-ui/master/build/angular-ui.min.js"></script> 

coffeescript

myapp = angular.module 'myapp', ['ui'] 

myapp.controller 'controller', ($scope) -> 

    $scope.items = [ 
     {id: 1, name: 'Item 1', children: [ 
     {id: 5, name: 'SubItem 1.1', children: [ 
      {id: 11, name: 'SubItem 1.1.1', children: []}, 
      {id: 12, name: 'SubItem 1.1.2', children: []} 
     ]}, 
     {id: 6, name: 'SubItem 1.2', children: []} 
     ]}, 
     {id: 2, name: 'Item 2', children: [ 
     {id: 7, name: 'SubItem 2.1', children: []}, 
     {id: 8, name: 'SubItem 2.2', children: []} 
     {id: 9, name: 'SubItem 2.3', children: []} 
     ]}, 
     {id: 3, name: 'Item 3', children: [ 
     {id: 10, name: 'SubItem 3.1', children: []} 
     ]} 
    ] 

angular.bootstrap document, ['myapp'] 

Kod jest w tym JSFiddle także: http://jsfiddle.net/bESrf/1/

Na moje „prawdziwe "Kod, zamiast tylko jednego poziomu dla dzieci, wyodrębniłem drugi <ul> do szablonu i renderowane rekurencyjnie, co działa dobrze, ale nie mogłem znaleźć sposobu, aby to zrobić w JSFiddle.

Jaki byłby najlepszy sposób renderowania go rekurencyjnie i nadal pozwala na przeciąganie i upuszczanie, które zmieniłoby tablicę obiektów i pod-obiektów reprezentowanych przez model-ng?

Odpowiedz

20

Spójrz na ten przykład: http://jsfiddle.net/furf/EJGHX/

Właśnie zakończono tego rozwiązania, więc nie jest jeszcze odpowiednio udokumentowane, ale powinieneś być w stanie wydobyć go do rozwiązania.

będzie musiał użyć kilku rzeczy:

  1. dyrektywę ezTree - renderowanie drzewa
  2. Manuele J Sarfatti's nestedSortable plugin for jQuery UI
  3. (opcja) dyrektywy uiNestedSortable - aby włączyć nestedSortable od szablonu. Kod
  4. kontroler do aktualizacji modelu - patrz $scope.update

Korzystanie dyrektywę

ezTree Biorąc rekurencyjnej struktury danych:

$scope.data = { 
    children: [{ 
    text: 'I want to create a tree like structure...', 
    children: [{ 
     text: 'Take a look at this example...', 
     children: [] 
    }] 
    }] 
}; 

Ten szablon będzie budować drzewo:

<ol> 
    <li ez-tree="child in data.children at ol"> 
    <div>{{item.text}}</div> 
    <ol></ol> 
    </li> 
</ol> 

Wyrażenie ez-tree powinien być zapisany jako item in collection at selector gdzie item jest powtórzyć dziecko (ala ng-repeat) collection jest kolekcja korzeń poziomu i selector jest selektor CSS dla węzła wewnątrz szablonu gdzie dyrektywa powinna recurse. Nazwa właściwości terminalu kolekcji, w tym przypadku children, będzie używana do rekurencji drzewa, w tym przypadku child.children. To może być przepisane, aby można było je konfigurować, ale zostawię to jako ćwiczenie dla czytelnika.

Korzystanie uiNestedSortable dyrektywę

<ol ui-nested-sortable="{ listType: 'ol', items: 'li', doNotClear: true }" 
    ui-nested-sortable-stop="update($event, $ui)"> 
</ol> 

Atrybut ui-nested-sortable powinien zawierać konfigurację JSON dla wtyczki nestedSortable. Wtyczka wymaga określenia listType i items. Moje rozwiązanie wymaga, aby doNotClear był true. Przypisz wywołania zwrotne do zdarzeń za pomocą ui-nested-sortable-*eventName*. Moja dyrektywa dostarcza opcjonalne argumenty $ event i $ ui do wywołań zwrotnych. Informacje na temat innych opcji można znaleźć w dokumentacji nestedSortable.

Aktualizacja model

Jest więcej niż jeden sposób na skórę ten kot. To moje. W zdarzeniu stop wyodrębnia właściwość potomną zakresu elementu, aby określić, który obiekt został przeniesiony, właściwość potomną zakresu elementu nadrzędnego elementu, aby określić miejsce docelowe obiektu, oraz położenie elementu w celu określenia położenia obiektu w miejscu docelowym. Następnie przechodzi przez strukturę danych i usuwa obiekt z pierwotnej pozycji i wstawia go do nowego położenia.

$scope.update = function (event, ui) { 

    var root = event.target, 
    item = ui.item, 
    parent = item.parent(), 
    target = (parent[0] === root) ? $scope.data : parent.scope().child, 
    child = item.scope().child, 
    index = item.index(); 

    target.children || (target.children = []); 

    function walk(target, child) { 
    var children = target.children, 
     i; 
    if (children) { 
     i = children.length; 
     while (i--) { 
     if (children[i] === child) { 
      return children.splice(i, 1); 
     } else { 
      walk(children[i], child) 
     } 
     } 
    } 
    } 
    walk($scope.data, child); 

    target.children.splice(index, 0, child); 
}; 
+0

Wow, dzięki za to! Dam ci szansę i dam ci znać. – kolrie

+0

Dobra robota !! Uwielbiam _pregnant_ class :) – null

+0

** FYI ** - To nie działa w IE, jak jest ... Aby to działało w IE10 zmień: 'cursor = parentNode.childNodes [i];' ** to be * * 'cursor = parentNode.childNodes [i]? parentNode.childNodes [i]: null; ' Wyobraź to sobie dzięki [ta odpowiedź] (http://stackoverflow.com/questions/9377887/ie-doesnt-support-insertbefore) – JustMaier

6

Lekka edycja skrzypiec przez futro, aby działało w IE.

IE daje błąd w funkcji insertNode, gdy drugi argument ma wartość null, więc w takim przypadku używany jest parametr appendNode.

http://jsfiddle.net/michieljoris/VmtfR/

if (!cursor) parentNode.appendChild(cached.element); 
else parentNode.insertBefore(cached.element, cursor); 

Wtyczka Zagnieżdżony Sortable jest inlined w js, ponieważ IE daje typ MIME niedopasowanie gdy zawarte z github.

+0

raw.github.com/ETC można połączyć za pośrednictwem rawgithub.com/ETC (zauważ usunięcie kropki). –

+1

Zaktualizowałem skrzypce i bezpośrednio powiązałem zagnieżdżoną zagnieżdżoną wtyczkę. Mam nadzieję, że nadal działa w IE. Dodałem także użycie isAllowed do implementacji warunkowego przeciągania i upuszczania. Zobacz także [skrzypce] (http://jsfiddle.net/michieljoris/PdKc7/2/) dla innego sposobu ustawienia isAllowed – michieljoris

+2

Mam dzieci na najwyższym poziomie, które można przeciągnąć: http://jsfiddle.net/blaha/BFNnr/ – blaha

Powiązane problemy