2013-01-12 9 views
9

Ich möchte eine baumähnliche Struktur erstellen, wo der Benutzer Blätter ziehen und ablegen kann. Ich habe einen Ausgangspunkt wie folgt dar:AngularJS - Wie macht man einen ziehbaren Baum?

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> 

Coffee

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'] 

Der Code in diesem JSFiddle ist auch: http://jsfiddle.net/bESrf/1/

Auf meinem „real "Code, anstatt nur eine Ebene für Kinder, extrahierte ich die zweite <ul> in eine Vorlage und es rekursiv gerendert, was gut funktioniert, aber ich konnte keinen Weg finden, es in JSFiddle zu tun.

Was wäre der beste Weg, um es rekursiv zu rendern und trotzdem Drag & Drop zu erlauben, was das Array von Objekten und Unterobjekten, die durch ng-model dargestellt werden, verändern würde?

Antwort

20

Werfen Sie einen Blick auf dieses Beispiel: http://jsfiddle.net/furf/EJGHX/

ich diese Lösung gerade abgeschlossen, so ist es noch nicht richtig dokumentiert, aber man sollte es mir für Ihre Lösung können.

Sie müssen ein paar Dinge verwenden:

  1. die ezTree Richtlinie - den Baum
  2. Manuele J Sarfatti's nestedSortable plugin for jQuery UI
  3. (optional) die uiNestedSortable Richtlinie machen - nestedSortable aus Ihrer Vorlage zu ermöglichen.
  4. Controller-Code Ihr Modell für die Aktualisierung - siehe $scope.update

Mit der ezTree Richtlinie

eine rekursive Datenstruktur Gegeben:

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

Diese Vorlage wird den Baum bauen:

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

ez-tree Der Ausdruck sollte als item in collection at selector geschrieben werden, wobei das iterierten item Kind (ala ng-repeat) ist, ist die collection Stammebene Sammlung und selector ist der CSS-Selektor für den Knoten in der Vorlage, wenn die Richtlinie Rekursion sollte. Der Name der Terminal-Eigenschaft der Sammlung, in diesem Fall children, wird verwendet, um den Baum zu rekurieren, in diesem Fall child.children. Dies könnte neu geschrieben werden, um konfigurierbar zu sein, aber ich werde das als eine Übung für den Leser verlassen.

Mit uiNestedSortable Richtlinie

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

Das ui-nested-sortable Attribut sollte eine JSON-Konfiguration für das nestedSortable Plugin enthalten. Das Plugin erfordert, dass Sie listType und items angeben. Meine Lösung erfordert, dass doNotCleartrue ist. Weisen Sie Callbacks für Ereignisse zu, indem Sie ui-nested-sortable-*eventName* verwenden. Meine Anweisung liefert optionale $ event und $ ui Argumente für Callbacks. Weitere Informationen finden Sie in der Dokumentation zu nestedSortable.

aktualisiert Modell

Es gibt mehr als einen Weg, um diese Katze Haut. Hier ist meins. Bei dem stop-Ereignis extrahiert es die untergeordnete Eigenschaft des Bereichs des Elements, um zu bestimmen, welches Objekt verschoben wurde, die untergeordnete Eigenschaft des Bereichs des übergeordneten Elements des Elements, um das Ziel des Objekts zu bestimmen, und die Position des Elements, um die Position des Objekts zu bestimmen an seinem Bestimmungsort. Dann durchläuft er die Datenstruktur und entfernt das Objekt von seiner ursprünglichen Position und fügt es in seine neue Position ein.

+0

Wow, danke dafür! Ich werde es versuchen und dich wissen lassen. – kolrie

+0

Gute Arbeit !! Ich liebe die _pregnant_ class :) – null

+0

** FYI ** - Dies funktioniert nicht im IE wie es ist ... Um es in IE10 arbeiten zu lassen, ändern: 'cursor = parentNode.childNodes [i];' ** sein * * 'cursor = parentNode.childNodes [i]? parentNode.childNodes [i]: null; ' Ich habe das herausgefunden dank [dieser Antwort] (http://stackoverflow.com/questions/9377887/ie-doesnt-support-insertbefore) – JustMaier

6

Leichte Bearbeitung der Geige durch Furf, damit es in IE funktioniert.

IE gibt einen Fehler auf insertNode, wenn das zweite Argument null ist, wenn dies der Fall ist, wird stattdessen appendNode verwendet.

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

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

Das Nested Sortable Plugin ist in den js inlined, weil IE eine Diskrepanz MIME-Typ gibt, wenn von Github enthalten.

+0

raw.github.com/ETC Dateien können über roggithub.com/ETC verlinkt werden (beachten Sie das Entfernen des Punktes) –

+1

Ich habe die Fidel aktualisiert und das Nested Sortable Plugin direkt verlinkt. Hoffentlich klappt es im IE noch. Ich habe auch die Verwendung von isAllowed hinzugefügt, um Conditional Drag and Drop zu implementieren. Siehe auch [fiddle] (http://jsfiddle.net/michieljoris/PdKc7/2/) für einen anderen Weg, um isAllowed zu setzen – michieljoris

+2

Ich bekam Top-Level-Kinder ziehbar: http://jsfiddle.net/blaha/BFNnr/ – blaha

6

Probieren Sie Angular-NestedSortable aus, ein Angularjs-Plugin, das verschachtelte Listen sortieren und Daten binden kann und nicht auf jQuery angewiesen ist. https://github.com/jimliu/Angular-NestedSortable

+1

beste Lösung aller Zeiten !! –