Open AnteroRamos opened 3 years ago
Change
let sortable = new Draggable.Sortable(document.querySelectorAll('.drop-field'), {
draggable: '.sortable'
});
to
let sortable = new Draggable.Sortable(document.querySelectorAll('.form-zone'), {
draggable: '.sortable'
});
will work fine.
I tried that class because in the documentation said that sortable only worked with direct children, but couldn't make to work... must have done something wrong. Thank you.
Just so I don't need to open another issue... Is it possible to have the sortable feature while dragging from the container on the left to the one on the right in the way I have the code? Basically, when dragged from the left to the right container I would be able to drag it anywhere I want.
drag:over
event can do this. For example https://jsfiddle.net/9q2mu6kd/1/
That way it let's me change when dragging but it adds to the last position because of the way I add the html, with += innerHTML. I didn't see it, but you guys have any function to replace the item without a huge amount of if statements?
The way I was going to do it was:
droppable.on('drag:over', function (evt) {
if (overContainer !== dropField) {
return;
}
if (mirror2.id === "campoTexto") {
evt.over.parentNode.insertBefore(texto(), evt.over);
} else if (mirror2.id === "campoEmail") {
evt.over.parentNode.insertBefore(email(), evt.over);
}
});
But, in the future, I'll have a lot more fields. Would there be a better way to do this with the library?
How about in left container
<li class="field-item">
<div class="field-item__name">E-mail</div>
<div class="field-item__content hidden">
<label>Email</label>
<textarea type="text" name="teste" placeholder="mail"/>
</div>
</li>
after drop to right container
<li class="field-item">
<div class="field-item__name hidden">E-mail</div>
<div class="field-item__content">
<label>Email</label>
<textarea type="text" name="teste" placeholder="mail"/>
</div>
</li>
Thanks for your input! That would actually work, but I would have a LOT of HTML that is very similar (I will use a fair amount of code for each field, not only the one I sent, that's a example). Since most of the HTML is similar, and only changes some things I was thinking of doing an array with the things that change for each and making a template that receives those things as parameter... That way I would have almost no HTML code in comparation.
That said, would there be another alternative with the way I have the code?
Did you mean this method?
<draggable
v-model="myArray" --- an array of each field
group="people"
@start="drag=true"
@end="drag=false"
item-key="id">
<template #item="{element}"> --- create each field according to the myArray
<div>{{element.name}}</div>
</template>
</draggable>
No, I actually didn't know that method... And I also don't know what it does ahah
What I mean is this:
let htmlToAdd = {
campoTexto: ['campoTexto'],
campoEmail: ['campoEmail']
}
droppable.on('drag:stopped', function (evt) {
draggedElementId = evt.originalSource.id;
label = htmlToAdd[draggedElementId];
makeFields(label)
dropField.querySelector(".field-item:not(.sortable)").remove();
});
function makeFields(label) {
dropField.querySelector('.form-zone').innerHTML += `<div class="sortable" draggable=true><label>${label}</label> <input type="text"/><br></div>`;
}
This way I only have one template and an object with all the different information. This may not make sense in the way I have right now, only 1 item per array, but in the final version there will be around 5 items for each.
That said, is there any way to add the field to the position I want when dragging, in the way I have the code right now? I'll leave the JSfiddle link, maybe it's easier:
I may not understand “add the field to the position I want when dragging”.
My understanding is that if you drag the Email element on the Campo element, the Email element will be inserted before the Campo element. This can be done by using drag:over
manipulate DOM.
Yes, that's what I meant. But I've changed my mind and I'm using your approach to create the fields.
But until now, I hand't noticed I wasn't adding the fields to the "form-zone", it was only being added to the container. I changed from '.drop-field' to '.form-zone' (where the form is created) and not being able to change the order.
Change line 59 if (overContainer !== dropField) {
to if (!overContainer.classList.contains('form-zone')) {
can make the mirror2 insert before the over element.
Thank you! Just one last question, when sorting in the form, it always creates a another instance of the element I'm dragging below, but it doesn't delete... How would I be able to do that?
Sure. Just need to change the mirror:created
listener to:
droppable.on("mirror:created", function (evt) {
if (evt.source.classList.contains("sortable-mirror")) {
mirror2 = evt.source;
return;
}
mirror2 = evt.mirror.cloneNode(true);
mirror2.classList.add("sortable-mirror");
});
That worked very well! Thank you!
Still on sortable, I added a 'form-row' to make the fields side by side. But I want to give the option to add below too (also in the middle of 2 fields, not only at the end of the form). For that, with bootstrap I would have to add another 'from-group', but I'm not being able to figure out a way to trigger the creation of a 'form-group'. This is what I did:
https://jsfiddle.net/cuf6tn51/3/
Is there a way to do that with this framework?
Suppose we have two rows of elements.
item1
item2
Do you mean you want to have an option if you select it, you will be able to drag an element to ph, ph' and ph''. And if you unselect it, you will be able to drag an element to ph2 and ph2''.
ph
item1 ph2
ph'
item2 ph2'
ph'‘
This effect can be achieved by changing the css flex property.
Essentially, yes, that's it! But I wanted to be able to do that with the drag motion. I could either drag to the side or below, I don't know if that's possible.
Also, I'm using bootstrap. What flex property should I use for that use?
How about try https://getbootstrap.com/docs/5.0/layout/columns/ . Using the col-12
class to drag to the below, and the col
class to drag to the side. Like https://jsfiddle.net/acshwvr5/
I've tried that, but then I wouldn't be able to add fields to the side if I wanted with the col-12.
I've managed to make it work it another way, where I have two divs and if I drag to the second one, it will add the another like (a new form-row) in the div above. It's a workaround that I think will do just fine.
In this new way, the problem is: I'm not being able to add a event listener to a "hr" element inside the form.
document.querySelectorAll('.hr-form-seperator').forEach(item => {
console.log("justThis");
console.log(item.innerHTML);
item.addEventListener('click', event => {
console.log("this123");
})
});
I click, and nothing happens, but if I do this code inside the browser console, it works. I think it might have something to do with the draggable instance. Is there any way to "turn it off" when I stop dragging? I already remove the form container when I stop dragging, but didn't seem to make any difference. Or if there any other solution to force the add event listener on click to work..
formDivs.forEach(e => droppable.removeContainer(document.querySelector(e)));
It seems that the element may add after the event was listened to. Or it was under a transparent element, so it was not clicked. Like: https://jsfiddle.net/agq6mkjL/
That makes a lot of sense! Didn't think abou that one.
I think I've managed to fix that issue. Can you just give me an idea on why I can't add a field above the 'div' with the "hr" element? I do not mean inside, I want to be able to add the field above that line. I'm gonna have multiple of them across the form and I wanted to be able to add fields between them.
Change <div class="div-for-hr-seperator">
to <div class="div-for-hr-seperator field-item">
can do this.
Correct, that would work! But when I drag the item it will be added inside the div instead of below. Is there any way to make it only sortable, for example, I drag and it gets added below or above the line. I could manage to do it with vanilla JS, just asking if there is any way with the library.
Seems no way with the library. As far as I know, unless the official Sortable, Swappable or Droppable libraries fully meet the requirements, Draggable can only be used, which can only help you create mirrors and monitoring items moving in and out of items or containers. Others include creating new elements, moving elements to specified positions, etc. can only be achieved by vanilla JS.
Hello,
I have this drag and drop form builder where I want only one container swappable. Is it possible to have an instance of Draggable.Draggable and another of Draggable.sortable? I've made this code, but I'm not being able to sort the items on the right container. This is the code I have:
https://jsfiddle.net/gx32et8b/4/
Thank you in advance for the explanation.