Chapter: Feature 2: Active search
Lecture: Searching as they type with htmx
0:00 So we've got this basic input field that we ask users to search by typing in Of course it does nothing yet because we haven't done our htmx
0:09 magic. Again, to do htmx, we do hx and then, what? The first thing we want to do is we want to do GET
0:20 and this is gonna be /videos/search and then we have to have an hx-trigger. What is going to cause this to happen and then gonna
0:30 be a key up changed delay 250. So let's break this apart key up is basically as they release the keys as they
0:38 type. So if we did just this that would totally work. But it would be very spastic. It would be every single keystroke would be going to
0:45 the server and results will be coming back and it would be totally crazy. Instead we're going to have changed and a delay.
0:55 The delay means you can type as much as you want, but it will only go
0:59 to the server if you stop for a quarter second between your typing that may be you've
1:04 only typed part of it and you're thinking and you'll see some results come in and
1:07 you'll type some more and the results will update or it could be you typed really
1:11 quick and then boom, the results show up but it won't every single keystroke start hammering the server and giving some weird experience.
1:19 The other one is not every keystroke actually results in different data being sent to the
1:25 server. So if I press the letter A and then letter B those keystrokes should have some kind of effect.
1:31 Right? I could have searched for absolute or whatever. However if I use the right arrow and the left arrow key that's not changing
1:39 the content of that text box. We don't want to rerun the same search over and over just because you're mousing around
1:46 or arrowing around inside there. So change means there has to both be a keyup and the result has to have changed the contents of the text box and it
1:55 has to wait for 250 milliseconds then rerun the search. And then the last thing is hx-target and here we put the CSS selector of
2:07 where the results go which is search/results that will do it. I think. It's going to do something really weird.
2:14 It's not gonna come out well, but it's gonna, I think it's going to do it.
2:19 Let's give it a try, refresh it here and now let me type something like apple.
2:25 That's weird, lool at that I could type inside myself it's like inception for search and so on. We could put indycar or whatever and now we're getting
2:37 the results and hear what in the world is this? Well remember we're going to this URL For the page,
2:45 the entire page right let's get rid of the search thing. It's not really participating. We go here and then we said our target, our
2:53 GET is /video/search. That's the same thing. How is this ever gonna work? Right. So if I put apple here, it's gonna say great, I went there,
3:04 the page that came back is the entire website and it jammed it in there.
3:09 So what we need to do is we need to differentiate between somebody coming like this and somebody coming there by through htmx.
3:18 Now you might say, we'll just make two views that are basically the same, but one returns a partial and one doesn't, we can do that and that's fine,
3:27 but we're also going to need to deal with this search_text=apple deep linking things. So we want to kind of process it in both places anyway,
3:36 so really what happens is it's identical code. The only different choice is what is being sent back.
3:43 We're going to need to change that over on the server, here. Now, when this request comes in directly from the browser,
3:52 it's just a standard old request, but when it comes in differently when it comes in from htmx, htmx says you might need to treat this separately,
4:03 you might need to treat it differently. To enable us to do that, they actually put a header in the request, so they put a header over and we
4:10 can check is this an htmx request? So we'll say something like if vm.is_htmx_request, which we don't have, then return something else.
4:24 Let's return something real simple. Like we'll just say how many videos there are for
4:28 the moment. That's not really helping them because we got to actually render them, but well we got to create some more HTML to make that happen. Now,
4:35 what about this? Let's go over here, and you might say, well let's put it into the search model, but we have this cool base class and
4:42 it's very likely other parts of our site in the future will also possibly need to make the same decision. So let's go down into here.
4:50 Well say something like this self.is_htmx_request. And then what we need to do is ask if there's a certain string in
4:59 flask.request.headers. We don't care what its value is. Just, is this header present? and that header text or the header keyword key is
5:09 HX-Request capitalized like this. So if htmx makes a request, it's going to also add this header to say,
5:18 hey, this is just coming from us in case you need to do something different than normal. So we're going to try to use that here. When a request comes
5:27 in like this, we're going to give them a different set of HTML. In this case, incredibly simple HTML rather than rendering the entire page back.
5:35 Let's try again. So we refresh this page come over here and let's just type apple. Oh, something has gone wrong,
5:47 ah we expected a dictionary, that's right because the way that this is set up we need to return something like this flask.make_response, there we go.
6:03 So we had to call flask.make_response. But you know, there are four videos. How about racing? How many videos are there on that?
6:12 How about indycar? two videos on indycar, Python? six videos on Python. Now we're not rendering the results, but we're doing the search
6:22 and we're sending it back actively. It does that delay and it does change, freeze the arrow keys.
6:27 Although I guess we can't really tell you would see the at least back here, you would see there are no more changes.
6:32 So you see those are not moving by but check it out down here, you can actually see the request coming in as a query string.
6:40 You see py, py, Python, all the stuff that's coming in indy, indycar, racing, racing, that's how it's communicating back to the server.
6:50 So it's exactly matching what we already set up here, and it's sending the header over
6:57 so we know to treat it differently and just send that little bit back and not do that crazy inception thing.
7:03 This is pretty awesome. We're super, super close, we just need a little more HTML to make this look real.