Now that we achieved this state
of this application,
there's one last feature,
which I wanna explore, which you will also see
on a lot of websites
and which chances are high,
you will also need as a web developer
when building a lot of websites.
And that would be query parameters.
Now, what are query parameters?
To give you a good example,
let's assume that here on this Browse Restaurants page,
we actually want to be able to sort these restaurants.
I wanna have a button you could say
that sorts the restaurants in ascending
or descending mode,
let's say based on their title.
At the moment, of course,
we don't really sort our restaurants.
Instead, when we get all these restaurants,
we simply get them in the order
in which they are stored in our data file.
So here in restaurant-data.js where I fetch the restaurants,
I simply read them from the file
and I return them like this,
and whilst that, of course, works,
we might want to sort them.
So therefore, let's start by sorting them as a default
before we then add a button
before I then, as a last step,
dive into that query parameters feature.
So to sort restaurants,
back in my restaurants.js routes file,
after I've fetched the restaurants,
before I actually hand them off to my template,
I wanna sort them.
And for this, to sort data,
JavaScript has a sort method,
which we can execute on an array of data
and storedRestaurants turns out to be such an array.
Now, this sort method tries to sort the data automatically.
For example, it is able to sort numbers
without any issues
but for more complex data,
like here an array of restaurant objects,
you instead need to pass a function to sort
that will be executed for every restaurant,
and which then will return -1 or 1,
depending on whether two compared restaurants
should change their order or not.
It's a little bit more advanced,
so I'll just show you the code, which we need here
and then I'll explain what this code does.
So we add a function here,
an anonymous function, which I just add here
inside of sort since I only need it here
as a parameter value to sort to be precise.
And this anonymous function
will receive two parameters always automatically
because sort, when we execute this
is in the end executed by the browser,
and the browser will execute this function,
which we pass to sort
for every pair of restaurants,
which the browser compares
to find out how they should be ordered.
So function here will always receive two parameters
because the browser will pass in two parameters.
And we'll always get a pair of restaurants here.
Here I will name them resA and resB
and that stands for the first and the second restaurant,
and all the restaurants will be compared with each other,
step by step by that sort method in the end.
And in here, we can then write our own logic
to determine which restaurant should win.
Now, for this, if we have a look our restaurant data,
it is, of course, worth noting that in the end.
A restaurant, if I restructure this here
so that it's a bit more readable,
has a much of fields that we could use for sorting.
But I actually will sort on the name here.
So I wanna sort on the name
and we sort alphabetically or we flip that
so that we start with the last character in the alphabet.
But as a default, I wanna sort alphabetically.
And for this here, we can check if resA.name,
accessing that name field in that single restaurant object,
if that is greater than resB.name.
If that's the case,
I wanna return one,
else if we make it past this if check, I'll return -1.
If I return one here,
so a value greater zero to be precise,
then the two items will be flipped,
so the second item, resB will be sorted in front of resA,
so they will swap the order.
If I return -1, so a value smaller zero,
then the opposite will be the case.
So then we will not flip these items.
Instead, they will keep their existing order
and resA will stay in front of resB.
That's simply how that sort method works internally.
Now, this might look very cryptic
but let's see what this does.
If I save that,
and I go back and reload now,
you see it is ordered such
that Munich Fines Restaurant comes first.
And I see that it's Fines, not Finest,
which is, of course, a typo,
but let's ignore that.
But what we can see is that this comes first
because M comes before R in the alphabet
and R comes before T.
Now, here we have the same start of the word
but then Test comes first
because it's simply shorter than Test 2.
So this is now the default order we have here,
and this is achieved by this function
being executed automatically by the browser
because we called sort here,
and it will receive two restaurants multiple times,
comparing all the restaurants,
and then we write our own logic
that we wanna compare the names of the restaurants,
and by returning 1 and -1,
we, in the end, tell the browser if the restaurants
that are compared should change their position,
if they should swap their position in the array
or if they shouldn't.
And you can play around with that
and return -1 here and 1 here
to see how results differ
or play around with that condition.
Now, it's a bit more advanced here
and we'll dive deeper into advanced JavaScript later,
but for the moment, it's hopefully clear
that here we are sorting restaurants alphabetically
by their name.
But that was just a start
because now I wanna make sure
that we can actually change that order
by actually having a button here, which we can press.
And for that, of course, we need to go into our template.
So into our views folder
and there, it's the restaurants.ejs file.
Here we have all our restaurants,
our list of restaurants,
and above that list of restaurants here,
so maybe above the unordered list
but below the paragraph,
I'll add a button
where I wanna say Change Order.
Now, if we save that and we reload,
we get that Change Order button here.
Now, this button also should be styled,
and to achieve this,
I'll give it a class, a CSS class of btn.
And we can then add some styling for that
by going to the public folder, our styles
and then restaurants.css.
And here, of course, we already got a bunch of styles,
and I just wanna also use the styles,
which I used on my links here.
So I will apply that on the existing CSS selector,
but then with a comma,
I also add another selector, the btn class selector
so that we use these styles for all the elements
that have a btn class as well.
Now I'll just also add cursor: pointer here,
and add a border of none
to override the default button styles.
And then down here,
I also wanna use that styling when we hover,
so I'll add btn:hover.
If we change all of that, and reload,
now we've got this button here.
Now, of course, clicking that button
doesn't do anything yet.
And that's now the part where we will use query parameters.
I will actually go back to the view here
to the restaurants.ejs file,
and wrap this button into a form,
which is, of course, something we did before
in the course already.
Now, since this is the only button in the form
and we didn't set any other type to that button,
it will automatically, by default, submit that form.
Now that form here, though
doesn't have any data that would be submitted
and therefore, I will add some.
I'll add a input field here,
and this will have a special type.
The type will be hidden
because here I don't wanna have a input field
where the user is able to enter something.
Instead here, I wanna have a pre-defined value,
which I as a developer define.
And hence, I'll set the value attribute to achieve this.
Now, we haven't seen this attribute before
but we can use that to assign a value to input.
Very often, you don't wanna do that
because you wanna let your users enter a value
but here I do wanna do that.
And I'll set this to asc for ascending.
I will later show you how we can change that dynamically
but for the moment, let's hard code asc here,
and give this input a name of order.
Name is up to you but order is quite fitting.
And then here, on that form,
we have to define our action, and our method.
And for action, I now wanna use /restaurants
because I basically just wanna reload the page
on which I already am.
I wanna reload this /restaurants page
on which I am already.
But, and that's now the special thing,
for method, I will not use POST
as we typically do for submitting data,
but instead GET
because whilst it is true that we typically do use POST
for forms, especially if we are dealing
with user-entered data,
here we have kind of a special case.
I'm not dealing with data entered by the user,
and I don't really wanna store data anywhere on the server.
And you typically do use the POST method
if you imply that data will be stored somewhere
in a database or in a file.
Here I don't wanna do that.
Instead, I wanna reload the page,
so get is a quite fitting choice for this method here
and I wanna reload this page
with slightly changed circumstances.
And now what I mean by circumstances
will become visible if you save that file.
And you then go back and reload
and you click on Change Order,
and watch that URL when you click it.
You see, the page did load.
It's the same as before.
But now we have this thing here in the URL, ?order=asc.
That's a so-called query parameter.
It's an extra optional value
that can be added to a URL
that won't change the page that's loaded typically
but instead that might be used on the server-side code
to change what's showing up on the page
or how things are displayed on the page.
And you can add any query parameter here.
If I add ?something=what and I hit Enter,
the page still loads correctly
because when it comes to determining
which route should be loaded,
so when it comes to going
through all these middleware functions
and through all these router functions,
then the query parameter is simply ignored.
We still make it into /restaurants
because the part after the question mark
and the question mark itself is ignored
when it comes to determining
which path is active and which route should be loaded.
And that's really important to keep in mind and understand.
But in the server-side code,
we can now access the query parameter value
and, for example, change the sorting based
on the query parameter value.
For this here in this get route
where I get all my sorted restaurants,
I can get my order,
you can name the constant however you want,
by using my request
and then there accessing .query.
That's a special field that exists
in this request object,
just as we had a body field on that request,
which is only populated if the route
was loaded through a post request though.
But query is always accessible
and that holds any query parameters we might have,
though keep in mind that in general,
those query parameters are always optional,
so you might not have any.
Now, here we could check if three is a order key
in that query object
because req.query will give you an object,
and it might be an empty object
if no query parameters were set
but it might also have an order key
if there is an query parameter
when this page is loaded,
when this route is loaded to be precise.
And therefore, we might have a value here.
Now, therefore, we might wanna actually make this a variable
by using let instead of const,
and then here we can check if order
is maybe not asc for ascending
and if order is maybe also not desc for descending,
if we assume that these are the two values
we would accept,
and in that case, we know it's not set,
at least not to one of our supported values,
and then we could set it to asc as a default.
That would be one way of handling this.
If it is set to asc or desc already, we keep that set value.
And then we can use that value here in our sorting logic
to change that logic
because here I can now check if order
is equal to asc,
and resA.name is greater than resB.name,
in which case I wanna return one here.
And otherwise, return -1.
But I actually also wanna add a else if case
and check if order is maybe equal to desc
and resB.name is greater than resA.name,
in which case, I also wanna return one.
And add some semicolons here.
Alternatively, we merge this all into one long condition,
and we grab this part here
and say if this is true,
or wrapping this with an extra pair of parentheses,
or if the condition I just cut is true,
then I wanna return one,
else we'll always return -1.
If we do that, we'll now take that order query parameter
into account to sort our restaurants differently based
on the value that's stored in that order query parameter.
So going back here, reloading this page,
if I click Change Order,
at the moment, nothing happens
because this always sets order equal to asc.
But not we can also pass the currently set order
into our template.
curOrder could be our key,
and we pass in the order,
so the order that's stored in this order variable.
And then our template,
we can then go to this form
and instead of always setting this to value
equals asc, we can inject a dynamic value here
as we learned it with EJS.
And check which value we currently have in curOrder
to know what our new order should be.
And therefore, instead of doing that,
I'll actually just add nextOrder here as a key,
and go back into restaurants.ejs
and instead of passing curOrder, pass next order.
And then just determine this dynamically.
For this, we can simply add a nextOrder variable here,
which by default is desc
since our default order is ascending.
But I add a if check
where I check if order is actually equal to desc,
so if it was descending,
then instead, the nextOrder should be ascending
so that we switch back to ascending.
And then we have this nextOrder variable,
which I'll pass as a value
into this nextOrder key,
which is exposed to the template
so that in the template, in this form,
we set the value of this hidden input
to that upcoming order,
which is the opposite of the current order.
If we currently are ordering in ascending mode,
then if we click the button,
we wanna switch to descending mode, and vice versa
because that's why the button says Change Order.
If we now save all these files and we reload,
now clicking this button toggles our ordering,
as you can see.
We switch the ordering of restaurants
because our query parameter in the URL changes
whenever I click the button as you can see,
and that is picked up in our route here
where we parse this query parameter
and then change our logic based on it.
And that was a quite long lecture on query parameters
but this can be a useful feature.
It's optional, as you learned.
You don't have to set a query parameter
but you can use query parameters,
especially for things like sorting or ordering.
So whenever you don't wanna change the entire page
that should be loaded but maybe parts of a page.
Now, it is worth noting
that we can still load this page just fine
without setting any query parameter
because it is optional
and hence, you should always write your code such
that you treat it as optional.
So here, for example, I have some fallback code
to set a default value in case the order query parameter
is not set.
You can also set more than one query parameter
by simply adding the ampersand symbol
after your first key-value pair here in the URL,
and then adding another query parameter if you want to.
Again, if you don't handle it, it's not doing anything,
but we could now also look for a something query parameter
in our code here to do something else.
It just depends on what your goals are
and what you wanna achieve.
And therefore, query parameters are the last feature
which I also wanted to introduce here.
We'll see them again later in some concrete examples
but it's now hopefully already clear
what they do and why we have them.