Todo Draggable - stevendevs/ALPHA-BLOG GitHub Wiki

Part 1

app\views\articles_article.html.erb

<li draggable="true">

app\views\articles\index.html.erb

<li draggable="true">

app\views\articles\index.html.erb

<li draggable="true">

Controlador stimulus

-/bin/rails g stimulus reorder

controllers\reorder_controller.js


  dragstart(event) {
    console.log(event);
    const dataNode = this.getDataNode(event.target);
    console.log(dataNode);
  }

<li 
  class="list-row flex justify-between items-center p-4"
  draggable="true"
  data-reorderable-id="<%= article.id %>">

conrolador


import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="reorder"
export default class extends Controller {
  connect() {
    console.log("Reorder controller connected");
  }

  dragstart(event) {
    console.log(event);
    const dataNode = this.getDataNode(event.target);
    console.log(dataNode);
    event.dataTransfer.effectAllowed = "mode";
  }

  getDataNode(node) {
    return node.closest("[data-reorderable-id]");
  }
}

you've got a to-do app and you want to be able to move those to-dos around now you could have some buttons to do that that's a great affordance but drag and drop is a great way to feel interactive and it's actually really easy to do with stimulus and hot wire let's get started now this tutorial is just going to focus on the front- end part part two will have the database operations where you'll actually do the prioritization of moving things around but for now I'm just going to show you how you can actually move the twoos around change the HTML and then where you could hook in some kind of response to the server and then get the actual changes done first thing I want to do is actually Draggable Items make the item draggable now I've got these to-dos here and if I look at this know I can't just sort of highlights it but what would be great if I could actually move around so to make something draggable just add a dragable attribute to the HTML save that and now you can see that I'm actually moving things around now nothing's changing on the page nothing's happening but now I'm able to hook in some JavaScript events and actually make things over since we're going to do this with stimulus let's make a stimulus controller so now we've got a reorder controller that we can use pretty straightforward I'm going to hook this up I'm going to put this on the index because it's going to be for the list of Dos now dragging and dropping is a bunch of different events and there's uh so we'll just go one by one and we'll kind of build this gradually and just show you all the things you can do the first we're going to event is drag start which makes sense because it's the start of the draging event this is our opportunity to actually tell the browser whether or not we want to continue with the drag operation so we'll go here just step out the method and then we'll go to the page index HTML start adding some actions okay so we're just going to log the event go to the console here and you can see I moved it and we got that drag start for any of these and you can see we have access to the Target uh there's a data transfer this is going to be key when you're trying to keep track of what's moving okay now we'll move over to the to-do and you'll notice that the to-do has the ID which we can get let's also add a data attribute that we can use this will help us keep track of what we're moving around and we can use it to find the elements as we're performing our drag operation so let me go to the drag reorder controller and I'm going to use that data attribute we just added and we're going to use this to perform a search for that um element that that is sort of the parent of you will of the to-do so that main div because when you're dragging this you'll see like this form could be dragged the button can be dragged the name and there's a bunch of different objects um especially with you're dragging over this is where it becomes more important so we want to be able to get the the main div that the to-do is on in order to have the right UI changes that and we can test out our get data node with console is not log event Target and so that's that div right there now again I could drag these things and we're going to get the right div right there then finally in order for this to work let's set this to be theow so that's a drag start that's the first bit of this and then the next Drag Over action want is actually the drag over and this is what gets fired on a particular Target and this is going this is where we can say whether or not this should be dragged over and kind of continue the operation so it's a JavaScript event like anything else under our controller they show you who this gets called on so we'll take the event log it and then we'll EV we'll log the node that's a Target and you'll see that it's going to be different than what we're dragging so it's a lot of so to-do one was the first item that we drag the start of the and then as we dropped it got dragg it over Todo three right here and so that's why it's very helpful to have that way to get the node that we dropped on because you could drop it on the button you could drop on the text and this function is going to help us make sure that again we're looking at the right item as we're starting to move these around now finally my drag over I need to turn true and then we'll call event. prevent default keep it all right now now that I'm dragging over we can get to the drop event need to this any more this here just so we can see what's going on we've got drag start drag over and then drop so I'm dragging I'm dragging I'm dragging and I drop it and so to-do one was the first one I pulled up and then to-do three is where I dropped it now you'll notice we uh we need to kind of keep track of what we're actually what we're starting with and what we're moving so the drag operation is interesting you can actually add data to this data transfer that you can then pull off in another spot so we'll set the data right here we'll give it a key this could kind of be whatever the drag key and then we'll get the ID of the node so close that out and then on the drop we'll actually pull that data out and I could show you that now this might be nice to refactor this is kind of a couple things and then also having a string right here let let's copy that just to keep track of that so it gets stringly it's not stringly typed then we'll log this just to see what we got so I'm going to drag this over and then we got the ID so dropped it onto do three but the ID is one and then we'll get the dragged item and we'll perform a query selector on the controller because there could be a bunch of list on the page and you don't want to pull something from a different list just to show you that item so again to-do one we're dragging dropping it on to-do three so to-do three was that first Target here and then to-do one is the Target that we are dropping so now we know where we're going to drop the to-do and we know where it's going to land and so now we can just do some Dom ulation and move the item around so we'll say if drag item so that exists you know just be defensive because I could go wrong now you know we are going from the top to bottom here but we could also go from three to one so part of the manipulation is we want to know which way we're ordering things let's get the drop Target so there's a really Nifty method called compare document position and this is a way to see where things are in relation to each other um anywhere in the Dom since these two items are going to be in this case on the same list it's just a matter of finding out what they should be um it's a it's a bit mask so in order to find the item we actually have to and it bitwise so a single Ampersand that's the bit wives and operator and then with the particular so if it's following it means it comes after the drop target comes afterwards we're going to do is insert we use the position before begin so this means it will appear um right next to it but above it you're to say right there okay and then it's not following we'll also just see where it is Drag Drop so therefore this insert adjacent element has four different things before begin which means before the element we're talking about after begin which means sort of inside this element before end which again means inside the element but at the bottom and then after end which means right after ourselves in the the Dom hierarchy so with these two positions now I should be able to move this here and you saw that make string gas goes there and we can move it back and now it goes to the top and it kind of you can see it sort of fits in the right order so it shifted those things up when I went down and I want to move this back up move this back up like that so that's pretty slick and that's just dragging and dropping and that's all in the da right now now we can make a couple of enhancements in order to make this feel more intuitive as we're going in so you can kind of see where things are the um first first thing Let's do let's sort of highlight the to-do list when I start the drag operation so let's go to the HTML here and let's start adding a couple classes call this an active Drop Zone class so this is going to go on again the whole list so let's uh give it a dotted border darken the background just to kind of show us what's active and then change this to color here add the class now on the drag start what we'll do is we will just go to this okay so the drag start will add those classes use the spread operator since it's we're using Tailwinds a bunch of classes okay so we can drag this and Drag End you'll see that it changes the Border changes the color that's great now if I let go uh nothing changes back so we added those classes but everything is still is is so we actually have to wait for that to stop and so we can listen for the drag end event so we have a drag start and a drag end to the book ends to the whole operation and we can basically do the the opposite of this so we added those classes remove those classes so now I can drag this over and the classes disappear like that pretty sweet now the next enhancement we could do is as we're dragging something over it'd be great if I could actually see kind of what the target is so we can add another class to our HTML file we'll call this drop Target and what we could do is just add an Shadow make that a gray Drop Shadow Shadow so we've got the drag over just to let us know what's happening but we need two different events the enter drag enter and then the drag leave and this is the uh the browser telling us where things are um who is is active so drag enter drag leave kind of behaves how you might think okay so let's say let get the target event add those classes here and then kind of a once we drag it over we will remove those classes and look at that you got a cool shadow as we move things over now let's see like if I put it over the button you'll see there's a weird and puts the shadow over the button which doesn't quite make sense so so what we should do is do our same thing where we get the the actually the node that data node and that gives us the parent for all this so that we're it to the parent node so I can drag the same thing but if I go over the button now you'll see if we need to remove that also when we drop the El so let's get the drop Target see it all kind of reverts back to normal once we Dro that off and as you know like we got this element it' be cool if we added a shadow to the item as dropping it over to kind of give it more of that feeling of depth so we can add another class call this active item just add that shadow so here we go dragable item cross list now I've only got the one class here but if I want to like change it or make it up we'll just make this more future proof especially since I'm using taable when I'm going have multiple classes so we'll call Active classes so now you can see I kind of got that drop shadow there it looks pretty cool and of course the drop shadow is still there so we have to remove it on the drop and so that shadow go away so we got a pretty interactive uh drag and dropper right now now obviously there's a lot more we can do to this but this is a pretty good structure to begin with and in the next tutorial we'll go on is I you could send this to the server um kind of have priority on those to-dos and then actually store that so that when you refresh the page the to-dos are in the same order as you drag them drop them so that we've got this client interaction right here and then we have to do some kind of synchronization for the server and that's pretty straight that's easy to do so no issue there so stay tuned for part two if you enjoyed this please subscribe subscribe to the channel like it if you have any questions leave a comment I'm happy to share some more on that there's a whole tutorial my on my blog which I have the link below that you can follow through enjoy