[MUSIC] Hi, my name is ThePrimeagen. I am a senior software engineer at
Netflix, husband to a beautiful wife and a father of four. The reason why I created the introduction
to HTMX is it's one of the few technologies I'm very excited about and I
believe it has a long future ahead of it. In this course, we go over each of
the basic annotations of HTML and then after that we go over some advanced
patterns that make developing apps easy. First thing is HATEOAS. You've probably seen this term,
heard this term. It stands for Hypermedia As The Engine
of Application State, meaning the state of your HTML is the
state of your program and that is how we drive the changes further on down
the line is what is currently there. In the modern world, we don't do that. What we do in the modern world
is that we have the virtual DOM, usually contains the state
of your program. Then you have a secondary state,
which is all the closures and things within your JavaScript. The use states, all the little bits that
are going to update that virtual DOM, that's your second layer of state. Then typically if you're more enterprise,
you'll have a third layer state, which is your Redux state,
which is controlling your routes. It could be controlling how you're
getting data, async, reducers, selectors, all that fun stuff to just
simply drive the engine of state. And so in the HTMX world,
we try to make it simple, the hypermedia, the HTML, that's the engine of
the engine of application state, not all the other things,
all the other layers. It's your server as the truth. Your client is
the reflection of the truth. And there's little in between. Now you can go as much as you want. I've seen projects where they use HTMX for
all the chrome and all the stuff around the application and they use React inside
of it to drive all the user interactions. Totally reasonable, you can emit events
from within a React application and have HTMX actually run on the outside and
do all the updating and executing on the outside. So totally okay. Does that mean HTML is finally
a programming yet language, yes. Does that mean you're finally
an HTML engineer, absolutely. What a great day to be alive. Finally, also, this is a 2011 nice
little document which you should read. This is by the current
community manager of Rust, and he has a whole talk about how to do
HATEOAS and all this stuff even in 2011. Again, this concept's been around for
quite some time, this is not something new. It just feels new because some unhinged
Montana man has now made it popular. And by the way,
I'm not the unhinged Montana man. All right, so let's do this. Hopefully I have the exact link,
yes, I do, fantastic. So typically, this is kind of like
your standard server interaction. I do a get at the root and the server responds with some HTML
that has links off to JavaScript. Maybe it's not a server
that actually does it. Maybe it's like a CDN in front
of the server, whatever happens. Something happens and
you get HTML back, right? And so, typically, we're going to be
doing something like this with HTMX. Any element may have some sort of hx-VERB. That VERB will have a path. We will make a VERB request to that path. It will hit the server. The server's expectation
is to respond with HTML. The contents of the HTML will
replace the inner HTML of the element that made or
that initiated the request. And that is only if it
responds with a 200. So if you respond with a 400,
a 500, or whatever, you now have to define some
sort of custom behavior. HTMX just says, no, we're not gonna
do anything in the 4 to 500s. So, that means if we had a div that
posted to foo, and it had the contents of four green squares, and
the server responds with two blue squares, the final state will
look something like this. The div will now have two blue squares. HTMX does emit a lot of events. So you can hook in with JavaScript
if you want to add custom behavior. It can react on a lot of different things,
including custom events. It has ways to reduce
HTML from the request so you don't actually get the entire request. You can just select out parts you want. And it also has ways to redirect to the
HTML to other parts of your application. So this is all a part of it. And you can even redirect from the server
or you can redirect from the client. You can make the choice yourself,
depending on where and how you do it. All right, so pretty fantastic. Hopefully everyone, that's it. I just taught you pretty
much all of HTMX right now. So we're gonna kind of go through some
exercises and put this into practice. I just really want you to
see this image right here. This I think is the best
image to understand HTMX. It starts with some green
squares inside of it. You make a request,
server responds with blue squares. Now you have blue squares
inside of that same div. The div was not removed,
the insides were removed. So there we go.
We have this nice little post. When we make a post,
this is what happens to our context page. This kind of sucks. Can we all agree that this sucks? This is not what I want to see at all,
right? This is not it. This is not it at any of it. In fact, this is horrible. And if I keep on adding, it'll just keep
on getting worse and worse and worse and worse and look at that thing go. It's just awful, right? So this isn't beautiful. I bet you though, that a lot of
people can now guess what happened. What happened? >> I have no idea. >> You have no idea but
we have already solved this problem. >> We're not targeting the div. >> Say it out loud, come on. >> We're not targeting the div. >> Yeah,
we're not targeting the right content. I love it. I know, right, John? >> Yes.
>> I knew you were gonna get it correct. I could feel it. You were ready. You were just there. All right, so yeah that's exactly it. Look at our response. We're responding with
the whole darn thing. And what is it doing? Who made the request in this situation? The form made the request. So therefore the form gets replaced. I mean, if we go to the HTML,
we might see that our form has a form, that has a form, that has a form,
that has a form. Our forms had babies. Look at that. Look at how many it had. So we did something wrong here, right? We're need to start targeting and thinking
about how are we gonna update this page. And this is actually quite
an interesting problem. We're gonna get to the problem of form and
display all in one page. Let's see, I don't know what it says. Yeah, so let's fix this problem. So this is the same problem as before. We're returning the whole thing. So first and obvious and
easiest thing we can do if you're lazy and you just want to get a product out there,
just hit it with the old hx-target = body. My goodness, fantastic. I'm refreshing the page. Did you see how fast that compiles? My goodness. It's just like it's
the easiest thing ever. Look at that. We're just adding stuff, it's updating,
not a big deal, super, super simple. By the way, I just love how fast that,
the compilation is just so good. All right, is this good? What are some problems with this approach? Can someone give me a problem with
what we're doing right now, John? >> Are we sending the full HTML? >> We're sending all the contacts and
everything. >> The payload get bigger,
the more trips that happen. >> Yes, so if you couldn't hear it,
the payload keeps getting ever bigger. Meaning if you had a 1,000 contacts, we have to send down 1,000 contacts plus
a form every single time you add one. That's a horrible problem to be in,
we don't wanna be there. So we're gonna explore the space,
just a little bit, okay? We're just gonna get in there, we're gonna see what happens because
this seems kind of exciting. Yes, I know some people are suggesting
the fix being Rust, 1,000 contacts, not a big deal with Rust, right? It's still a problem. Trust me, this is a problem. Let's not do that. So let's first start by only
responding with contacts. That should be a pretty
easy reduction of stuff. So let's jump back in here and
we need to change two things. We need to change, who are we targeting
and then the code that's being generated. So I'm gonna go like this, hx-target,
and let's go down here and call this thing id = contacts, right? And then we're gonna jump back here and
we're gonna go #contacts. All right, awesome. So now that we have that,
that should do all the redirecting. So now we're gonna go over to
the server and we need to say, hey, don't render the index,
render the context, right? Or wait, I think I call it display. Did I call it display? Yeah, I called it display. Terrible name, but you get the idea. Okay, awesome. We are gonna do that. So I'm going to refresh this. And let's add a contact. Okay, I mean, that's better, right? We're getting better. I'm gonna just keep on. Look, I'm just creating so
many sweet contacts. Is this better? In some sense it's better, but let's take a little gander
at what's happening inside. Look at what happened here, we were
having multiple levels of contacts. Why is that? Can anyone tell me why we're having
multiple levels of contacts? >> InnerHTML. >> InnerHTML, boom. Did you know HTMX you can say
how you want to replace it. So let's just jump up here and
let's do a little hx-swap = outerHTML. So instead of replacing
the inner contents, let's replace the entire element here for
a second. So let's at least fix that problem. So I'm gonna do that. And boom as we added a bunch, notice
that we no longer have that problem. So we can kind of specify how we
wish to swap out the elements, which is a pretty cool little items. So for those that didn't see
it on the form, I did hx-swap. And so
this is just how you dynamically say, this is how we want to change things out. Pretty cool, pretty great. Very happy about that. I'm happy, you're happy,
hopefully let's keep being happy together. So now we have this
delicious icon right here. Next, we need to make a do a delete
to the icons id, or I mean, well, we need to make it do
a request to contacts id. Obviously, you probably go we
don't have ids for contacts. Well, we're gonna have to make one, okay? We have to make one now. All right, so let's go hx-delete. This delete attribute call will cause
an element to issue a delete request. Okay, fantastic. Let's absolutely do that. And let's go to contacts. And then we'll do a /.id. Yeah, look at that. Looks good, right? It's looking good.
This is feeling good. And then I'm gonna also do a little
id up here and call this contact. And then we're gonna
put an id on this one. This is for
a future problem that we will see. We'll get there,
don't worry about it, it's okay. So we have this nice delete. So now how do we say what to delete? Because if I just issue this request and
we successfully delete, what is HTMX gonna remove? >> It should remove the HTML
connected to that contact. >> It will remove, currently,
the savage inside of this div, right? Because it always the default
behavior is swap innerHTML. So we need to have a different
swap potential strategy. So let's first have hx-swap = "outerHTML". So now we will delete this div, but
we're still only deleting the trash can. So we need to do something
a little bit different. Let's also add in hx-target =, so normally if you can you can use
something called closest which is a CSS which does a selector upwards and
will check your ancestor. So technically you could do something
like this except for I am a div myself therefore closest will also consider
yourself as part of the selector thing that's just welcome to Web 3 delicious
standards here, very annoying. I wish it just did parent and
beyond because that'd be super useful. Cuz I could just say, hey, delete my
parent div and it would just boom. And it would work. So we can't do that. So I'll just go like this. Contact, do you like how it does
that little shift every time? I don't know what that is. There we go. So fantastic. So now we're saying, hey, who to delete? How to delete it? What end point to get to go to? I think we're effectively ready. Let's do a little refresh. It says internal error. Why does it say an internal error? Anybody, anyone wanna make a guess? >> No id.
>> No id, bam. Gosh, this guy, it's like you program Go. It's just like you know,
you know it, you could feel it. All right, so I'm gonna go up
to my little contact form and I'm just gonna go var id = 0. Why not? This is why, by the way, if you're
wondering why I did a little new contact here, it's like I was pre-prepared for
this eventuality we're having right here. So there we go. Okay, there we go. Everything's been specified. We're looking good. Fantastic, I don't think I
technically need this one. Yeah, I don't even need it. All right, so there we go. Awesome, so
now we have an Id on the contact forms, which means every single time we create
a contact, it will come with an Id. Which is also why I use
these functions right here. So now even our dummy data,
we have Ids, we're feeling good, everything's looking good. We go back here, we hit refresh,
everything's there. Let's look at the HTML just to validate
that we have actually done the thing. Let's bring it down, look at that. We have contact 1 reflecting on the kids. This thing is saying, hey,
target contact 1 swap outerHTML. So if I click it,
let's bring up the old network and I click that look at what happened. It said, hey, that's not found, why not? Well, we did a 404 because
there's nothing there. We haven't added the handler yet,
but it did the right thing. It went to contact/1 and
issued a delete request. It's like proper. We're just so proper at this point. So let's do an e.DELETE/contacts/:id,
fantastic. Let's get the id string equals that. I'll do id and err equals stir convert. I mean, maybe I could have done
something better here, but I didn't do something better here. Throw in one of those. If we hit that, I'm just gonna
return a e.String(400, right? Is that no, it's C, sorry, C.String. So we're gonna go all the way
back up to the data and let's add in one more function. Function d Data, let's go indexOf this. And we'll do, let' see,
what do we wanna do? We want to do id, right? So there we go, so
we're just gonna return out the contact. I mean, we could make it nice like that. And copilot will pretty much do it for us. All right, awesome. And we don't wanna do that, actually,
we wanna do it indexOf, don't we? Let's return out the index
that was found here. Or -1, I guess we can do the other way. I'm not sure why I did an index 1. Why did I do an index 1? Did I do it? Do I have a good reason for it? I don't think I have a good reason for it. Index 1, it's just in my head,
that's what I was doing. So we're gonna keep on doing
the thing I already built. And we could actually do, yeah,
we could have just used the nil as that. Else, we need to simply delete out this. That's why I did that. That's why I had to delete it out. That's the thing we got to do. And I knew it and so
let's just do the little deletion here. All right, fantastic. Let's just make sure this is good. We're gonna have page up to index and then
we're gonna start from index +1 and on. Okay, awesome. We've now created this wonderful contacts
right here or we've updated our contacts. Now we need to return something from
this deletion, which of course, C.NoContent (200), right? We're just gonna return an empty reply. You got it. So I'm gonna refresh this and
when I hit delete, it's gone. Look at that inline deleting,
refresh, nothing is there. Hit the save on the server, we're back. We just rehydrated the data, okay. [MUSIC]