So as a next step,
let's make sure it is View Post button works
and takes us to the post detail page.
For this, we have to add a link to it
because at the moment,
this link doesn't have any actual link.
If we go to the post item EJS file,
it's this anchor element,
which doesn't have a value for the href attribute,
at least not a valid one.
And we of course have to add a fitting route
and then all the logic to that route.
Now let's maybe start with defining the link,
the path here to which you wanna link.
And that could be a slash posts
and then the ID of this specific post.
So that we actually will use a dynamic path, a dynamic URL,
which is a little bit different for the different posts,
having the different post IDs in it,
but generally of course, it's always the same structure.
So once we register our route,
we'll work with a dynamic route parameter
to store and grab that ID.
Here in the place where we define the path we wanna link to,
we of course, wanna use EJS here
to inject a dynamic value into our HTML code,
so that for every post item that's being output,
we generate a different link.
And we want to add the depost ID here with post.id.
This will ensure that the post ID is part of this path
and therefore if I go back after saving this
and I reload this page.
Now, if I hover over the you post in the bottom left corner,
I can see that this would lead to /posts/1
for the first post and /posts/2 for the second post.
So that's looking good.
Now we just need to make sure that we actually handle
those incoming requests on the server side
and that we return the appropriate template
or that we render the appropriate template.
And for this in our block.js routes file,
we wanna register a new route.
Now that we have all those existing routes,
it's time for a brand new one.
And here we want to handle a get request again,
because if we click a link, a get request will be sent
and we wanna target /posts/
and then the ID will be different for the different posts.
So that screams for a dynamic route with route parameters.
And you'll learn that we can implement this easily
with express by adding colon,
and then any identifier of our choice,
like post ID or just ID.
I'll go for just ID here, but this identifier is up to you.
Then the second value here, the second parameter again
is our function that will be executed for
an incoming request.
And in this function, we now of course,
wanna fetch the data for this specific post.
Again, also fetch the author data that belongs to it
because in the template which we will see in the render,
I also wanna show the name of the author
and use the email of the author,
and then of course, we wanna render the template.
Now let's start with rendering the template actually
for this, we can use res render
and the template I do want to render here
is post-detail.
So this post detail EJS file,
but of course we need some data
to regularly have a useful template being rendered.
And for this, we wanna again, construct a query
and since it will again, be a little bit of a longer query
or again, use a standalone constant, and then the back ticks
so that I can split my query across multiple lines.
Simply just for readability sake,
since this will also be a little bit of a longer query here.
Now that being said, let's start writing it.
Of course you wanna select some data.
We wanna fetch some data
and I wanna select everything from posts,
but of course not for all the posts.
I wanna fetch all the data, but not for all the posts.
Therefore we'll also need a WHERE clause,
because this route is about fetching the data
for a single post for a specific post.
And hence with a WHERE clause,
we can narrow down the amount of records we wanna fetch,
and we can also adjust the fetch one single post,
if we want to.
So with that, here we can add WHERE,
and we wanna fetch all the posts
where id is equal to one specific id,
which of course means that in the end
it will only be one post.
So here, then we wanna say WHERE id =
and I will again, add a question mark here as a placeholder,
because I wanna inject that ID dynamically
it will be the ID from my URL in the end.
That means that,
here if we wanna execute this with DB query
using the query method again,
we pass our query which we defined in the query constant
as a first parameter value.
And then as you learn it for inserting
it's all to the same for fetching data with select,
we can pass a second parameter value to query,
which is an array of all the values
that should be injected into our query string,
into our query command here.
So replacements for those question marks.
And here, I only have one question mark,
so I only need one value in this array.
And that one value here will be rec.params.id.
That's how we extract the concrete value
of that ID placeholder from the path
for which this route was loaded.
So here, if we visited the first post ID would be one,
for the second post, it would be two
and the value one or two would be extracted from the URL
and would then be passed as a value
instead of this question mark into tbis query string.
That's how this would work.
Now with that, however, of course we're not done yet.
This would fetch us to a single post, but as I mentioned,
I'm also interested in the author data.
Therefore we wanna join our posts
with the author data from the authors' table.
And hence we keep the WHERE clause here,
but before we add it,
since it has to come at the end, as you learned,
we add INNER JOIN and JOIN our authors table
ON posts.author_id being equal to authors.id.
And then here for the WHERE clause,
we can actually also change that to posts.id,
to make it clear that here we're looking for the ID
in the posts table, not the ID in the author's table.
And with that, we're joining in the authors data.
And now I also wanna change
the concrete columns I'm fetching.
I wanna get all the columns from posts,
but when it comes to the author data,
I wanna fetch authors.name
and give that alias off author_name
and separated by another comma.
I also wanna fetch the email,
but as the author_email.
Again, using these aliases is totally optional,
I'm just doing it here so that in the template later,
it will be clear which kind of data we're accessing there.
But with that, we're fetching the post data
and the merged in author data,
the name and the email to be precise.
And therefore that should do the trick.
As always, this is a asynchronous operation.
Running that query is an asynchronous operation
and hence we wanna use, async await here
to wait for that result like this.
And again, result is an array with two items.
The first item are our fetched records,
the second item is the metadata.
I'm not interested in the metadata,
but I'm interested in the first item.
And therefore, again, I use array de-structuring
to get my posts here.
And I deliberately named this posts instead of just post,
because even though we know it will only be one post
that meets this criteria,
technically it could be more than one
because it's just a select query with a WHERE clause.
So the MySQL package doesn't know ahead of time
that we'll only have one matching record here
and hence it will return us an array here,
which then just turns out to only hold one item.
But that's something we as a developer know
the package doesn't know it,
and hence you always get back an array here
and hence I name it posts,
because that makes it clear that this is an array of posts,
even though it will only hold one post.
Now here to my template,
I then wanna forward that one single post,
which I know I will have,
and that will simply be the first item
I find in this post array.
Because again, we know there will only be one item in there.
Technically though, we might not even have that one item
because of what if a user manually enters a URL
with an idea of a post that doesn't exist.
Then posts wouldn't have any posts at all.
So to handle that case that we don't get back any data,
I'll actually check if posts has maybe on the find
or if posts.length ===0,
which means we didn't find any posts
and then dad case, I don't wanna render this template here.
Instead in that case, I want to actually set my status code
on the response to 404 to signal a 404 not found error
and render my 404 template which I prepared.
And it will actually add a return keyword here
so that the code thereafter won't be executed.
That's also something
we discussed earlier in the course already.
Without return, this line would execute,
and this line would also still execute.
We could wrap it in an l statement alternatively,
but if we never do that, nor add a return statement here,
then this line line 51 would also execute
and we would basically try to send two responses,
which doesn't work.
So simply adding return here does a trick
and ensures that this code in line 51, doesn't execute
if this line executed already.
And with that,
we should handle the case that we did not find a post.
And alternatively,
we do render this template with data about this single post.
And therefore we cannot go to that template
and adjust what we output there.
In this template, it actually all starts here at the top
with the title of the post.
That's the title that's shown on the browser tab
and that would show up in search engines
and here, instead of having
this hard coded post title placeholder,
I wanna have to concrete posts title,
which we can here by simply accessing post.title.
Post because in block.js,
I'm setting this post key, which is exposed to the template.
Now, that's the first step.
I also wanna I would put the post title here
between the h1 tags
and if we're here, it's also post title, like that.
Now in this meta section,
I actually wanna output the author name and the date.
And that's maybe something you didn't do
if you try this on your own and that's absolutely fine,
but here I wanna show you
one possible way of outputting that extra metadata
in a clean way.
For the author name,
I'll use the special address, HTML element.
This is a standard HTML element,
which typically should be used
if you're outputting some address information.
And address does not just mean the address of a house
or anything like that,
but it could also be the email address,
often author of a block post.
So therefore address is great,
whenever you have contact details or anything like this,
and then for an address, I'll add a link
which should show the author name
and then automatically open the mail client
with an email to that author being composed.
And that can be achieved by adding mailto here,
this special keyword, if you wanna call it like this
and the then inserting the email address
to which emails should be composed.
This will not send it automatically,
it will just open the mail client.
So for this here, I then use EJS
to output posts.author_email author_email,
because that's the alias I assigned here
when we fetched that data.
And then here between the opening
and closing anchor elements, I wanna show the actual text,
the actual name of the author.
So for that here, we can access post.author_name,
author_name was another alias
I set up in my select statement.
So that's the first part, adding this address,
I'll then add a white space and then there's pipe symbol,
which is just a regular character on the keyboard.
And then below that,
I will add a number of built in HTML element,
the time element.
Now just like address, that's a very specific element,
which is great
if you're outputting some date time information,
and I wanna output the date off this blog post.
So the creation date off that blog post here.
And for this between the time opening and closing tax,
I wanna output that creation date in a human readable way.
Now for the moment let's just output post.date
that will hold the date,
not perfectly human readable though,
but we'll work on that later
but as a start, this is something we can do.
And then here time does element
should also take a daytime attribute.
That's an attribute you should always add
to this time element
where you then output the machine readable date.
And therefore again,
I'll use EJS to output posts.date here as well.
And that will then soon be a machine-readable date,
which is basically interpreted by the browser,
which can help assist of technologies.
And then we've got the human readable time or a date
between the opening and closing elements.
So that's a little bit of extra HTML knowledge here,
probably worth knowing as well.
And with that, we're outputting that post metadata
in a clean and correct way.
Again, if you did not do it like that,
chances are high you didn't, that's absolutely fine.
These are new elements,
which I didn't wanna hide from you though.
So with that route putting the metadata,
now as a last piece here,
I also wanna output the actual post body.
And for this here,
we can actually output post.body here with help of EJS
in that body paragraph.
And with that we're outputting all that post data.
If you now save all the files
and you go back and view a single post,
you should see something like this.
The data is not formatted in the way I wanted yet,
but the rest is looking good.
I also got this clickable author text,
and if we do click it, the male client would open up.