Cancel drag or disable reorder - javascript

Is there a way to cancel drop action of react-beautiful-dnd's Draggable object? I have a list of items with one item to be always at last position.
I want to disable (or at least properly cancel) drop if item is dragged below last item. I know I can exclude last item from droppable component and area, but that's not an option.

It is simple
When you drop any element in the onDragEnd method you'll get an object for destination and source so in that destination you find one index.
This index is referred to as your element at that index in your list of elements.
So you can make one condition there like if your element list length is equal to your index then don't do nothing return from that function.

Related

Cost of storing live htmlCollection vs iterating array of item IDs (and tree traversal)

The selection area contains items that are dynamically loaded (up to 100). Clicking an item, adds a copy of it to the storage box. Clicking the "x" button on an item in the storage box, removes the item and deselects it from the selection area.
Which is better practise/more efficient?
Option 1:
When the items are loaded into the selection area, store the items in as a live HTMLCollection in a variable. When the X is clicked, iterate this live collection and deselect it when found.
Question 1: Is it costly storing a live collection as a variable?
Question 2: When iterating over this live collection, does it actually iterate over the DOM or just the stored collection?
Option 2:
When the items are loaded into the selection area, store the item IDs only in an array. When the X is clicked, iterate this array, when the ID is found, perform a 'getElementById' which would traverse the DOM and then deselect it.
Neither would be a an issue as iterating over 100 nodes is not a lot.
But there is a 3rd option, storing a reference to the original directly on the clone. This way you can later on find the original by just looking at the clone's relevant
property.
So after you clone, add a property to it with the original
const copyNode = originalNode.cloneNode(true);
copyNode.referenceToOriginal = originalNode; // make sure the property name is something that will not clash with built-in properties
then when you wan to deselect the original (after clicking on the X of the clone)
const clone = clickedNode;// somehow get the copied node you clicked the X of
deselect( clone.referenceToOriginal );
clone.remove(); // remove the clone from the DOM

The last created element isn't the one I dropped

I have to do a drag and drop program so i use Vue.Draggable but when i drop my element into the second list the last created element on that list isn't the one i dropped but the one who had the value replaced.
So for instance if i have a drop array like that:
var a = [
{
name: 'element1'
},
{
name: 'element2'
},
...
]
and I drop an element before the first element of the second list, the last created element will be 'element1' and I need my program to make the last created element the one droped
I don't know how Vue.Draggable does that but when I had programmatically
an element somewhere in the second list like so secondList.splice(3, 0, newElement) the last created element is the one i want (newElement)
Here's the code from the first list:
<draggable v-model="blocks" :clone="clone" :options="draggableOptions" #end="reGenerateUuid">
<block
v-for="b in blocks"
:key="b.props.uuid"
:title="b.title"
:image="b.image"
#click.native="addBlock(blocks[key])" />
</draggable>
the second list is a rendered component so I can't share it because it's massive.
The second list doesn't use v-model with the draggable component but the list prop, because from what I understood I can't put a v-model on a rendered element in VueJS.
The elements draggable on the second list doesn't have the key prop because I don't want them to regenerate.
Maybe I need to specify how draggable should add the element to the second list?
Does anyone have an idea?
The elements draggable on the second list doesn't have the key prop
because i don't want them to regenerate.
You need the key prop. Otherwise Vue doesn't properly keep track of the order of elements.

Move between lists open multiple times

I'm trying to create an app that moves elements between two lists. When the element in the joblist gets clicked it has to open multiple times.
So when I click on: Open: 2 x. This elements has to move to the other list but also show up there twice.
I have no idea how to do this and where to start. I got it so far that you can click the element and it moves to the other list. But i don't know how to multiply it by the number.
$scope.toB = function(item) {
$scope.listB.push(item);
$scope.listA.splice($scope.listA.indexOf(item), 1);
};
$scope.toA = function(item) {
$scope.listA.push(item);
$scope.listB.splice($scope.listB.indexOf(item), 1);
};
My version on plunker
Here is an image that displays what I mean.
Based on your description, I made this:
http://plnkr.co/edit/K9SlyYkJLJjLm9QH0MqV?p=preview
so now when an item in the left list is clicked, it'll show up in the right list x times, where x is the item's id attribute. You can replicate the code to also clone items when clicked in the right list.
Was this anywhere near what you needed, or if not, can you explain your problem in a bit more detail?

How do I get the bottom-most element, or, a list of all elements under my cursor?

I'm creating a drag and drop system that includes sortables, and I'm trying to replicate jQuery's insertBefore/insertAfter behavior when hovering over a list of elements. As such, I have an element under my cursor and I want to put a placeholder where it would show up in the list.
I've tried:
document.elementFromPoint - this only gives me the topmost element
document.querySelectorAll(':hover') - this gives me the containing list and the dragged element, but not the intermediate element that I would insert a placeholder before/after
checking event.toElement, .srcElement, etc.
settings pointer-events: none on the dragged element - this just seems to remove it from the document.querySelectorAll ":hover" list
I want to avoid searching through all items in a list to see if my mouse cursor is inside their boundaries if possible, because I suspect it will be a huge performance hit.
Use document.elementFromPoint.
You need a list of displays and a list of elements.
For each element: (1) save the display string to a list, (2) set display to "none", (3) add the element to a list, and (4) check the element at the point again.
Then, go through the element list in reverse order and set the display back to what it was.

Can you explain this odd behavior with dragging items into nested sortables?

I have the following setup:
A sortable list where one of the <li> has a table with lists in each cell.
All of the lists are sortable with each other.
Draggable items that can be added to any of the sortables
Issue: When adding a draggable item ('drag 1', 'drag 2', 'drag 3') to one of the lists in the horizontal lists (table of lists) it duplicates the draggable when dropped. Sometimes it will create both copies in the same list or one in the item list and one in the column list.
Here is a demo: http://jsfiddle.net/MQTgA/
Question: How do I prevent the second item being created when dropping the draggable?
UPDATE: With changing the class names of the horizontal lists to something else ('hlist') and omitting the new class name from the 'connectToSortable' option ('ul.hlist'), it no longer drops two copies and still allows the item to be dropped in any list. This doesn't seem right. Also when trying to drop an item into the horizontal list instead of the main list it seems very touchy as well (won't make for a good user experience). Thoughts?
Updated demo: http://jsfiddle.net/MQTgA/3/
It's doing that because your top level unordered list ( the one with Items 1 - X) has the same class as the tables unordered list. If you change the top level , to a different class name it should stop double dropping the draggable. I hope I'm understanding your problem correctly, here is my change. New code
EDIT: Actually that won't help either because then you wont be able to drop into your upper lists. I think the issue is that as you are dragging and dropping jquery doesn't know which ul you actually want to drop into. You could try making all the elements a little bigger so the user would not have to finesse the draggable into the right spot.
With some more experimenting I have found the best way is to have the horizontal lists not part of the main list. This way there are no double items being created when an item is dropped onto them and no touchiness when moving items around.
Here's a demo of what I'm going with looks like:
http://jsfiddle.net/MQTgA/5/

Categories