I got some problem with my code but I simply cannot put my finger on what would be at fault in that situation I am lost.
So the situation is as follows, I am making a simple drag and drop interface by using jquery, all it does is: Make a grid, add/remove "pawns" depending on a certain table in the same page and drag&drop whatever pawn you want in whatever square you wish to. Everything works as expected but almost always when I try to drop the pawn on a square it teleports in a random position, rarely it does drop where it is expected to. I am not sure it is relevant but I am using laravel 10 and this is a blade file, Any suggestions I could try?
<div class="col-md-3 gridframe">
<h3 class="text-center">Character Grid</h3>
<div id="grid" class="row mx-auto">
</div>
</div>
<style>
.gridframe {
width: 300px;
border: 1px solid black;
overflow: hidden;
}
.grid-cell {
width: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
position: relative;
float: left;
}
.character {
width: 30px;
height: 30px;
background-color: black;
color: white;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
position: absolute;
top: 10px;
left: 10px;
}
</style>
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script>
function insertCharacter(nickname, hp) {
var cells = $('.grid-cell');
cells.each(function() {
if (!$(this).children('.character').length) {
var row = $(this).data('row');
var col = $(this).data('col');
$(this).append('<div class="character" data-hp="' + hp + '">' + nickname + '<br>' + hp + '</div>');
return false;
}
});
// make characters draggable
$('.character').draggable({
revert: 'invalid',
zIndex: 100,
start: function(event, ui) {
$(this).css('cursor', 'pointer');
},
stop: function(event, ui) {
$(this).css('cursor', 'auto');
}
});
// make grid cells droppable
$('.grid-cell').droppable({
accept: '.character',
drop: function(event, ui) {
var character = ui.draggable;
// var characterHP = character.data('hp');
character.appendTo($(this));
}
});
}
$(document).ready(function() {
$('#character-table tbody').on('DOMNodeInserted', 'tr', function() {
var nickname = $(this).find('td:eq(0)').text();
var hp = $(this).find('td:eq(1)').text();
insertCharacter(nickname, hp);
});
$('#character-table tbody').on('DOMNodeRemoved', 'tr', function() {
var nickname = $(this).find('td:eq(0)').text();
$('.character').each(function() {
if ($(this).text().includes(nickname)) {
$(this).remove();
}
});
});
var gridSize = 10;
var grid = $('#grid');
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
$('<div class="grid-cell" data-row="' + i + '" data-col="' + j + '"></div>').appendTo(grid);
}
}
});
</script>```
In my experience, getting draggable
and droppable
to work together has the same inconsistencies you mention. Unless they are required, I would suggest trying sortable instead. Sortable functions very similar to draggable + droppable and allows you to link multiple containers using the connectWith
property.
Here is a simple example:
let gridSize = 5,
characters = [
{ name: 'Frodo', hp: 100, type: 'hobbit' },
{ name: 'Data', hp: 105, type: 'android' },
{ name: 'Spiderman', hp: 62, type: 'human' }
];
$('.grid')
.css(`grid-template-columns`, `repeat(${gridSize}, 4rem)`)
.html([...Array(gridSize**2)].map(() => '<div class="cell"></div>').join(''));
$('.characters')
.html(characters.map((character) =>
`<div class="character"><div class="stats"><p>${character.name}</p><p>hp: ${character.hp}</p></div></div>`).join(``))
.add('.grid .cell')
.sortable({
connectWith: '.characters, .grid .cell',
cursor: 'grabbing',
receive: (e, ui) => {
if(ui.item.parent().hasClass('cell')) {
let $cell = $(e.target),
$character = ui.item,
$characters = $cell.find('.character').not($character),
coords = [$cell.index() % gridSize, Math.floor($cell.index() / gridSize)];
//do stuff
}
}
});
.grid{
border: 2px solid gray;
display: grid;
width: fit-content;}
.grid .cell{
align-items: center;
aspect-ratio: 1 / 1;
border: 1px solid lightgray;
display: flex;
justify-content: center;
overflow: visible;}
.grid .cell:has(.character):hover{
border-width: 2px;
box-sizing: border-box;}
.characters{
border: 2px solid gray;
display: flex;
gap: 1rem;
margin-top: 1rem;
min-height: 3rem;
min-width: 6rem;
padding: 1rem;
width: fit-content;}
.character{
align-items: end;
background-color: #000000;
border-radius: 50%;
color: #ffffff;
display: flex;
height: 3rem;
justify-content: center;
text-align: center;
width: 3rem;}
.character .stats{
background-color: inherit;
padding: 4px;}
.character p{
font-size: .66rem;
margin: 0;
white-space: nowrap;}
<div class="grid"></div>
<div class="characters"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>