Kanban Board Overview0:00
Now, let's build a Kanban board with drag and drop, a minimal version of Trello, because why not? So here you see a three column layout, some items in to do, some in progress and some in done. You can drag any item and put it anywhere in the other column. You can also drag items within the column. You can add a new task quickly, just type anything and hit enter, it will get added and you can quickly add another one as well, or you can cancel. You can also hover over any item and delete it, you'll get a confirmation model. So here's the minimal version.
Static Board Setup0:32
You can also hover over any item and delete it, you'll get a confirmation model. So here's the minimal version. Let's build it now. So I'm starting with a static list. You can't drag any item. There's no way you can delete or add anything yet, but all of this is coming from the database in our LiveWire component. So let's look at that. Here's the minimum LiveWire component. We have columns as the computed property.
Here's the minimum LiveWire component. We have columns as the computed property. It gets all the tasks in the database, orders it by position, groups it by status, which is to do, in progress and done. This union is there to make sure that all three lists are there. Even if they are empty, we at least have an empty collection. And down here, the UI is just very simple. We have some column configurations like the label and the status color. And for each of the columns, we are displaying the column header with this count of how many items are there, the label and the color, of course.
And for each of the columns, we are displaying the column header with this count of how many items are there, the label and the color, of course. And then we have the task list. Here we are looping through each of the items within that status, whether it's progress or done. And here we're just showing the task title. So if there's nothing in the list, we show no tasks. So this is what we are starting with. Let's add a way to sort the items within a column first. LiveWire 4 makes it very easy with the new wire sort.
Sorting Within Columns2:04
Let's add a way to sort the items within a column first. LiveWire 4 makes it very easy with the new wire sort. So just go into the parent of the items that you would like to sort. Simply add wire sort and pass in the method that you would like LiveWire to call as soon as the item is dragged and dropped. So let's call a method handle sort. I'm yet to add this. And for each list item, along with wire key, we also need a wire sort item. Wire sort not dot, this has to be a coolant, wire sort item with the task ID. So now this handle sort method will be called along with this ID and the new position which
Wire sort not dot, this has to be a coolant, wire sort item with the task ID. So now this handle sort method will be called along with this ID and the new position which the item was dropped into. So let's add the method here. I'll just be pasting it. So we have the handle sort that accepts the ID of the task and the new position. So let's first find the task and get all the items from the column except for the one that was dragged and dropped. So except for this current task, we get everything else ordered by position. And later we just add this task into the new position.
So except for this current task, we get everything else ordered by position. And later we just add this task into the new position. So that way we have the array with the correct positions. We just update them in the database. And finally, we unset the columns computed property so that it can compute again. This much should work. Let's try. Refresh. Let me try dragging something. Yeah, it works.
Let me try dragging something. Yeah, it works. Let me refresh. And yes, I did refresh. It persists. So this is working. But when I hover over the list, I should change the cursor to show that you can drag this. So let's go back to the list item and to the class. Let me add cursor grab and active cursor grabbing so that when I'm actually grabbing it, you see a closed fist.
Let me add cursor grab and active cursor grabbing so that when I'm actually grabbing it, you see a closed fist. Let's try this out. So you see when I hover over it, I see an open fist. And when I start grabbing it, you will see the closed fist. So this is working great. Now if I try to move it into the other column, nothing happens. And Livewire makes it very easy to sort items between columns. So let's go back. When you want to sort items between columns, they have to belong to the same group.
Moving Between Columns4:31
So let's go back. When you want to sort items between columns, they have to belong to the same group. And that you can specify using wire sort group. And you could give it a name, any name like Kanban. And this name will be same for all the group because we are anyway in for each. And for each of the columns, we need to add an ID, which could be the status itself. So wire sort group ID could be the status. Now this will be the third parameter that will be passed into the handle sort method. So let's update that method. So right here we have string status.
So let's update that method. So right here we have string status. Let's save the old status. Yeah, let's get the task status and save it into old and update the status now with the new one. So now we get the siblings of the new column where it was added into. So the new column is status. We get all the siblings from there, except for this task ID and everything else is correct. We just order it and we just order it correctly and update all the positions. And if the item was dragged into a new column, that is, if old status is not same as the
We just order it and we just order it correctly and update all the positions. And if the item was dragged into a new column, that is, if old status is not same as the new status, then we also have to reorder the old one. So I'll create another method for reorder, public function reorder. Yes, it just takes the particular status, gets all the tasks and just updates the position with the index. That's about it. It should work now. Let's check. So let me drag something from one column to another and yes, perfect.
Adding New Tasks6:17
Let's check. So let me drag something from one column to another and yes, perfect. You can put it in any position in the beginning, in the middle or in the end and refresh. The order is persisted. So now we have the Kanban board with drag and drop ready. We just have to be able to add another item to each column and be able to delete them. So let's add a button first, right after the task list here. Let me add a button. This would be an Alpine component because we should be able to toggle the button with the input.
This would be an Alpine component because we should be able to toggle the button with the input. So initially we set adding to false so we can show the button. If adding is true, then we show the input, which I'm going to add next. So clicking on the button will set adding to true. Let me add a form with input and add and cancel buttons. Here's the form which shows when adding is true and once again, all the keyboard navigation that needs to work on clicking escape, it closes. Clicking anywhere outside will also close it and this is just an input. Here's the add button.
Clicking anywhere outside will also close it and this is just an input. Here's the add button. Clicking on this will actually submit the form and clicking on cancel will simply close the form, right? So we see add task button on all three lists. Let me click on it. I'm seeing an input with add and cancel. Cancel already works and it works on everything. If I click add task on a different column, notice that because we have a click outside, the previous one closes, which is great.
If I click add task on a different column, notice that because we have a click outside, the previous one closes, which is great. Now clicking on it should automatically focus on the input so it avoids another click from the user. For that, let's just go to the add task button and after click, that is after this is done on next tick, using next tick, let's focus on this input. The input already has an XRef as input, so we are able to focus on that. Click on add task and it's automatically focused. Now let's make it work. Go to Livewire and create a new public property, which is new task title, and let's create
Now let's make it work. Go to Livewire and create a new public property, which is new task title, and let's create a method to add new task. So public function add task, we accept the status because we need to know which column the task is being added into. We take in the title, we will bind this public property to the input. So we get this title and trim it. If it's blank, we just return and then this could be done inline. We just get the max position because we always add the new one at the end of the column. So we just have to create this task, new task with the title status and get the max position
We just get the max position because we always add the new one at the end of the column. So we just have to create this task, new task with the title status and get the max position of that status column. Add one and then we just reset it to blank and once again, unset the columns computed property. Now let's go to the input and bind it using WireModel, where's the input? It's right here. So let's use WireModel, we don't need differ, WireModel, new task title. And on submit, we need to call the function. So right here, WireSubmit, we don't need prevent, WireSubmit add task and we need to pass in
And on submit, we need to call the function. So right here, WireSubmit, we don't need prevent, WireSubmit add task and we need to pass in the status that is the column. This should work. Let's try it out. Okay, let me add a task in progress. So this is in progress, hit enter and there we go. Let me refresh and yeah, it is working. You can add it in any other column and it will work. Finally, let's add a close icon here on Hoover.
Deleting and Polish10:11
You can add it in any other column and it will work. Finally, let's add a close icon here on Hoover. So we should be able to delete that item, scroll up to the list item. Let's replace this with a flex container with the title and the delete icon like so. So we have the task title, we have flex and we have this button. Now it'll be nice to see the button only when the list item is hovered. So we can simply add a group here, group class on group hover, we can show it, otherwise we can hide it. So we can do something like opacity 0, group hover opacity 100. Perfect.
So we can do something like opacity 0, group hover opacity 100. Perfect. Clicking on this button, we should be able to delete the item. So wire click, delete task and we pass the task ID. And also while clicking on this button, we shouldn't trigger the drag. So we just add wire sort ignore. So this is taken care of. Let's add the delete task method on top, public function delete task. It finds the task, it makes note of the status, deletes the task and then reorders the status. I think we also need to unset the columns computed property once again.
It finds the task, it makes note of the status, deletes the task and then reorders the status. I think we also need to unset the columns computed property once again. Okay, so now the delete feature should work. Let me hover over the list item. I'm able to see it. So let me click on delete and yeah, we forgot to take a confirmation from the user. So let's go back, scroll down to the delete button, add wire confirm. You can obviously use a model if you would like. So this just uses the default browser confirmation. Are you sure you want to delete this task and then deletes it.
So this just uses the default browser confirmation. Are you sure you want to delete this task and then deletes it. So now click on it and you see, yes. So it's deleted and the count is updated as always. One last thing, there's a small issue here. So let's say I start dragging the second item from the third column. Notice how the second item in the third column now gets a hover and the delete icon there is visible. That's very annoying. It doesn't look right.
That's very annoying. It doesn't look right. So to avoid this, we can hide the close button while the sorting is taking place. LiveWire doesn't yet have a native way of doing it, but since LiveWire uses SortableJS behind the scenes, SortableJS adds a class called sorting to the body while the sorting is taking place. We can make use of that and we can hide the button if the body has sorting class, which we can easily do using Tailwinds in variant. So we say in any parent which has the sorting class, we can set opacity to zero and it needs to be important because a group hover has opacity 100.
So we say in any parent which has the sorting class, we can set opacity to zero and it needs to be important because a group hover has opacity 100. We need to override that. Let me start dragging and notice you don't see that icon anymore. And that's about it. That's our Kanban board and this is also the end of this course. Thank you for watching and enjoy building with LiveWire and Alpine.
