So let's get started with Ajax.
And as mentioned in the
beginning of this course section,
Ajax, and this entire idea behind this concept,
is all about sending HTTP requests from
inside your browser-side JavaScript code.
And therefore, if you want to use this Ajax concept,
we first of all have to write some
browser-side JavaScript code.
And for this I'll go to the public folder,
since the contents of that folder are
statically-served and made available to
the visitors of our page.
And in there,
I'll add a scripts folder,
next to the styles folder.
In the scripts folder,
I'll add a "comments" JS file,
because I'll write some JavaScript code,
some browser-site JavaScript code,
that will deal with fetching and saving comments
with those Ajax requests to be precise.
And since I want to start with fetching comments,
let's see how that could work.
For this, let's have a look at the template
where I do want to fetch comments.
That's the post-details EJS file.
And in there I have this load comments button,
which is wrapped by a form,
just to ensure that a get request
is sent to this URL if this button is clicked.
So this form doesn't submit any
data that should be stored.
That's why I'm using a GET
instead of a POST request.
It's only there to GET a new URL
when we click a button,
alternatively,
we could simply use a link to this URL,
that would work as well.
But now I do want to change this all a little bit.
And instead of using such a form,
I want to add a click listener to this button.
And when the button is clicked,
then I want to send such an Ajax request.
Therefore, as a first step,
we can actually get rid of this
form element here,
and just add the button like this,
because whilst the button now
normally wouldn't do anything,
we can of course add a click listener to
the button with JavaScript,
and then write our own browser-side
JavaScript logic that will be kicked off
once this button is clicked.
For this, we just need a way of
getting access to this button.
And one easy way of getting access
is to add an ID to it.
And for example, name this the
"load comments" button, like this.
And then in our comments JS file,
which will run in the browser,
we can get access to the
"load comments" button element
by using document get element by ID,
and passing this ID here.
So, this will then give us access to this button,
so, that as a next step,
we can add an event listener to it.
As we also did it many times before
in this course already.
And here, I then wanna add a click listener to
then execute a function that should then
actually send a request to fetch those comments.
So, therefore we can add a function,
"fetch comments for post" could be
the function name, describing what
the function will do.
And then here, I'll pass this function,
pointer at this function,
as a second parameter value to this button.
Now, in here, in this function,
I now do want to send such an Ajax request to
my server to fetch that data,
that comments data.
And as I mentioned,
we could do this with this XML HTTP request object,
but that's a bit clunky to use.
Or we add a third party library,
like Axios,
and use stat in this function then.
Or we use the built-in "fetch" function,
and I'll go for that approach.
So, we can call the fetch function here,
even though we haven't defined it,
because it's built into the browser.
And then the fetch function takes a
string as a parameter value.
And the concrete value here
should be the URL to which you
want to send a GET request;
Because the fetch function by
default sends a get request,
though you can configure it to
send different kinds of requests as well.
We will explore that later though.
So, here we'll send a get request.
Now, the URL to which I do want to
send a request here is in the end,
"/",
so appended to the domain of
the page we're currently on,
and then, "/" "posts", "/", the concrete post ID.
We'll have to see how we get that,
"/", "comments".
So, I want to send a request to
this path on the currently loaded domain,
on the currently loaded website, in the end.
Now, how can we get this ID here,
inside of this Java script file?
There are various ways of getting that,
one rather simple, yet very good way
of getting the ID,
is to add it to this button.
With such a "data-" attribute.
You might recall this special attribute.
I did cover it early in the course when
we built this tic-tac-toe game.
It's an attribute that allows you to
append or add arbitrary data values to
any HTML element of your choice.
So all HTML elements can take
these data attributes,
and you can then use these values,
which you added to HTML elements
in your JavaScript code.
So for example, here we could add
a post ID data attribute like this,
with "data-", and then any identifier of your choice,
in this case post ID,
and then simply set this equal to
"post._ID"
injected with EJS,
so that the concrete post Id value is
injected dynamically when
this template is rendered.
So once it was rendered,
this will be a fixed value,
but it will of course be different
for different posts.
And now we can extract that from the button
when the button is clicked.
Because in this function here,
will automatically get an "event" object.
We also learned about this
early on the course already.
When you trigger a function
based on an Event Listener,
JavaScript automatically gives you an
"event" object describing the
event that occurred.
And in there you, for example,
get the target of the event.
So in this case,
the button that caused the event, like this.
Though, we don't even need that, of course.
Because we already got access to
the button here, through line one.
So whilst we could get access to it,
like this with event target,
we don't even have to use this way.
Instead, we can get our post ID therefore,
by getting access to this button,
the "load comments button" here,
and then there,
we can use the "dataset" property to
get access to all these
data attributes we added.
And then the identifier we chose
for our data attributes.
In this case,
"postid".
Like this.
This will give us the post ID we added,
because I chose post ID here as an identifier,
after a dash.
And that's how we can get the concrete post ID.
And now we can add this here,
and to easily inject this into the string,
I'll use this template string,
with the back ticks.
We learned about that earlier in the course.
Where I have back ticks instead of single quotes,
and this still creates a regular string,
but it's a string into which
you can inject values like this,
with this dollar sign, curly brace syntax.
So this then constructs a string,
which contains the post ID value.
And this will then send a
HTTP request to this URL.
So now with that,
we'll send a GET request to this URL.
That already is a Ajax request,
if you want to call it like this,
or simply a JavaScript driven request.
A HTTP request, which is invoked by
our own JavaScript code.
And that is a key difference to
all the requests we sent before.
It's now not sent automatically
by the browser and therefore,
the response won't automatically
be handled by the browser.
Instead it's sent manually and therefore now,
we as a developer also have to
define the exact code that should
be executed once we get a response.
And that's why we're doing this,
because now we'll have full control
over what we do with the response.
We don't automatically load a new page,
we can instead just update the existing page.
Which is exactly what I want to do.
Now, how do we do this, though?
Well, as I mentioned before, on the slides,
the fetch function returns a promise.
So therefore, we can actually add the
async keyword here.
As we did it multiple times before
on the server site,
when we worked with Mongo DB or mySQL.
Now ,I'm doing it here in the client-side,
in the browser side code,
because there we can also use async await.
It's not Node JS specific.
And we can use async await
whenever we're dealing with
asynchronous operations that use promises,
like the fetch function does here.
And we can then await this response,
which we get eventually back.
So fetch will give us a promise,
which will resolve to a response eventually.
And that response can be stored
in a constant like this.
Now in this response,
we'll get a bunch of information.
This response here, is simply an object
with a bunch of information about the response.
For example, we can look into the headers,
which are as some metadata,
some pieces of metadata that are attached.
We get an "ok" field,
which is true or false,
telling us whether it's a success response,
or if an error occurred,
and much more.
For us most importantly,
we want to get the body,
which is the data that was
sent back by the server.
Though, we actually don't get it
in a convenient format here,
if we access this body field.
Instead, we typically use one of
the utility functions,
the find on this response object.
So, also built into the browser,
which will part the response body for us.
For example, if we get back such JSON data,
which is the data format commonly used,
we would call the JSON function here,
or the JSON method to be precise,
on the response.
And this would give us the
extracted and already parsed
response data as a JavaScript object,
or as JavaScript value types in general.
Now, JSON doesn't give us the data like this.
Instead, it actually also yields a promise,
because this parsing can also take a bit longer.
And therefore is an asynchronous task.
And hence, we can also wait this
before we then actually got the data
which we want.
So the actual response data.
And that (inaudible) the data which
we can use in code to continue,
to then, for example,
update parts of the loaded page.
But before we do that,
we'll have to move back to
the server-side first.
Because it's good that we
try to parse some JSON data here,
when we send the request to this URL,
or to this path.
But at the moment this would fail,
because at the moment,
if we have a look at our routes,
this get route here,
to which we're sending a request,
does not return any JSON.
Instead,
this get route returns a rendered template,
and therefore in the end some HTML code.
Which was great
as long as the browser should handle this,
but which is not what we want
now that we are sending our own request.
Now we're not interested in a full HTML document.
We don't want a rendered template.
We want the raw data,
so that we can use that in our
own client-side, JavaScript code.
And therefore,
now we want to change the response
that's sent back here,
in this get route.
Instead of sending back a rendered template,
we want to call the JSON method
on the response object here,
in our Node Express code.
And the JSON method is a
built-in method on this response object,
just as render was a built-in method.
Render was a built-in method
for rendering templates.
JSON is a built in method for
sending back JSON data.
And this can be confusing because we
got a JSON method here in
our Node JS Express code.
And we got a JSON method here
in our client-side JavaScript code.
But the two methods are coming from
totally different places,
here in the client-side Java script code
it's built into the browser.
Here on the server-side code
it's built into the Express library.
And they do different things.
Here, when we call it on the server-side,
we in the end, encode data as JSON,
to send it back as a response.
On the client-side we do the opposite.
We decode data which is currently encoded in JSON,
to convert it back into JavaScript data values,
with which we can work in our JavaScript code here.
So we've got the two opposite sides
working together here,
between request and response.
And therefore here, we now wanna send back
a response where we encode our data as JSON
so that we can and decode, and use it,
here in our client-side code
with help of that JSON method.
Because JSON is that data format,
that machine-readable data format,
which is typically used for
transmitting data between client and server.
Now the JSON method here,
in our server-side Node Express code,
wants a value that should be encoded to JSON,
and that should then be
sent back as to response data.
And in my case here,
that should be the comments,
the comments which have fetched here,
this array of comments.
That's what I wanna send back.
We could also send back an object
that has a "comments" key,
which then stores to comments.
So then the comments array would be a
nested array in this object.
This is totally up to you.
You can wrap the array in
such an extra object,
or you directly sent back the comments array,
which is what I'll do here,
but ultimately that is totally up to you.
What we now don't need any more here,
in our server-side route,
is this line here, line 119.
Previously, I needed to fetch the
post in addition to the comments,
because I had to render the
complete post detailed template.
Now, since we don't load a new page,
but only sent back specific data
that we want on the front-end,
we don't need to get the post again.
Instead, we just need to send back
that specific data that was requested,
and the specific data that was requested were
these comments.
So sending back the comments is all we need to do.
And therefore now with that,
we updated this server-side route.
Now back on the front-end,
we get this response data,
and parsing this from the JSON
data should now work,
because we are now getting JSON data
in the response.
Now, before we do anything useful with it,
let's simply console-log this
response data here,
to see whether that all works.
So now, after adding all this code,
if we now save all our files on the server,
and on the client,
all we have to do is go back to
the post detailed template,
and then make sure that
we load our JavaScript file.
So here in the head section,
we can add a script tag and point at:
"/", "scripts", "/", "comments" JS.
And also at the defer attribute
to make sure that this file
only executes once all the
HTML code has been parsed.
Now save this as well.
And then back here,
we can go back to all posts,
and view a single post.
And now let's open the developer tools,
and go to the JavaScript console there,
to then click "load comments".
And if everything works,
you should now see your array of comments here.
So the comments that were
fetched from the server-side.
And there were fetched from the database.
Now, of course you might not have any comments yet.
You have to add them through this form first.
And you can do that,
even though the form is not
implemented with Ajax yet,
still it works.
So you can add some comments.
And once you did add some comments,
you should also see them here in the console.
Whenever you click load comments.
Because sending this behind-the-scenes
JavaScript request works.
And you can tell that the page wasn't reloaded.
If you take a closer look at
this "refresh" icon here.
When you reload the page, or if you switch a page,
it briefly changes to a cross it's very quick,
but it briefly flickers and changes to a cross.
Here if I click "load comments",
if you watch this icon,
it never flickers.
It never changes to a cross because
this page never is reloaded.
The browser is not loading any new page.
This is really just happening behind the scenes,
driven by our own JavaScript code,
where we used this Ajax concept
to send our own request.
And that is a huge step forward.
Now let's however,
also see how we can update
what we see on the screen based
on that response that we get back.