0 votes
by (2.7k points)

As previously explained here, I am trying to make a drag-and-drop inventory. However, if you drag enough items into it, they overflow. How do you fix this? The containerToList() function does not work along with the .length function, so I cannot find the size of the Inventory. And even if I could, how would I go about removing the drag-and-drop attribute until the player removes an item?

1 Answer

0 votes
by (68.6k points)
selected by
 
Best answer

How do you fix this?

By changing the drop() function so that it doesn't move the dragged element if the container is "full".  For example, the following pulls the "size" of the container from the data-size attribute and limits the container to that many items:

window.drop = function (ev) {
	ev.preventDefault();

	var maxLength = Number(ev.target.getAttribute('data-size'));

	if (ev.target.children.length >= maxLength) {
		return;
	}

	ev.target.appendChild(
		document.getElementById(
			ev.dataTransfer.getData('id')
		)
	);
};

Then you'd simply add a data-size attribute to your container elements.  For example:

<div id="inventory" ondrop="drop(event)" ondragover="allowDrop(event)" data-size="1"></div>
<div id="chest" ondrop="drop(event)" ondragover="allowDrop(event)" data-size="10"></div>

 

The containerToList() function does not work along with the .length function, so I cannot find the size of the Inventory.

Nitpick: The length property, not function (or method in this case).

All three of the ...ToList() functions return arrays, so of course they support the length property, which is an intrinsic property of arrays.  For example, both of the following will print the current number of items within the #inventory container:

<<print containerToList('#inventory').length>>
	/* OR */
<<print inventoryToList().length>>

I'm unsure why you thought that wouldn't work, but I assure you that it does.

by (2.7k points)
Ok, I see, the containerToList() function does work with the length property - I thought it wouldn't because when I printed the contents of a containerToList() function, there were no brackets or commas.

Anyway, the problem with the new code is that I cannot have more than one of an item in the inventory at once any more. E.G. I cannot have 2 or more Health Potions - If I try to drag a second one in it just does not work. How do I fix this?
by (68.6k points)

Did you change the value of the data-size attribute on your inventory container?  Its value should be equal to the number of items you can (or want to) fit within the container.  My example has it set to 1, so if you didn't change it as I said you should, then that's the problem.

Beyond that.  Have you given the "Health Potions" different IDs?  IDs must be unique, so if you've tried to reuse the same ID, you're going to run into issues.

by (2.7k points)
They all have the same ID. I want the player, when they defeat an enemy, to sometimes be rewarded with a Health Potion. There is a second drag-and-drop <div> called "use" that you can drag the potions onto to be used. Should I use class='health-potion' instead of id='health-potion'? Or do I have to use some other method?
by (68.6k points)

If you want multiple copies of the same item/type of item, then there must be some way of uniquely identifying the dragged element, so the system knows which one to move.  Classes and/or any other non-unique property cannot be used for this purpose.

Classes are great for styling similar types of things, but uniquely identifying them, not so much.

I'm going to assume that you do not want to manually create unique IDs for every item you plan to have in your project, so the best thing would probably be to dynamically create a temporary unique identifier for an item when you start the drag.  Here are new versions of drag() and drop() which do exactly that.

window.drag = function (ev) {
	var dragTarget = ev.target;

	while (dragTarget && !dragTarget.hasAttribute('draggable')) {
		dragTarget = dragTarget.parentNode;
	}

	if (!dragTarget) {
		return;
	}

	var dragId = Date.now() + ':' + Math.random();
	dragTarget.setAttribute('data-dragid', dragId);

	ev.dataTransfer.clearData();
	ev.dataTransfer.setData('text/plain', dragId);
};

window.drop = function (ev) {
	ev.preventDefault();

	var maxLength = Number(ev.target.getAttribute('data-size'));

	if (ev.target.children.length >= maxLength) {
		return;
	}

	var dragId     = ev.dataTransfer.getData('text/plain');
	var dragTarget = document.querySelector('[data-dragid="' + dragId + '"]');

	dragTarget.removeAttribute('data-dragid');

	ev.target.appendChild(dragTarget);
};

 

...