[javascript (jquery ui - Draggable, Droppable)] Gedropte Elemente ausrichten .....

technik_toni

Ensign
Registriert
Sep. 2008
Beiträge
250
Hy ich habe ein Problem bei jquery ui. Leider bin ich mit jquery noch nicht so erfahren deshalb brauche ich Hilfe :)

Also ich möchte gern zwei Dropzonen erstellen in der ich Divboxen hin und her draggen und droppen kann. Die Anzahl der Divboxen ist beliebig und wird aus einer Datenbank abgefragt.
Nun würde ich gerne das die Divboxen in der Dropzone 1 erscheinen und ich beliebig viele dieser Divboxen in die Dropzone 2 rüberziehen und droppen kann. Diesen Zustand will ich speichern können und beim erneuten Aufruf dieses Profils sollen alle Divboxen in der Dropzone erscheinen in der sie beim Zeitpunkt der Speicherung waren.

Ich habe schon zwei Dropzonen erstellt und kann auch die draggable-Divboxen in die Dropzonen ziehen.

Nun zu meinen Problemen:
1. Wie kann ich die Divboxen die in die Dropzone gedroppt wurden aneinander ausrichten?
Zurzeit werden die Divboxen in der Dropzone einfach dort abgelegt wo ich mit der Maus loslasse. So kommt es vor das mehrere Divboxen übereinander liegen wenn ich Sie an der gleichen Stelle droppe. Ich möchte jedoch das die Divboxen nebeneinander ausgerichtet werden egal wo ich Sie in der Dropzone ablege. So als ob die Boxen ein float+margin haben.

2. Wie kann ich feststellen welche Box in welcher Dropzone liegt?
Dies muss ich wissen damit ich das beim speichern mit in die Datenbank schreiben kann.

3. Wie kann ich die Divboxen beim Aufruf der Seite in den Dropzonen erscheinen lassen?
Derzeit sind meine Divboxen noch außerhalb der beiden Dropzonen. Sie müssten jedoch beim ersten Aufruf der Seite in Dropzone 1 liegen.



Ich hoffe Ihr könnt nachvollziehen was ich will.

Gruß Toni
Ergänzung ()

Also mit html5 und der drag and drop API habe ich es schon hinbekommen. Leider funktioniert das nicht mit dem IE. Daher bin ich auf die Lösung mit jquery gekommen.

Hier mel ein beispiele mit html5.
So will ich es quasi auch mit jquery hinbekommen.
HTML5 Drag & Drop Code1

Beispiel
(So soll es bei mir auch funktionieren jedoch mit zwei dropzonen. Wie man sieht werden die Elemente die man in die Dropzone zieht automatisch ausgerichtet)

HTML5 Drag & Drop Code2
 
Zunächst solltest du mal schauen wie das Event/Funktion von draggable/droppable heißt, wenn du das Objekt "losgelassen" hast, onDraggableEnd/Finish/Wasauchimmer.

Zu 1.)
Du könntest nach dem loslassen des drag-baren Objekts per $.each alle Element in der Dropzone durchgehen und per Hand ausrichten. Aber ich kann mir gut vorstellen, dass es in der jQuery UI - API Seite auch Beispiele bzw. Funktionen gibt, die die Elemente automatisch ausrichten.

Zu 2.)
Die Dropzone ist ja bestimmt n Div-Container mit ner ID. Die droppable - Elemente haben ja sicherlich eine class. Du könntest also auch hier: $.each($('.droppable_element'), ... ) anwenden.

Zu 3.)
Deine droppable - Elemente erstellst du aus einer Datendank? Na einfach an der Stelle, wo du deiner Startzone definierst, machst du die Datenbank-Abfrage und erstellst die Elemente?!

EDIT: Ups, was vergessen bei 2.):
$.each($('#dropzone').children('.droppable_element'), ... )
 
Zuletzt bearbeitet:
Ich habe mit Drag&Drop zwar noch nichts gemacht, aber HTML ist zum Glück standardisiert^^

1) Das Verhalten in dem Beispiel scheint mir normales HTML Verhalten zu sein. Die gedropten DIVs verhalten sich wie Blockelemente innerhalb eines anderen, nachdem sie im DOM verschoben wurden.
Daher würde ich erwarten, dass mit folgendem Code alle nebeneinander ausgerichtet werden.
Code:
.dropzone > div.dragable {
	display:inline-block;
}
Ansonsten solltest du mal prüfen, welche anderen Regeln sich (unbeabsichtigt) auf die dragables vererbt werden. Stichwort Dubugging Tools á la "Firebug", "Entwicklertools", ...

2) Entweder du gehst in jeder Dropzone die IDs der der Kinder-DIVs (draggables) durch, oder bei allen dragables das Elternelement.
Code:
$("#dropzone1").children("div").each(function() {
	alert($(this).attr("id"));
}

--- oder ---

$(".dragable").each(function() {
	alert($(this).parent("div").attr("id"));
}

3) Wenn du zu den dragables jeweils die ID der dropzone speicherst, einfach beim erstellen und einfügen der dragables in die Seite, direkt der dropzone anhängen.
Ich gehe hier davon aus, das alle dragables in einer entsprechenden data map vorliegen...
Code:
var dragables = [ { "id":"drag1", "dropzone":"dropzone1", "text":"Banane" }, { "id":"drag2", "dropzone":"dropzone2", "text":"Apfel" }, { "id":"drag3", "dropzone":"dropzone1", "text":"Mango" } ];
for(var i=0; i < dragables.length; i++) {
    $("<div>").addClass("dragable").attr("id", dragables[i].id).html(dragables[i].text).appendTo($("#" + dragables[i].dropzone));
}
 
Zuletzt bearbeitet:
Danke schonmal für eure antworten.
Also auf der jquery ui Seite finde ich kein Beispiel wie ich die gedroppten Elemente ausrichten kann. Dort wird in den Beispielen meist nur 1 element gedroppt.

Es gibt wohl die möglichkeit das gedroppte element per { top, left } auszurichten, aber das nützt mir nichts. Ich will ja das die Divboxen automatisch ausgerichtet werden (wie bei aufruf der Seite mit float und margin der draggable divs)

Es ist sicher ne kleine Sache aber ich habe noch nicht viel mit javascript bzw. jquery gearbeitet.

Also hier mal ein Beispiel auf das minimalste reduziert.
HTML:
<html lang="de">
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="http://code.jquery.com/jquery-1.8.3.js"></script>
    <script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
    <style>
    .draggable { width: 100px; height: 100px; padding:5px; float: left; margin: 5px; background-color:#FE2E2E; display:inline-block; cursor:pointer;}
    .droppable { width: 400px; height: 400px; padding:5px; float: left; margin: 10px; background:#2EFE2E; }
    </style>
    <script>
    $(function() {
            $('.draggable').draggable({
      cursor: "pointer",
      revert: "invalid",
      opacity: 0.7,
      snap: ".droppable",
      snapMode: "inner"
    });
        $( ".droppable" ).droppable({
            drop: function( event, ui ) {
                $( this )
                    .find( "p" )
                    .html( "Dropped!" );
            }
        });

    });
	
    </script>
</head>
<body>
	<div class="droppable">
		<p>Drop here</p>
	</div>
	<div class="droppable">
		<p>Drop here</p>
	</div>

	<div class="draggable">
		<p>Drag me to my target</p>
	</div>
	<div class="draggable">
		<p>Drag me to my target</p>
	</div>
	<div class="draggable">
		<p>Drag me to my target</p>
	</div>
	<div class="draggable">
		<p>Drag me to my target</p>
	</div>
	<div class="draggable">
		<p>Drag me to my target</p>
	</div>

</body>
</html>

Wie schaffe ich es das die gedroppten Elemente in der Dropzone ordentlich ausgerichtet werden. Die Divs bleiben innerhalb der Dropzone genau dort liegen wo ich die Maus loslasse.

@Spike S.: Der Code ".dropzone > div.dragable { display:inline-block; }" funktioniert leider nicht bzw. ich krieg es so nicht zum laufen.


PS: Die Anzahl der Divs hängt vom Inhalt der Datenbank ab. Ich lese mit php die Daten aus der Datenbank aus und erzeuge mit einer foreach Schleife die draggable Divs. Je nach Größe der Tabelle kann die Anzahl der Divs unterschiedlich ausfallen. Deshalb will ich dann wenn die divs ordentlich in der Dropzone ausgerichtet werden die Dropzone mit einem overflow:auto; ausrüsten damit ich quasi beliebig viele Divs in der Dropzone ablegen kann.

PSS: Dank der foreach Schleife kann ich quasi jedem erzeugten draggable Div eine individuelle ID geben. Somit sollte ich recht einfach rausfinden welche box in welcher Dropzone liegt.
 
Das was du möchtest macht, genau so, dein Beispiel Nr. 1 mit Standard HTML. Dein Problem ist, du hast das jQuery Framework verwendet, was sich hier offensichtlich anders verhält.
HTML:
<!DOCTYPE html>
<html lang="de">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title></title>
<style>
.draggable { width: 100px; height: 100px; padding:5px; float: left; margin: 5px; background-color:#FE2E2E; display:inline-block; cursor:pointer;}
.droppable { width: 400px; height: 400px; padding:5px; float: left; margin: 10px; background:#2EFE2E; border: 2px solid transparent; }
.droppable.over { border: 2px dashed #aaaaaa; }
</style>
<script>
function drag(event) {
	event.dataTransfer.setData("Text", event.target.id);
}
function dragEnter(event) {
	if(event.target.className.search(/droppable/g) > -1) event.target.className = "droppable over";
}
function dragLeave(event) {
	if(event.target.className.search(/droppable/g) > -1) event.target.className = "droppable";
}
function allowDrop(event) {
	event.preventDefault();
}
function drop(event) {
	if(event.target.className.search(/droppable/g) > -1) {
		event.target.className = "droppable";
		var data = event.dataTransfer.getData("Text");
		event.target.appendChild(document.getElementById(data));
	}
	event.preventDefault();
}
</script>
</head>
<body>
<div class="droppable" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" ondrop="drop(event)" ondragover="allowDrop(event)">
<p>Drop here</p>
</div>
<div class="droppable" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" ondrop="drop(event)" ondragover="allowDrop(event)">
<p>Drop here</p>
</div>

<div id="drag1" class="draggable" draggable="true" ondragstart="drag(event)">
<p>Drag me to my target</p>
</div>
<div id="drag2" class="draggable" draggable="true" ondragstart="drag(event)">
<p>Drag me to my target</p>
</div>
<div id="drag3" class="draggable" draggable="true" ondragstart="drag(event)">
<p>Drag me to my target</p>
</div>
<div id="drag4" class="draggable" draggable="true" ondragstart="drag(event)">
<p>Drag me to my target</p>
</div>
<div id="drag5" class="draggable" draggable="true" ondragstart="drag(event)">
<p>Drag me to my target</p>
</div>

</body>
</html>

Der einzige Haken an der Sache ist, du musst jetzt Browser wie IE < 9 abfangen, einige Browser bringen diese HTML5 Funktionalität noch nicht. Ansonsten heißt es die jQuery API durchzustöbern, wie man das Verhalten wieder Richtung Standard HTML drehen kann.
Der Rest sollte sich von selbst erklären.

Edit: hier noch etwas zur Browserunterstützung und Funktion: http://www.w3schools.com/html/html5_draganddrop.asp
 
Zuletzt bearbeitet:
@Spike S: Danke für dein Beispiel. So in etwa hatte ich das auch schon mit der HTML5 Lösung hinbekommen. Da ist wie du schon sagst das Problem mit dem IE. Deshalb wollte ich es mit jQuery machen. Aber ich finde da ums verrecken nichts wie man die gedroppten Boxen innerhalb der Dropzonen ausrichten kann. Die einzigen Beispiele auf der jquery ui Seite wo mehrere Elemente ordentlich ausgerichtet Angezeigt werden sind folgende.

Beispiel 1
Beispiel 2

Doch da wird jedesmal mit Listen statt mit Divboxen gearbeitet.


Es muss doch ne möglichkeit geben die mit jquery ordentlich auszurichten.
Sonst ist doch die ganze draggable/droppable Geschichte unter jquery bei mehreren verwendeten Boxen recht sinnlos....
 
Ungetestete Idee und Annahmen zum Ausrichten-Problem:

Die draggable - Elemente und die Dropzone sind ja im DOM unabhängig voneinander. Wenn du also ein draggable Element in die Dropzone packst, dann liegt es ja nur optisch in der Dropzone, es ist aber nachwievor im DOM unabhängig voneinander! Soweit die Annahme von mir!

Du könntest folgendes probieren:

Sobald du ein Element gedroppt hast in die Dropzone, dann füge dieses Element als Kind-Element per $.append hinzu, entferne alle absoluten Positionsangaben und lass das Element floaten. Es sollte danach sich selbst in der Dropzone aufgrund des float ausrichten und es sollte weiterhin draggable sein.

Verstehste was ich meine??!

Also:

onDrop --> $(this-dropzone).append($(this-draggable-element)) --> $(this-draggable-element).css({'position': 'static', 'float': 'left'});
 
Die Annahme von Rain ist richtig. Das UI Framework ändert beim droppen nichts an der DOM struktur, rein visuelle Änderungen.

Draggables sind zudem standardmäßig position:relative;. Die Draggables können jetzt allerdings nicht einfach statisch positioniert werden, da sich die dragging-Animation (während das Draggable bewegt wird) sich weiter auf die relative Position bezieht.

Damit hier Standard HTML Verhalten greift, muss die Struktur entsprechend angepasst werden. Dazu folgende Lösung: Das Draggable wird der entsprechenden Dropzone untergordnet und erhält ein statisches Hilfs-DIV drumherum. Damit kann man sich sparen die Style und Positionsänderungen durch das Framework ständig zu überwachen und zu überschreiben.

Ergänzung im CSS Teil:
Code:
.helper { display:inline-block; }

Geänderte "drop"-Event Funktion:
Code:
drop: function( event, ui ) {
	$( this ).find( "p" ).html( "Dropped!" );
	$(ui.draggable[0]).appendTo(event.target);
	$(ui.draggable[0]).wrap($("<div>").addClass("helper"));
	$(document.getElementById(ui.draggable[0].id)).css("top", 0);
	$(document.getElementById(ui.draggable[0].id)).css("left", 0);
	$("div.helper:empty").remove();
}
Top und Left müssen hier überschrieben werden, da das Framework sich ja hier auf ein anderen Punkt als unser Hilfs-DIV bezieht.
Da man ja die Draggables zwischen beiden Dropzones hin und her schieben kann, müssen zum Schluss leere Hilfs-DIVs wieder gelöscht werden (werden ja bei erneutem Drag&Drop mit appendTo "rausgerissen" und wieder woanders eingehangen).
 
Ihr hattet ja oben diesen code gepostet. Was muss ich da ändern, wenn ich möchte, dass das per drag & drop gezogene teil an der stelle, wo es hingezogen wurde gespeicht wird?

<html lang="de">
<head>
<meta charset="utf-8" />
<title></title>
<script src="http://code.jquery.com/jquery-1.8.3.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<style>
.draggable { width: 100px; height: 100px; padding:5px; float: left; margin: 5px; background-color:#FE2E2E; display:inline-block; cursor:pointer;}
.droppable { width: 400px; height: 400px; padding:5px; float: left; margin: 10px; background:#2EFE2E; }
</style>
<script>
$(function() {
$('.draggable').draggable({
cursor: "pointer",
revert: "invalid",
opacity: 0.7,
snap: ".droppable",
snapMode: "inner"
});
$( ".droppable" ).droppable({
drop: function( event, ui ) {
$( this )
.find( "p" )
.html( "Dropped!" );
}
});
*
});

</script>
</head>
<body>
<div class="droppable">
<p>Drop here</p>
</div>
<div class="droppable">
<p>Drop here</p>
</div>
*
<div class="draggable">
<p>Drag me to my target</p>
</div>
<div class="draggable">
<p>Drag me to my target</p>
</div>
<div class="draggable">
<p>Drag me to my target</p>
</div>
<div class="draggable">
<p>Drag me to my target</p>
</div>
<div class="draggable">
<p>Drag me to my target</p>
</div>
*
</body>
</html>
 
Dazu musst du die Top und Left Werte speichern, soweit ich das gesehen habe bezieht sich das auf die Dropzone. Dazu einfach in der Drop Callback Funktion per Ajax die Werte an den Server senden. Erstell aber einen neuen Thread wenn du dabei Hilfe benötigst, deine Frage geht ja in eine andere Richtung ;)
 
Zurück
Oben