Draggable is not dragging - javascript

Somehow my draggables arn't dragging anymore into the placeholders.
I noticed it gives an error on the appendChild in the drop() function but when I alert in there I notice it doesn't even get that far.
var people = ['Sinan', 'Babette', 'Thomas', 'Yannick', 'Nick'];
$.each(people, function(key, val) {
$('#placeholders').append('<div class="dnd" data-id="' + val + '" ondrop="drop(event)" ondragover="testDiv(event, innerHTML)"></div>');
});
$('#seizeImg img').on('dragstart', function(event) {
drag(event);
});
function testDiv(ev, x) {
if (x.length > 0) {
return false;
} else {
allowDrop(ev);
return true;
}
}
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
var complete = false;
$.each('#seizeImg img', function(key, val) {
alert(key);
});
}
.dnd {
display: inline-block;
vertical-align: top;
width: 10%;
height: 160px;
padding: 10px;
border: 2px solid #B7E6E6;
background: rgba(51, 255, 102, 0.2);
}
#seizeImg img {
width: 10%;
height: 160px;
}
div.label {
height: 25px;
text-align: center;
border: none;
background: none;
}
div.buf {
background: rgba(255, 0, 0, 0.2);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="placeholders">
</div>
<br>
<br>
<div id="seizeImg">
<img id="Babette" src="img/Babette.jpg" draggable="true" ondrop="drop(event)" width="186" height="186">
<img id="Thomas" src="img/Thomas.jpg" draggable="true" ondrop="drop(event)" width="186" height="186">
<img id="Yannick" src="img/Yannick.jpg" draggable="true" ondrop="drop(event)" width="186" height="186">
<img id="Sinan" src="img/Sinan.jpg" ondrop="drop(event)" draggable="true" ondrop="drop(event)" width="186" height="186">
<img id="Nick" src="img/Nick.jpg" ondrop="drop(event)" draggable="true" ondrop="drop(event)" width="186" height="186">
</div>

I am assuming you are using jqueryUI with the drag and drop libraries installed. If you aren't that might make things a little easier for you.
you could make it work with:
$('#seizeImg img').draggable();
and if you wanted the drop to save data all you have to do is:
$('#placeholders').droppable({
accept: $('#seizeImg img'),
drop: function(){
//enter code here to take place whenever you drop something on it
// if you want to take a value from the object you are dropping on
// the droppable object just use:
var varID = (ui.draggable.attr("value");
}
});
Its a little more concise and jqueryUI takes out a lot of the guess work.
EDIT:
Unless you didn't include the code up top, you never call the actual jqueryUI draggable function. somewhere around
$(document).ready({function(){
// you have to include
$('seizeImg img').draggable({function(){
//add some more moving parts here if you need to
});
}
just setting draggable='true' in your HTML isn't the same thing.

The problem you are facing is caused by the lines below
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
You are trying to append an element that is not of Node type. That is happening because data is an empty string thus document.getElementById("") returns null which is not allowed to be passued to appendChild.

Related

append the element before and after on drop it

I'm trying to make a website that use drag and drop functionality to build a website. But I'm facing the problem that the element is not being append before another element like the code I have shown. please help me so it can drop the elements before and after a specific element not just at the end of all the elements.
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
#div1,
#div2 {
float: left;
width: 500px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
<h2>Drag and Drop</h2>
<p>Drag the image back and forth between the two div elements.</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<button draggable="true" ondragstart="drag(event)" id="drag1">button1</button>
<button draggable="true" ondragstart="drag(event)" id="drag2">button2</button>
<button draggable="true" ondragstart="drag(event)" id="drag3">button3</button>
<button draggable="true" ondragstart="drag(event)" id="drag4">button4</button>
</div>
<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)">
</div>
I'm using javascript.
That's actually quite tricky to achieve, you need to implement your own logic for inserting the element to the correct position in the list.
Here is an example where you can move items between divs and reorder items in the same div
(Note that I only implemented the logic for drag/drop items horizontally in a single line by using left offset, if you have multiple lines items list, you need to implement your own)
function allowDrop(ev) {
ev.preventDefault()
}
function drag(ev) {
ev.dataTransfer.setData('text', ev.target.id)
}
function drop(ev) {
ev.preventDefault()
var data = ev.dataTransfer.getData('text')
// ev.currentTarget is the div that the elements are dropped
const currentDragElementOffset = ev.clientX
const items = ev.currentTarget.children
//empty list, just append and return
if (items.length === 0) {
ev.currentTarget.appendChild(document.getElementById(data))
return
}
// non-empty list
for (let i = 0; i < items.length; i++) {
const item = items[i]
const {
left,
width
} = item.getBoundingClientRect()
// find the offset left from the center of the item
const currentElementLeftOffset = left + width / 2;
if (currentDragElementOffset < currentElementLeftOffset) {
ev.currentTarget.insertBefore(document.getElementById(data), item)
return
}
// found no insertion point, that means item was dragged to the end of the list
if (i === items.length - 1 && currentDragElementOffset > currentElementLeftOffset) {
ev.currentTarget.appendChild(document.getElementById(data))
}
}
}
#div1,
#div2 {
float: left;
width: 500px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
<!DOCTYPE html>
<html>
<body>
<h2>Drag and Drop</h2>
<p>Drag the image back and forth between the two div elements.</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<button draggable="true" ondragstart="drag(event)" id="drag1">
button1
</button>
<button draggable="true" ondragstart="drag(event)" id="drag2">
button2
</button>
<button draggable="true" ondragstart="drag(event)" id="drag3">
button3
</button>
<button draggable="true" ondragstart="drag(event)" id="drag4">
button4
</button>
</div>
<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
</body>
</html>
Simply use the CSS property order.
The drop zones must have display: flex or display: inline-flex (see .zone in Example - CSS)
Each item that is draggable should have style="order: number " (see Example - JS)
Also, to avoid an item appending to another item, use event.currentTarget instead of event.target in the drop() function (see drop() in Example - JS). In the example, the repetitive parts in HTML have been streamlined (see Figure I):
Figure I
Original Post
Example
Attributes on each element in HTML
Attributes assigned to each element by .forEach()
Inline events on each element in HTML
Onevent properties bound to each element by .forEach()
Example
Details are commented
/*
Collect all .btn into a NodeList
Iterate through NodeList with .forEach()
Bind dragstart event to current <button>
Add inline style "order" with the value of current index
Add "draggable" attribute with the value of true
*/
document.querySelectorAll('.btn').forEach((b, i) => {
b.ondragstart = drag;
b.style.order = i;
b.setAttribute('draggable', true);
});
/*
Collect all .zone into a NodeList
Iterate through NodeList with .forEach()
Bind drop event to current <div>
Bind dragover event to current <div>
*/
document.querySelectorAll('.zone').forEach(z => {
z.ondrop = drop;
z.ondragover = allowDrop;
});
function allowDrop(e) {
e.preventDefault();
}
function drag(e) {
e.dataTransfer.setData("text", e.target.id);
}
function drop(e) {
e.preventDefault();
let data = e.dataTransfer.getData("text");
/*
Change e.target to e.currentTarget to prevent any <button>
appending onto another <button>. e.currentTarget will always
point to .zone
*/
e.currentTarget.append(document.getElementById(data));
}
.zone {
display: flex;
align-items: center;
width: 500px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
.btn {
margin: 0 10px;
cursor: move;
}
<h2>Drag and Drop</h2>
<p>Drag the buttons back and forth between the two div elements.</p>
<div class="zone">
<button id='b1' class='btn'>button1</button>
<button id='b2' class='btn'>button2</button>
<button id='b3' class='btn'>button3</button>
<button id='b4' class='btn'>button4</button>
</div>
<div class="zone"></div>
You should use .prepend() method for inserting element before the other element.
Element.prepend() method inserts a set of Node objects or string objects before the first child of the Element. String objects are inserted as equivalent Text nodes.
Here's a Working Code :
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.prepend(document.getElementById(data));
}
#div1,
#div2 {
float: left;
width: 500px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
<h2>Drag and Drop</h2>
<p>Drag the image back and forth between the two div elements.</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<button draggable="true" ondragstart="drag(event)" id="drag1">button1</button>
<button draggable="true" ondragstart="drag(event)" id="drag2">button2</button>
<button draggable="true" ondragstart="drag(event)" id="drag3">button3</button>
<button draggable="true" ondragstart="drag(event)" id="drag4">button4</button>
</div>
<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)">
</div>

How to get event property again for already dragged image

I have image that I want to drag and drop infinitely.From first box to second box when I move,image disappear from first box.Not to lose image created same image on first box again using .appendchild(img) method.I want to drag image from initial position,not from where I dropped.So I changed draggable property as false when I dropped image into box.It creates image on first box,there's no problem.But I can't drag and drop it from first box to third again because that image has no event properties.I want to give them those properties again and it should be repeated because I want to do it forever.
Here's what I tried
<!DOCTYPE HTML>
<html>
<head>
<style>
#div1, #div2,#div3 {
float: left;
width: 100px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
</style>
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
var img = document.createElement("img");
img.src = "https://mikasasports.com/wp-content/uploads/2015/04/MVA2001.png";
var src = document.getElementById("div1");
img.style.width="88px";
img.style.height="31px";
src.appendChild(img);
drag1.draggable=false;
}
</script>
</head>
<body>
<h2>Drag and Drop</h2>
<p>Drag the image back and forth between the three div elements.</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<img src="https://mikasasports.com/wp-content/uploads/2015/04/MVA2001.png" draggable="true" ondragstart="drag(event)" id="drag1" width="88" height="31">
</div>
<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<div id="div3" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
</body>
</html>

Revert back not possible in javascript

I have 3 box with id div1, and a box with id drag1. The box drag1 can be dragged and dropped to any of box div1.
I want to know if there is a way that the div drag1 can be seen during the drag in javascript - like in jquery.
Is there any revert back possible because I don't want to completely change the function to jquery
How to achieve this?
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
/*
$("#drag1").draggable({
revert: "valid",
drag: function (event, ui) {
$("#info").html("<font color=red>This square will go back to it`s original position once it`s dropped in target zone. </font>");
}
});
$("#div1").droppable({
drop: function (event, ui)
{
$(this).css("background-color", "lightgreen")
},
out: function (event, ui)
{
$(this).css("background-color", "")
}
});
});
*/
#div1 {
width:120px;
height: 100px;
padding: 10px;
border: 1px solid #aaaaaa;
float:left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<img id="drag1" src="https://picsum.photos/200/300/?random"
draggable="true" ondragstart="drag(event)" width="100" height="100" style="border:solid">
First, in HTML, you must have unique IDs for each element, so div1 cannot be the ID for all three.
This example of mine is poorly put together and it gives you something to start with. You didn't include in your post what would be needed to trigger a revert event. my example only reverts a Drag if it is dragged to a Drop that has revert class name.
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
var boxData = ev.target.getBoundingClientRect();
ev.dataTransfer.setData("original-position-top", boxData.top);
ev.dataTransfer.setData("original-position-left", boxData.left);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
if (ev.target.className == "revert") {
var el = document.getElementById(data);
el.style.position = "relative";
var startPosition = el.getBoundingClientRect();
startPosition = {
top: startPosition.top,
left: startPosition.left
};
var targetPosition = {
top: ev.dataTransfer.getData("original-position-top"),
left: ev.dataTransfer.getData("original-position-left")
};
console.log("Trigger Revert", el.id, startPosition, targetPosition);
function calcSteps(start, finish) {
var l = Math.abs(start.left - finish.left);
var t = Math.abs(start.top - finish.top);
return {
top: t,
left: l,
pick: (l > t ? "left" : "top")
};
}
var steps = calcSteps(startPosition, targetPosition);
console.log("Steps:", steps);
var a = setInterval(frame, 2);
function frame() {
var i = steps.pick;
console.log("Animate Frame:", steps[i]);
if (steps[i] <= 0) {
clearInterval(a);
} else {
if (startPosition.left + 1 > targetPosition.left) {
// Do nothing
} else {
startPosition.left++;
el.style.left = startPosition.left + "px";
}
if (startPosition.top + 1 > targetPosition.top) {
// Do nothing
} else {
startPosition.top++;
el.style.top = startPosition.top + "px";
}
console.log("Animate Frame:", steps[i], startPosition);
steps[i]--;
}
}
}
}
#div1,
#div2,
#div3 {
width: 120px;
height: 100px;
padding: 10px;
border: 1px solid #aaaaaa;
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)" class="revert"></div>
<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<div id="div3" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<img id="drag1" src="https://picsum.photos/200/300/?random" draggable="true" ondragstart="drag(event)" width="100" height="100" style="border:solid">
Hope that helps.

display next image on drop

I have three div boxes with id 10, 11, 12. I have an image array, on dropping an item box, the box element gets deleted, I make a call to function nextslide in the on-drop method which calls next slide to display.
On dropping the first element on any box with id 10, 11, 12 The box gets deleted, but displaying next image through nextslide() method doesn't work.
I want to display next image in an array on successfully dropping the first element.
How to achieve this?
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("Text", ev.target.id);
}
var x = document.get
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("Text");
alert(data);
var el = document.getElementById(data);
el.parentNode.removeChild(el); // deleting drag item
ev.target.style.backgroundColor = 'initial'; //[value indicate which box elemenet] bgcoclor none
nextslide();
}
var images = new Array();
images[0] = "https://picsum.photos/200/300/?random";
images[1] = "https://picsum.photos/200/300/?random";
images[2] = "https://picsum.photos/200/300/?random";
var currentpic = 0;
var lastpic = images.length - 1;
function nextslide() {
if (currentpic == lastpic) {
currentpic = 0;
document.getElementById('slide').src = images[currentpic];
} else {
currentpic++;
document.getElementById('slide').src = images[currentpic];
}
}
.box {
background-color: coral;
width: 20%;
height: 60px;
display: inline-block;
border-radius: 5px;
margin: -2px;
border-radius: 12%;
background-color: #00b300;
}
<div id="container">
<div class="box" ondrop="drop(event)" ondragover="allowDrop(event)" id="10">
<p name="values"></p>
</div>
<div class="box" ondrop="drop(event)" ondragover="allowDrop(event)" id="11">
<p name="values"></p>
</div>
<div class="box" ondrop="drop(event)" ondragover="allowDrop(event)" id="12">
<p name="values"></p>
</div>
</div>
<div class="box2" draggable="true" ondragstart="drag(event)" id="2">
<img src="https://picsum.photos/200/300/?random" draggable="true" id="slide" style="width:30px; height:100px; border-radius: 50%;" border="rounded" onclick="nextslide()" />
</div>

Javascript / html5 drag n drop counting

Ok I have 7 colour block in which to drag 7 colour names. If the user get the correct colour name in the right colour block they receive a point. This is my code below but my count is not working when the user gets the correct answer. Can anyone help please, I know it is something stupid I'm not seeing.
function readDropZone() {
var score = document.getElementById('score');
score.innerHTML = 0;
var block = document.getElementById('colour-block').children;
for(var i = 0; i < block.length; ++i) {
var hitblock = block[i];
var dropzone = hitblock.lastElementChild;
if (dropzone.children.length > 0) {
var dropzoneId = dropzone.id;
var blockId = dropzone.firstElementChild.id;
var blockNo = dropzoneId.substring(dropzoneId.indexOf('-') + 1);
var dragNo = blockId.substring(blockId.indexOf('-') + 1);
if (dragNo == blockNo) {
score.innerHTML = parseInt(score.innerHTML) + 1;
}
}
if (parseInt(score.innerHTML) == 10) {
alert('Congratulations! You won the game!\nClick OK to restart.');
location.reload();
}
}
}
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
readDropZone();
const data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
#block-1, #block-2, #block-3, #block-4, #block-5, #block-6, #block-7 {
color: #fff;
width: 150px;
height: 35px;
border: 1px solid #aaaaaa;
text-align: center;
padding: 10px 0;
font-size: 1.25em;
}
#block-3 {
color: #000;
}
#colour-block {
float: left;
width: 50%;
}
#colour-name {
float: right;
line-height: 1.5em;
font-size: 1.25em;
font-weight: bold;
width: 50%;
clear: right;
cursor: move;
}
<h2>1. Drag and drop the names into the coloured blocks</h2>
<div id="colour-block">
<div id="block-1" class="block" style="background-color:red" ondrop="drop(event)" ondragover="allowDrop(event)" name="red"></div>
<div id="block-2" class="block" style="background-color:orangered" ondrop="drop(event)" ondragover="allowDrop(event)" name="orange" ></div>
<div id="block-3" class="block" style="background-color:yellow" ondrop="drop(event)" ondragover="allowDrop(event)" name="yellow"></div>
<div id="block-4" class="block" style="background-color:green" ondrop="drop(event)" ondragover="allowDrop(event)" name="green"></div>
<div id="block-5" class="block" style="background-color:skyblue" ondrop="drop(event)" ondragover="allowDrop(event)" name="blue"></div>
<div id="block-6" class="block" style="background-color:midnightblue" ondrop="drop(event)" ondragover="allowDrop(event)" name="indego"></div>
<div id="block-7" class="block" style="background-color:rgb(109, 92, 221)" ondrop="drop(event)" ondragover="allowDrop(event)" name="violet"></div>
</div>
<div id="colour-name">
<div id="drag-6" class="colour" draggable="true" ondragstart="drag(event)" name="indego">Indeagó</div>
<div id="drag-2" class="colour" draggable="true" ondragstart="drag(event)" name="orange">Oráiste</div>
<div id="drag-4" class="colour" draggable="true" ondragstart="drag(event)" name="green">Glas</div>
<div id="drag-3" class="colour" draggable="true" ondragstart="drag(event)" name="yellow">Buí</div>
<div id="drag-1" class="colour" draggable="true" ondragstart="drag(event)" name="red">Dearg</div>
<div id="drag-7" class="colour" draggable="true" ondragstart="drag(event)" name="violet">Corcairghorm</div>
<div id="drag-5" class="colour" draggable="true" ondragstart="drag(event)" name="blue">Gorm</div>
</div>
<div style="clear:both"></div>
<h1>Your score is <span id="score">0</span> out of 7</h1>
</div>
As several others have stated, your blockResults function is not being invoked. Once it is being invoked there are 2 errors that are preventing count from incrementing properly:
dropzone will never have children. You already check for the presense of children in this line: var dropzone = hitblock.lastElementChild; So I changed the if statement to just if (dropzone) {
The line var blockId = dropzone.firstElementChild.id; was a bit confusing to me as you are trying to get the id of the block but you are looking at the child's Id which is not present. I changed the line to var blockId = hitblock.id;
The counter begun incrementing after these two changes.

Categories