Join me while I learn HTMX and talk at you about it
Twitter: @htmxlabs
Let me try something a little bit different right now. I'm gonna basically try to get into the mind space of building a new app from scratch. And this is gonna be a to do app and it's something that I've built a long time ago. But I'd like to rebuild it with h t m x, something I use every day, and I highly encourage any developer to build their own to do app that matches with your own workflow because I think there's a ton of them out there and there's a good reason to try it, basically. Because you end up building something that actually works for you in the way that you think, and that's actually very different for a lot of different developers.
Lazarus:Some people need due dates and some people need categories and some people need, you know, all kinds of different stuff can go into your task management list, right? So that's why there's so many of them out there. And if you're anything like me, none of them have ever felt quite right cause I don't want to feel like I'm filling out a form every time I do something new. So that's why I'm I've I've built my own to do thing. And I built it a while ago, but I think it's worthy of a rebuild now.
Lazarus:Part of this is just to use htmx to build something on a daily basis. Because that's usually what I do when I'm learning a new technology. And part of it is just, for fun. So okay. So here's what I'm gonna try.
Lazarus:I'm going to enter this kind of relaxed mindset. I'm gonna close my eyes. It's almost like, it's almost like a guided meditation except the end result is going to be kind of a complete picture of a website and all the code that goes into it. So first thing we're going to do is we're going to look at what we're going to build. We're going to build a whole just basically one page.
Lazarus:It's not gonna be, you know, we're not gonna do a bunch of different screens here. This is just a to do app. So But what do we need in the to do app? First of all we need a list of items. And maybe that's not even first of all.
Lazarus:Maybe first of all we need to a way to enter the items. So we're gonna have a small form. And what are the items? I guess in a simplified version of the to do app, you really just want, I want, I should say. You can do this your own way, of course.
Lazarus:But I wanna have a task, but you also need to have details on the task sometimes. You don't always. So I'm gonna separate that into 2 parts. There's the main tasks that I have to do and then there's the details. So the main task is going to be a text input, and the details are going to be a text area.
Lazarus:So this is all going to be a form. So we're going to build this form. We're going to submit the form using h x post. So we'll just set this to h x post equals tasks, and that's it. Yeah.
Lazarus:Slash tasks. So we're gonna we're gonna put our item into slash tasks. This is just kind of using their general rest formula. And our first input is going to have a name of task. And then our text area is going to have a name of details.
Lazarus:And we are going to we're going to include along with that post, we're going to include h x headers equals. And we're gonna include that, a little bit of JSON to put the CSRF token in there. Actually, do we want to do that or do we want just let's just do an input type equals hidden and put the CRSRF token in there. So just kind of a standard way to use the to use the CSRF tokens. Okay.
Lazarus:So we have our form for adding a new task and now we are going to let's see, we have our form for a new task. Okay. That's good. So what do we do with our form for a new task? I think maybe we need to let me just think about this for a minute here.
Lazarus:Okay. When we submit, we're going to go into our web and create a route. We're going to I'm using I'm gonna be using Laravel, but this would probably work in any, you know, any back end system. You're gonna have a way to add a route. And this is going to be a post because we're receiving the post from that.
Lazarus:And it's post slash tasks. So we have a po incoming post slash tasks. That's going to go to our controller which is going to add the task into the database, Right? So we have probably, you know, a model with tasks. You create a new task.
Lazarus:You set the task itself. And you set the details to those two things that you're that were just sent in, and you save it. And that's probably all we need for now. I'm not going to worry about the we could add some other stuff along with these tasks like a due date or, you know, a sorting sorting number or something so we can keep them sorted but I don't really want to add any of that right now. Right now, I just want to keep it as simple as possible.
Lazarus:So we've created our new task. Now, we are going to send back with that response in the new in the, created let's see. What is that going to be called? We'll use store because store is kind of the most common. So that was a store function that created the new task.
Lazarus:And we're going to return a view. So we're going to return HTML of our task list because that's what's been edited along with this is the task list, right? So we have our task list. That's going to be just kind of HTML, and we're going to loop through in a for each loop all our different all our current tasks. And we'll we'll make that list active tasks.
Lazarus:So things that we haven't checked off yet. We haven't made any way to check these off yet, but we'll make those active lists. Active tasks only. So what's that list going to look like? That is going to be an HTML view.
Lazarus:We do a for each on all the active tasks. And let's put a number next to each one. So we'll start by just getting the iteration of the loop. So they don't need to be a specific task number for each task or something like that. Some sort of unique ID.
Lazarus:We don't need that. We're just gonna use the iteration of the loop. So that's going to loop through the next thing we'll need in our this is basically gonna be a table that we're building. It doesn't have to be officially a table. It doesn't have to be an HTML table.
Lazarus:But, you know, if you're using Tailwind, you can use the the things that kind of act like a table. Because we want it all to be nicely lined up. So we have our first, our iteration. So it's gonna be 1 dot, you know, just so you can see in your list how many tasks there are. And you can say, oh, okay.
Lazarus:Task 9 is something I'm working on right now. Then we need a checkbox. And this does not have to be an input type equals checkbox. Although it could be. But I think this could just be, you know, a little box with a, with a border on it.
Lazarus:Like a gray border. Just something that looks like a checkbox so that you can check it off. You can hover your mouse over it. Maybe it puts a little x in there or maybe it puts a little check mark in there. Whatever it is, we just want that little checkbox because later on, we want to be able to check it off and and sort of handle that as a way to mark things as done.
Lazarus:And then we're going to put, in the 3rd column here, we're going to put the actual task and we'll make that bold so that all the current tasks are bold. And then underneath that, in the same column, we'll put the details. Okay. So we have each item in our row now has a number, a little checkbox to say it's done, and then it has the task in bold. And then underneath that in kind of a light gray text are all the details that go along with that task.
Lazarus:And then let's add, another column for, when it was added. Right? So, if you're using something like Laravel, when it's added into the database, we get our created at stamp. We get our time stamp for when it was created. So we can use that.
Lazarus:And once we have that, we can, use like some use a let library like carbon. Something something that makes it nice like, you can say like 2 hours ago. So you use diff for humans in carbon, but there's probably other tools out there that kinda make it, you know, just puts a date on it so you can see how old this task is. You can see at a glance, you know, one day ago, 6 days ago, 2 weeks ago, etcetera. And then the last thing we'll have for our our task columns is gonna be an edit button, because we always need to be able to edit things if we type them in wrong or something like that.
Lazarus:So that's our our list view. Right? So that's what we're going to return. We're going to use that list view on the whole page. Okay.
Lazarus:So let's back up back and let's think of the whole page again. So far we we've added our new task form, but let's lay stuff out a little bit. We'll put the new task form over in the top right and make it a kind of box. And that box, again, has a text input for task and it has a text area for the details and it has a button to submit. And that whole form has on it the hx post for slash tasks.
Lazarus:And the h x target is going to be over to our left where we are gonna put the whole list of tasks. At the top of that, it's gonna say to do this week or just to do. I like to think of things in terms of weeks, so let's make this a weekly. So to do this week. Right?
Lazarus:Okay. So we have to do this week and it tells you when it was added. We have our list of tasks, each one with the iterative number in the list, a box to check it off, and the name of the task underneath that, the details, and then when it was added, and an edit button. Okay. And for now, that's all we need.
Lazarus:Let's also underneath our add new task form on the right, let's add a let's add a column, not a column, but let's add an area to put our completed tasks. So once we check them off they kind of just go underneath our our other ones. So that really the focus of the page is going to be the tasks that we have to do, which is going to be the top left, right? Okay. So we have that.
Lazarus:We have our completed tasks. So what happens when we check something off on our main list, right? We have that little that little box that we want to have at the left of each task and we want to check that off. So we want to be able to hover over our checkbox and see some sort of indicator. So we'll put like We'll put inside that checkbox.
Lazarus:We'll put something with opacity 0 and we'll do hover, you know, opacity 100 and that's gonna be some sort of icon like a check mark or a an x or whatever it is you wanna do. Right? Okay. But when it's actually clicked, so what is it on there? So we do an h x trigger equals click on that.
Lazarus:Okay. So when you click So what happens? We need to go and take that tasks that so what's set of route? H x we'll do h x do we do h x post or h x get? Let's do h x post since we're changing things.
Lazarus:Okay. So we have an h x post for that. So we'll do h x post equals slash tasks slash task ID, so whatever the ID of that task is, and then we're going to set that to let's see, okay, if we want to set it to complete. So that's one thing that we haven't added yet is whether the task itself is active. So let's actually set a completed so we'll go back to our we'll think about our original task model and on that model we're gonna have a completed at, a time stamp, so that when you check something off it sets that to now.
Lazarus:Okay. So we have a new route, let's set this actually as a specific route. It's not just a general, like, editing this route. This is gonna be tasks slash task ID slash completed. Okay.
Lazarus:So we click that. It goes to that route. It sets the completed at to now, right, and then it saves that task. And then it's going to have to do something a little different than before. Right?
Lazarus:Before, the last time when we added a new task, it just drew the updated list. But this time it's a little bit different, right, because we have the updated list, we need the list of active tasks where we're gonna remove this because it's now gone from this list and we need to redraw the completed tasks, right? So we have 2 different views that we want to do here. So we can return in our response, the list view and we're going to use actually hxswap00b. Okay?
Lazarus:So we're going to have both of those lists returned, but we're going to set the ID at the root for each one, h x swap o o b, to be the ID of the active list for one of them and the ID of the completed list for the other one. Okay? So we're going to swap out so using h x swap o o b, lets us place our response from the server side where we we decide on the server side where it's gonna go, But it's out of band of the original request. So the original request was just us checking something off. Right?
Lazarus:So it was just We haven't set a target for that yet. So it's just going into whatever target, you know, whatever target that happened on. So we're not going to do that. We are going to use hx swap OOB in the response. That's going to allow us to redraw both the active list and the completed list at the same time, right?
Lazarus:Because because those are the things that need to be updated, so we can just sort of update those specifically. Okay. So now we have a way to check it off. Now, over in our completed list, what if we screw something up, right? We need a way to put it back on the active list.
Lazarus:So we're just gonna do a button there that does the same thing And we could even use the same route, like check off completed or we could make a new route for active. Okay. So on that, we are going to have a little button for each one in the completed. Now the completed list doesn't need all the other stuff. Okay.
Lazarus:It just needs maybe maybe the number, maybe the name of the original task, it could have the details, but this is a much smaller list. It's over on the right underneath the add new task, So we don't really need that much, but we do want to have a little button on there that you can then click to put it back on the active list. So h x post equals slash tasks slash task ID slash activate or active. That goes to another route. That route is simple.
Lazarus:It goes to a controller. It just gets that task that was there in the task ID, and it sets completed at to null. And that will make it so that next time when you redraw your active list and your completed list, we want to send that same route that that we want to send those same views back that we did before with the h x swap o o b, because we're going to be sending out both the updated active list and the completed list. Alright? Okay.
Lazarus:So we now have our way to add a task, including the task, the details, and, you know, just a button to submit them. That updates our active list on the page. It goes and redraws our active list. Now we also have in that list, we have all our items. Each one has a checkbox that should work and it puts it over into the completed list.
Lazarus:And then we have a little button on the completed to send it back to the active list. Right? We haven't talked about a deleted one yet but that would be pretty straightforward. We just make a little x on each item and then when you click it, we'll probably do h x confirm equals first. Are you sure you want to delete this?
Lazarus:And then we can send an h x delete to / task/taskid, and then we handle that, on the server side. We have an incoming, delete. We have an incoming delete, so we send that to our controller and we just call delete on that particular task. And then we redraw, whichever place it came from. So, you know, we could say, actually let's just redraw the active list.
Lazarus:Once it's completed there's no need to delete it, so we're just going to redraw the active list after. Okay. So the active the delete is going to have, as a target, it's going to have the active list. So h x target equals and then the the css selector for the whole active list. And then the the response is going to update that.
Lazarus:Okay. So that seems okay so far. Right? I don't I hope you're with me. I'm sort of I'm I'm I'm kind of getting trying to get a full image of this in my head right now.
Lazarus:I think the next thing that we need to do is we need to be able to edit. Okay? So we're going to edit each one. We need to be able to edit it right in line. Okay.
Lazarus:So let's see. That means we need to build an edit form. The edit form is going to be very similar to our new form, our new task form, but it's gonna fit sort of in line in that table. So what we're gonna do is we're gonna have that edit button on each item in the active list and when you click that, we're going to send a we're gonna do a get this time instead of h everything else has been h x post, but we're just pulling in some new HTML here. Okay.
Lazarus:So we are going to send in a get and it's going to be specifically for that row. So we're going to have to give each row an ID and maybe it's like row underscore and then the task ID. That way they'll they'll be unique because, you know, they have the unique task ID. So we're gonna send in a request and we're gonna we're gonna do h x get equals slash tasks slash task ID slash edit. Right?
Lazarus:Okay. Because we're getting an edit form. And then the target is gonna be the row ID that you're on. So we're gonna replace we're gonna swap out the row that's currently there with an edit form. Okay.
Lazarus:So what's the edit form look like? It's got the in it's got the whole form. It's got the input, text. It's got an input type equals text. That's the task again.
Lazarus:And that's going to be filled in with that specific task, what's already there. Okay. And then same deal with the details. So we have a text area, name equals details, and that's going to be filled in with our task details. Okay.
Lazarus:And then once again we we do our input type equals hidden, the csrf token to make sure we have that. Now we can have, if We have 2 options here. We have a save or we have a cancel button for this edit form. Okay? So if you hit cancel then it just goes that's okay.
Lazarus:So the cancel button is going to be h x get equals slash tasks slash id. And we could just have it be the ID and and, you know, that's gonna because we don't really have a page for each task, so that route can just return that single row. So that's gonna return one single task in the format of our task row. And we're setting these up. All these little all these little views are sort of their own little blade components.
Lazarus:Blade is the Laravel version but, you know, whatever templating language you're using, you can have these little HTML snippets that you include in different places. Right? So we're gonna have that blade view, with just each task inside the blade view, and we're gonna use that when we build our initial list. We'll be looping through and including it for each row. But now we can set it up so that if you call get slash tasks and then the task ID it returns that single row.
Lazarus:So that's what our cancel button will do with the target being the row ID. Okay? So when you press cancel, it's going to the server, it's pulling that same task back and just putting that HTML back. Just like when you clicked edit, it pulled in the edit form for that and replaced it. Now it's going to put it back to where it was.
Lazarus:Okay. But if you hit save, so that's going to have an h x post equals and this time it's going to post. We could use put if we wanted to. So h x put equals and now it'll be task slash the task ID. So we're gonna put into that all our new data.
Lazarus:So when you submit the form everything else there is gonna be submitted. So we have now this whole editing workflow in there and it's going to do the same thing, it's gonna have the same response and the same target as the a check as the cancel button because all we're gonna do is after we save it, it's gonna save that and it's gonna send it back and put it back into the same row there. Okay. So we have our item, both the cancel and the save, they both end up going to the same target because they just replaced that row. But one of them goes and it saves the data first.
Lazarus:And it so it goes to its own route of updating all the data and Okay. So what is this missing? Some of the details that we haven't really talked about yet are what happens to items. It's okay, that's probably enough as it is, right? That's a functional to do workflow, because you add items, you can check off items, and you can delete items, right?
Lazarus:So that part's good, but what do we need to kind of make it something unique? And I think items shouldn't just so one of the problems with to do lists is that items just sit there, right? They just sit there forever and ever and ever. It's very frustrating sometimes, because maybe you add it to the list just so you wouldn't forget it, right? Maybe it's never gonna get done, maybe there's some reason, but you don't necessarily want to delete it because you might someday need to do this.
Lazarus:So someone tells you about something, there's some reason why you still need to have that there. So I think one thing you could do is just make it so that this to do list only shows your recent items. So underneath our to do list, anything that's, let's say, 1 week or 2 weeks old just kind of gets below the fold. There's a separate section, so your main to do list only shows you items that have been added or updated in the last week. So underneath that we're gonna have a new section.
Lazarus:The new section is going to be items that are just kind of old and I don't know what to call this exactly but you could call it like, you know, let's see, how about future or or out date now? We want to keep it kind of friendly, so these are things that are they're basically to do items that are rotting, you know, they're old, they may or may not happen, but we don't necessarily want to forget about them. Okay? So you can do some of the same things, but on this list your only real option, you're not going to be able to edit them or check them off or anything like that. The first thing you can do on this list it just sort of shows you all of them, or maybe it doesn't show you all, maybe you have to click to see them.
Lazarus:I think that's better actually. Okay, so we're gonna have a button that lets you click to see them. So that's just gonna be an so it'll show it'll tell you how many items there are. So let's say like 20, you know, 21 future items or something like that, and you can click to see all. That see all is gonna have an hx get, will have a div right there, and it will that will pull in, will find all the tasks that have a created at greater than a week, that are created at or an updated actually, let's just go with updated at.
Lazarus:So because if if you've changed something or edited something, you want to keep it at the top of the to do list. That means it's still active. So we'll look at the updated at, and anything that has not been updated in less than a week we are going to put underneath below the fold. So when you click it it pulls all those in and it just shows them in a list by their names. There's only one button on there and that one button, we don't have the edit, we don't have the check off or anything like that, next to each item we have a button that you click to bring it back to the active list and all that does is goes and it changes the updated time to right now, right?
Lazarus:Okay? So we have the updated time is what we're looking at on our main to do list to see whether it's active or not. It has to be active and updated within the last week or maybe 2 weeks. Okay? Because we don't want things to just disappear too quickly.
Lazarus:But we now have this idea of a to do list that is current and relevant and you can add stuff to this, you know, we could have like a category or a project or something like that, but I really don't think that's necessary. You know, so like hx or f s or cf or a h, you know, these are just like you can put them in caps just so you can quickly look at it and know exactly which project it's part of that you're working on. But then you've got the task, you've got the details, and this list can be your sort of central place for this week. What do I need to do? What's relevant to me?
Lazarus:You add it right in the beginning and then what's relevant to me? You can see that whole list. There's nothing on there that's stale. There's nothing on but you can always go look and you can see what are the things that I've forgotten about. As soon as you get an item, you add it to the list, even if it doesn't need to be done for a while.
Lazarus:Then you can go through your stale list. In the stale list you'll see all those items that maybe you need to bring back. Maybe they should be there, maybe you need to continue working on those, but you have that list forever of things that you might work on in the future. Okay? Alright.
Lazarus:So this live coding from my brain without a computer, didn't end up using a ton of h t m x but it only used h t m x. I don't know if it would all go down exactly as I sort of laid it out here. So this is just a bit of an experiment to see, kind of, what it's like doing this kind of live coding. Kind of, imagining how an app would go, seeing if I have the mental model, you know, of this sort of HTMX setup for my to do app. This was fun to try though.
Lazarus:I hope it was, I hope it was fun for you guys to listen to if you made it through. And I highly encourage you to build your own to do app. It might look nothing like my to do app. It might have a lot of different stuff in it that you need, but I do think that as a developer, it's something you can do. Just build it with whatever cool tech you're learning right now.
Lazarus:To do apps are so simple, you'll get a huge benefit from having a specific to do app that's built for your way of working, even if you have to use it some other system for some other project or something like that. When you get to do stuff for yourself and when you get to use your own to do app, there's just a benefit in general, a productivity benefit, and you also just learn something while you're building it. So, anyway, I highly recommend. Have a good day.