Filtering A Query By Pattern Likeness
In this lesson, we'll learn how to add a pattern filter to our movies.index page that will allow us to filter our movies list by title using a case-insensitive pattern search.
- Author
- Tom Gobich
- Published
- Apr 27
- Duration
- 7m 9s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
Filtering A Query By Pattern Likeness
-
[MUSIC]
-
The first filter we're going to add is the ability to
-
search by the titles like this.
-
We're going to add a text box right up
-
here that will allow us to type something in.
-
Since we're just working with basic forms in the page,
-
we'll need to do a full refresh.
-
We'll add in a Submit button here as well.
-
Let's hide our browser away.
-
Let's get our form added.
-
Our method here is going to be Get,
-
so that whenever we submit this form,
-
it just adds in the fields and
-
their values as query strings for us.
-
Then we'll have our action.
-
We'll do routeMovies.index to
-
point that to the same page that we're presently on.
-
Since this will be a Get,
-
we should not need our CSRF field.
-
That's just for four methods that are posting data up,
-
whereas this Get will be adding to the query string.
-
That just leaves us with needing our inputs.
-
We'll do a div class.
-
Let's flex and maybe add a gap of three.
-
Then we just need our form input component to add in our input.
-
We'll add in a label.
-
Let's call this our title search.
-
We'll have the name for the input,
-
just be search, and then the type for
-
the input we'll have as search as well.
-
Once we have that, let's add our button in.
-
We'll do addButton.
-
The type for the button will be submit,
-
so that whenever we click on it,
-
it auto-submits our form.
-
We'll call the button textSearch,
-
and let's add that button.
-
Let's also do itemsBaseline there,
-
because we have a label here,
-
but our button won't.
-
Presently with how we have this,
-
if we submit this form,
-
it should almost just redirect
-
us back to the page that we're currently on.
-
I guess we need to do end,
-
to hide that away real quick,
-
and switch that from itemsBaseline to itemsEnd.
-
There we go. That looks a little bit better.
-
Do need some spacing, but let's give this a test first.
-
If we type something out,
-
like maybe angry,
-
I see right down there in the first one,
-
hit "Search" here.
-
We can see that it adds in our search
-
equals angry within our query string,
-
and it essentially just refreshed our page,
-
because we're not actually doing
-
anything with the queried results.
-
We do know that at least our form's
-
working and it's behaving as we intend,
-
which leaves us with the next thing that we need to do,
-
taking care of that search equals angry,
-
to actually filter down our movies
-
to just those that contain angry within the title.
-
Let's go ahead and hide our browser away.
-
While we're thinking about it, let's add
-
a padding top of maybe four to our div there,
-
and then let's jump into our movies controller,
-
where we're now going to need
-
our request so that we can
-
grab that query string information.
-
We'll do const qs for query string equals request.qs,
-
which will give us back a record where the key is
-
the query string key and the value is the query string value.
-
For this, we can use a utility that's on
-
the model query builder called if,
-
that allows us to pass in a condition that
-
resolves back in either a truthy or falsy value,
-
and then we can provide in up to two callback methods.
-
The first one is going to be the truthy condition handler.
-
So if the condition that we provide in comes back truthy,
-
it will move forward with that first callback function
-
that we provide in, and if
-
the condition that we provide in is falsy,
-
it will skip the first one,
-
not execute it, and jump straight to executing
-
just the second one which is the falsy condition callback.
-
So let's put this into practice.
-
So if we have a query string.search field,
-
we don't really want to do anything if this is falsy,
-
we just want to apply the search value
-
to the query that we have if it's truthy.
-
So for that, we'll do query,
-
and this provides us the exact same query builder
-
that we're working with outside of this if method.
-
So we could do query.where
-
I like to do a case insensitive search.
-
The title is like our qs.search value.
-
Then if we wanted to do something if that were falsy,
-
we could do a comma there and do
-
the exact same thing with another query builder
-
just like we are with our truthy value.
-
That in turn works just like an if.
-
So if qs.search,
-
then do something else, do something else.
-
Where this is the first callback and the else is the second.
-
Then since this is a likeness search,
-
we're going to want percent signs on
-
both sides of the search field that we're actually adding in.
-
So add back ticks around our search here,
-
inject our search value into the value,
-
and add a percent sign on both the start and the end.
-
So with that if in place now,
-
if we jump back into our browser,
-
we already have a query string value here from
-
our previous search submission searching for angry.
-
So if we give this a refresh,
-
we should see just movies that have angry within the title,
-
which appears to just be one.
-
If we expand this a little bit to just movies with one in the title,
-
hit "Enter" there to submit that,
-
we get back a number of different movies,
-
each containing one in some way or fashion in the title.
-
Now we need to populate that one or
-
whatever our search value is back into our title search.
-
So let's hide this away once more.
-
There's a few different ways that we can actually do this.
-
So we can jump straight into our index page and set
-
the value here to request.qs.search, just like so.
-
That should grab the value off of the query string if we have one,
-
provided it has the value and the way that we have our components set up there.
-
If the query string doesn't have a value for search,
-
and that comes back as undefined,
-
then it will just default to an empty string.
-
But we can see here, we jump back into our browser,
-
it set our value to one.
-
If we switch this back to angry, it's now angry.
-
So it's populated in there okay,
-
and if we get rid of it altogether,
-
it's defaulting to an empty string.
-
I do want to take a note on one alternative way that you could write that query.
-
So within our movies controller here,
-
the query builder doesn't actually execute until you await it.
-
Meaning, we could get rid of this await,
-
call this our movies query,
-
and let's just comment out our if statement for right now.
-
If we take a look at the return type now for our movies query,
-
it's now of type model query builder contract,
-
type of our movie model, movie model.
-
Meaning, if we add in a couple of lines here,
-
we can now do movies query dot and expand whatever we need to off of it.
-
So we could do an actual if statement searching for query string search,
-
and if we have a value,
-
then we could do movies query dot where I like title,
-
and then I'm just going to come up here,
-
copy that value real quick,
-
and paste that in place.
-
Now, we still haven't awaited our actual query,
-
so we haven't executed it yet.
-
Meaning, we can now do const movies equals await movies query,
-
and now we have executed that query,
-
and we'll get back our movie results within our movies.
-
So if we give that a save,
-
just jump back into our browser,
-
give it a quick refresh,
-
comes back with everything as expected,
-
but we don't have a filter applied.
-
Let's go ahead and apply our filter.
-
So we'll just search for one here,
-
give it a run, and there we go.
-
You can see it applied successfully,
-
and we now only get back movies with one in the title in some fashion.
-
Type in angry, and it will do the exact same.
-
So it's working the exact same as it
-
was while we were just using that direct if statement.
-
So if you happen to have more complex filters that you need to apply in,
-
this is a perfect option for you.
-
In our case, our filters are rather straightforward.
-
So we can go ahead and just step back a couple of steps,
-
and apply the if directly into our query,
-
so that we have it just within this one statement here.
-
As for alternative ways that we can populate
-
the actual default value for our form fields,
-
well, we're already grabbing the query string here.
-
So we could just provide that directly into the page state,
-
so that we don't have to call that method
-
every single time that we want to populate a value.
-
We could call that something like our filters.
-
So we can jump down into our index page.
-
Instead of doing request.queryString,
-
we can do filters.search,
-
and that should behave the exact same as it was before.
-
It's just now that query string is coming directly from our route handler.
-
Query string values are also available via the input on the request.
-
It considers those an input type.
-
So we could use our request once more,
-
and use the input method to grab just the search input from the query string.
-
We give that a save, jump back into our browser,
-
did a refresh already, but we could do once more for sanity sake,
-
and it's still populating there, okay.
-
Either one of those works just fine.
-
I think for now, we'll go ahead and keep with just the filters.search approach,
-
providing so that if we need to normalize this in any way,
-
we have the ability to do that directly from our route handler.
-
Introduction
-
Fundamentals
-
2.0Routes and How To Create Them5m 23s
-
2.1Rendering a View for a Route6m 29s
-
2.2Linking Between Routes7m 51s
-
2.3Loading A Movie Using Route Parameters9m 17s
-
2.4Validating Route Parameters6m 6s
-
2.5Vite and Our Assets6m 38s
-
2.6Setting Up Tailwind CSS9m 5s
-
2.7Reading and Supporting Markdown Content4m 32s
-
2.8Listing Movies from their Markdown Files8m 51s
-
2.9Extracting Reusable Code with Services7m 4s
-
2.10Cleaning Up Routes with Controllers4m 52s
-
2.11Defining A Structure for our Movie using Models9m 38s
-
2.12Singleton Services and the Idea of Caching6m 11s
-
2.13Environment Variables and their Validation4m 16s
-
2.14Improved Caching with Redis10m 44s
-
2.15Deleting Items and Flushing our Redis Cache6m 46s
-
2.16Quick Start Apps with Custom Starter Kits6m 28s
-
2.17Easy Imports with NodeJS Subpath Imports8m 40s
-
-
Building Views with EdgeJS
-
3.0EdgeJS Templating Basics8m 49s
-
3.1HTML Attribute and Class Utilities6m 9s
-
3.2Making A Reusable Movie Card Component10m 24s
-
3.3Component Tags, State, and Props4m 53s
-
3.4Use Slots To Make A Button Component6m 56s
-
3.5Extracting A Layout Component5m 13s
-
3.6State vs Share Data Flow2m 59s
-
3.7Share vs Global Data Flow6m 7s
-
3.8Form Basics and CSRF Protection6m 13s
-
3.9HTTP Method Spoofing HTML Forms3m 3s
-
3.10Easy SVG Icons with Edge Iconify7m 57s
-
-
Database and Lucid ORM Basics
-
4.0Configuring Lucid and our Database Connection4m 3s
-
4.1Understanding our Database Schema9m 35s
-
4.2Introducing and Defining Database Migrations18m 35s
-
4.3The Flow of Migrations8m 28s
-
4.4Introducing Lucid Models5m 43s
-
4.5Defining Our Models6m 49s
-
4.6The Basics of CRUD11m 56s
-
4.7Defining Required Data with Seeders11m 11s
-
4.8Stubbing Fake Data with Model Factories13m 48s
-
4.9Querying Our Movies with the Query Builder15m 30s
-
4.10Unmapped and Computed Model Properties3m 24s
-
4.11Altering Tables with Migrations7m 6s
-
4.12Adding A Profile Model, Migration, Factory, and Controller2m 57s
-
4.13SQL Parameters and Injection Protection9m 19s
-
4.14Reusable Query Statements with Model Query Scopes8m 11s
-
4.15Tapping into Model Factory States9m 15s
-
4.16Querying Recently Released and Coming Soon Movies4m 59s
-
4.17Generating A Unique Movie Slug With Model Hooks7m 59s
-
-
Lucid ORM Relationships
-
5.0Defining One to One Relationships Within Lucid Models5m 49s
-
5.1Model Factory Relationships2m 54s
-
5.2Querying Relationships and Eager Vs Lazy Loading5m 17s
-
5.3Cascading and Deleting Model Relationships5m 16s
-
5.4Defining One to Many Relationships with Lucid Models6m 56s
-
5.5Seeding Movies with One to Many Model Factory Relationships5m 24s
-
5.6Listing A Director's Movies with Relationship Existence Queries8m 41s
-
5.7Listing and Counting a Writer's Movies8m 41s
-
5.8Using Eager and Lazy Loading to Load A Movie's Writer and Director5m 18s
-
5.9Defining Many-To-Many Relationships and Pivot Columns9m 48s
-
5.10Many-To-Many Model Factory Relationships4m 50s
-
5.11A Deep Dive Into Relationship CRUD with Models18m 5s
-
5.12How To Create Factory Relationships from a Pool of Data13m 55s
-
5.13How To Query, Sort, and Filter by Pivot Table Data9m 47s
-
-
Working With Forms
-
6.0Accepting Form Data12m 15s
-
6.1Validating Form Data with VineJS9m 29s
-
6.2Displaying Validation Errors and Validating from our Request7m 16s
-
6.3Reusing Old Form Values After A Validation Error2m 3s
-
6.4Creating An EdgeJS Form Input Component5m 28s
-
6.5Creating A Login Form and Validator5m 1s
-
6.6How To Create A Custom VineJS Validation Rule9m 7s
-
-
Authentication & Middleware
-
7.0The Flow of Middleware7m 49s
-
7.1Authenticating A Newly Registered User4m 14s
-
7.2Checking For and Populating an Authenticated User2m 10s
-
7.3Logging Out An Authenticated User2m 24s
-
7.4Logging In An Existing User6m 54s
-
7.5Remembering A User's Authenticated Session6m 55s
-
7.6Protecting Routes with Auth, Guest, and Admin Middleware5m 36s
-
-
Filtering and Paginating Queries
-
8.0Creating A Movie List Page3m 43s
-
8.1Filtering A Query By Pattern Likeness7m 9s
-
8.2Filtering Our List by Movie Status5m 47s
-
8.3How To Apply A Dynamic Sort Filter To Your Query7m 12s
-
8.4Joining SQL Tables To Order By A Related Column4m 49s
-
Validating Query String Filter Values7m 23s
-
How To Paginate Filtered Query Results9m 15s
-
Pagination First, Last, Next, and Previous Buttons4m 2s
-
-
User Watchlist
-
An Alternative Approach to Many-To-Many Relationships4m 56s
-
Toggling A Movie in an Authenticated User's Watchlist9m 56s
-
Listing and Filtering User Watchlist Items7m 34s
-
Allowing Users To Toggle A Movie As Watched4m 44s
-
Filtering By User's Watched Status6m 7s
-
Defining A Composite Unique Constraint4m 46s
-
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!