Jonas: Welcome back, so let's now take care
of our application data and the user interface as well
by using a technique called templating.
So basically we have this HTML template
that will then be filled with the data for each
of the laptops.
So for example when it's laptop four,
then our template will get filled with all this data,
this image, this price, then this data,
then also the description.
If we have image three for example,
then it is a different price, different image,
different data, different name here,
and everything changes, but the template is the same.
And so what we're gonna do now is to take
an HTML file that I coded for this page
and convert it into a template which we can then use
to replace the data and send that back to the browser, okay?
Maybe it sounds complicated,
but it's actually quite straightforward.
Okay, so let's open up the laptop.html.
And so this is the HTML code that I was talking about.
I also have the CSS code right in the HTML
because that's easier, okay?
And so down here that is the HTML that people now replace
with some placeholders basically
that we can then replace, okay?
So let's create a folder here called templates.
And then copy these two into that folder
so that we keep the originals here.
What happened here?
Copy, sure, I wanted to paste.
So paste them in there, and here we go.
Close all of this.
Let's rename this also, and the name doesn't really matter,
I'm just gonna call it template
and then the original name, alright?
So starting with template overview,
or actually template laptop, let's come down here
and everything that is data we will now replace
with a placeholder.
So here we have the price, so let's replace that.
So what I'm gonna do here as a placeholder
is like using a couple of symbols so that we don't
accidentally replace something
that we actually want to keep.
So if we do it like this, well then we can be sure
that nowhere else on the page,
actually I want this, okay.
So now we know that nowhere else on the page
will probably be something like this, right?
So this is our placeholder.
If we just called this price, just like this,
maybe there might be some other string
exactly like this, and then we would replace something
that we actually want to keep.
And so with this kind of unique looking text here,
that is not going to happen.
And so we're always going to use this format here, okay?
Then here we want the image.
We actually copied this one here, that's easier.
And here's the slash, and I'm going to explain why
here in a second, or actually a bit later in the video,
because image will be something that we will
have to fix later, okay?
As the alt text here, we want the product name, okay?
The product name will be this here, right?
So again later we are going to replace all of this
by the data that's going to come from this JSON.
So the price, the product name and image,
CPU, RAM, storage, screen, and description, okay?
So the product name here, again the product name.
Then here, we have the screen.
Then we have the CPU.
We have storage.
And finally we have the RAM.
Then this here is the description.
And then finally again, the price.
Okay.
Then here I have some emojis as you're probably noticing.
Maybe on your computer they are not working,
maybe you don't have the latest operating system version,
and you could just use something else
or you could get rid of the emojis altogether
if you don't like them, okay?
But anyway our template here should now be done
and we are now ready to basically load this HTML file,
replace all of these placeholders by the real text,
and then send that HTML to the browser each time
that we request a certain laptop.
Okay, make sense?
So let's do that, and it's right here
in the laptop route, right?
So fs.readFile again,
and this time we're not going to use
the same conversion, okay?
So many times in note there are synchronous
and asynchronous versions of the same functions.
Now I'm not going to go into real deep details here,
but the synchronous version is always blocking,
so basically it makes the entire code stop
for the time that the function is doing its work,
and that is going to block the entire thread
for all the users that are accessing your code.
Because Node.js runs in something called a single thread.
And so there's only one thread in the computer
that runs your application, no matter if you have 10 users
or a million users accessing your app at the same time.
So if you block the single thread with a synchronous
function that takes up a lot of time,
all the other users will have to wait
until that function finishes its work.
And so usually we always try to use
the asynchronous versions, okay?
Because then they do the work in the background
and as soon as they're finished,
they simply run the callback that we pass into
the asynchronous function, okay?
And so that's what we're gonna do here.
So we have the asynchronous file read
and then we need to pass in the file name
of the template that we just created.
Again we have to use the dirname variable
and then templates,
and template-laptop.html.
Then the character encoding again, so UTF-8.
And now this time again we have
the callback function in here.
And that callback function adds access
to at least two parameters which are error and direct data.
Okay, so this time we're not going to save anything
to any variable like we did up here
in this synchronous file read,
but instead we're going to wait until node
finishes reading our file and then calls our callback
and passes the data into that callback
as the data parameter.
And so now in here in this callback
we will have access to that data using
this data parameter, okay?
Now up here we get the synchronous file here,
I just want to mention this because you might be wondering
why the hell we used the synchronous version up here.
And we did so because here it is no problem,
because this only happens once you start your app,
and now while maybe millions or at least thousands
of users might be using your app at the same time, okay?
Because remember, each time that someone accesses your code,
this is the callback function that is executed, okay?
So this is where you don't want to block the main thread.
But here is no problem, because again it runs
only once when you start up your application.
Anyway, what we have here now is basically
this HTML read into this data variable, right?
So all of this here is now as a string
in that data variable.
So now all we have to do is to replace again
these placeholders as I mentioned before, okay?
So that's very easy, so let's do that.
So let's create a variable here called output.
And it's actually a let because we're going to change this
basically for each of the placeholders, okay?
So this will be data.replace.
It's a very simple string method and so we say it,
and let's start here by the product name.
And then replace it with the actual data.
And what is the actual data?
Well it is the laptop data, right?
So that is our array here that we read
from the adta.json file and then at the position of the ID.
So ID, which is remember, the ID that we read
from our URL, okay?
And so if it reads the number three,
well then we're gonna access the laptop data
at position number three, okay?
So we have that laptop now, imagine that it's number three,
so zero, one, two, three, and what we want
is the product name, okay?
.ProductName.
And let's actually create this variable here outside,
so just like this.
So take it from here so we only have to read it once.
And so it's now laptop.productName.
Okay, and now all we have to do is to do the same
for all the others.
Now keep in mind that this replace method here
will actually return a new string, alright?
So output is now data with the product name replaced.
What this means is that when we next want to replace
the next placeholder, let's say image,
we have to do that in the output from before, okay?
Otherwise we're going to do it in the original data variable
where the product name was not yet changed.
So basically this is like a chain.
So first we replace the product name,
then in that variable we replace the image
and then the price, the screen,
and so on and so forth, okay?
And now we can just duplicate this here a couple times.
So we have image, then we have price,
then we have the screen,
we have CPU,
we have storage,
we have the RAM and then finally
we're gonna have the description.
And I guess that's all for now.
Alright, now there's just one small issue here,
which is that replace only replaces the first occurrence
of each of the labels, so of the strings
that we're searching for.
Now we have the price here I remember twice.
And so we have to change that,
and the way we do it is to actually use something
called a regular expression, okay?
And I'm not gonna go deep into that here.
Again, you can just always Google a regular expression
when you need it, okay?
Now all I'm gonna do here is to actually replace
these quotes here with a slash, okay?
Because the regular expression always starts and ends
with a dash, and then the same here.
So all of these here need to go now,
and then slash and G, okay?
So again, a regular expressions is something
that you can just Google.
This is not a part of Node.js,
it is just a regular JavaScript, alright?
And if this here seems a lot of work to you,
then of course as I mentioned before,
there are tools in Node.js, and mainly I'm talking
about something called Express which is a framework
for Node which takes some of the pain away from this.
So we can use something called template engines
which will make it a lot easier to do this,
what we're now doing manually,
but again I think it's a great exercise
to learn how things actually work
and how you can do everything on your own also
even without using any framework, alright.
So we should now have our final HTML in this output variable
and then all we have to do is to actually send this
to the browser, so send a response back.
So we use the res variable again, so a res object,
and then end and output.
Alright, let's check that out.
We have number four and we have some kind of error here,
so let's check out what's happening.
And it says here that output has already been declared
and of course yeah, this doesn't make any sense.
Let's just get rid of all of them,
so we only need to declare it of course once
and then we're good to go.
Try that again, and bam, here we go.
So we have our real HTML page here with all the data
that is coming from the Samsung Notebook nine.
So from, yeah number four.
So we have the RAM storage screen
and you will see everything is the same
as we have in our data JSON, so that's amazing,
that's really great.
Number one is the Apple MacBook
and now we have one terabyte, 15 inch retina display
and a six core Intel i9.
And of course there's the huge price.
Now one thing that's missing here is the image,
and we're gonna fix that a bit later.
Because that's something a bit particular
and for now I just want to continue with this templating
now for the other part, so for the products.
So we have the laptop page now working,
let's go ahead and do the same
for the product overview.
So basically this part here, okay?
Now this will be a bit more difficult
because we will basically have a loop which will loop
over all of our products and then for each of them
create this HTML for this card here.
So if we have only one product it will only create
of course one of these product cards.
If we have 10, then we want 10 of these product cards.
And so we have to do that with a kind of loop.
So let's again start by creating a template, okay?
So we have the template overview.
And so let's go ahead and do the same as we did before
down here in the HTML, alright?
And actually I think I forgot something here,
because the product name should also be in the title.
So right here as well.
Okay, so now if we change, now it also says Dell XPS 13
in the title and also down here.
So that part we didn't have before.
Anyway, going back to the template overview
we will now actually have to split it in two.
And that's because of what I explained to you
a moment ago which is that we have to create this card here.
So only this part, we have to create this one here
in a loop and we have to create as many as we need
according to the number of laptops in our data.
And so we need one template for everything that's outside
that's not the card, so that we have basically
that container where we can then put the cards into, okay?
Does that make sense?
So actually go ahead and cut this here,
create a new template,
template card.html.
And then paste it here.
And what we want here in this place
is all the cards.
So you will create a string basically with all
of the HTML for all the cards and then replace
this string with that code which contains the cards, okay?
And so in here we're actually done,
so all we have to replace really is this part.
Up here there's nothing really.
And then all the data is actually here.
So again we have the image.
Let me go ahead and copy this pattern here,
then in the alt we will have the product name again.
And here the same.
Here it's the screen.
The CPU, and finally the price.
This one here has a bit less data.
Now actually we also need something else,
and that is the href for this link.
So we want to go to laptop,
and then remember our query string.
So ID equals, and then the ID, right?
So let me show that to you in the original.
So in here as you can see down there in the corner, right?
We have laptop and then the query ID of ID equals zero,
because that will then lead us to the page,
as you see then the ID zero,
which will then load the data according to the ID.
So as we did in the previous step, okay?
And so now in the overview we will actually have to provide,
we will have to construct this ID so that it will then
take is to the correct laptop that we want to display.
Okay, make sense?
So again, the path is laptop and then the ID equals
the ID that we're then going to replace, alright?
And so that's actually it already I believe.
And so let's go back and do that here in route
for the product, so the product overview.
We don't need that, and now we could go ahead
and copy a bunch of this code here,
but then we would have duplicate code and that's not ideal.
So instead let's simply create a function for that
which we can then reuse, so that's always the better
thing to do not only in JavaScript
but in programming in general.
Right, so let's create function replaceTemplate.
And so what I need in here is the originalHTML,
and we need of course the laptop, okay?
And so now what I'm going to do is to cut
all of this and paste it down here, okay?
Just format the selection and alright,
just one minor change that we have to do here,
because this is no longer called data now,
it is the original HTML,
which is coming from this parameter, right?
So in the end all we have to do is to return the output.
Okay?
And finally we also need to replace the ID.
So that's for this part here.
This part we didn't yet have here in the code
and so I'm adding that to the replaceTemplate function now.
So let's use replaceTemplate.
First here in this place which we already had working.
So const output will be replaceTemplate
and here we pass in the data and the laptop, alright?
And just to see if this actually works,
let's just reload this and indeed it does.
So everything works the same and so we simply
explored this functionality into its own function
so that we can now do the same
with the product overview, okay?
So where do we have that part?
Ah, it's right here.
Let's actually add some comment here to make this
a bit more legible.
So product overview, or products.
And the laptop detail.
And then URL not found.
Alright, so that always makes it
a little bit easier to understand.
So again we need to do this in two phases
basically as I explained before.
We first need to basically load all the HTML
which is not in the cart.
So basically just everything here around.
So the tile basically and then this background, okay?
And so that is this HTML that we have down here.
So just this.
And we will then go ahead and replace the cards
with the HTML generated using this template, okay?
So again we need to do this in two steps
because we want to have a dynamic number of laptops.
So I'm just gonna go ahead and grab this code here
because it's quite similar
and there's no need to rewrite all of it.
So it's template overview now
and now this part is what we don't need.
And now just to check, let's actually simply render
what we already have, okay?
And so instead of render output, it's now render the data,
so this parameter here, okay?
So let's try that out.
So products is our route and here we go.
So we have the title and then we have this string here
that we now in the next step need to replace with our cards.
So I can actually go ahead and copy this again
and then have it in here, okay?
And so this callback function in here basically,
so this new one here, needs to be inside the first one
because we only want to read the card template
as soon as the overview template has been read, okay?
So basically to create a sequence here, alright?
So this is now, I put cards, card.
This is no longer needed 'cause we're not going
to send the data just here without the cards in there
and so let's now loop through all of our different laptops
and create the template for each of them, alright?
And that would be fairly easy as well.
So laptop data, remember that is the array
where all of our laptops are stored,
so all the objects for each of the laptops,
and so we do a simple map.
And remember that map is an array method
which moves through the array and in each iteration
it saves the result of the callback function
into a new array, okay?
And so we need to actually save this here to a new variable.
Output, alright.
So we've been calling this always output,
and so this one is the cards output, alright?
So we want to loop through the laptop area,
and for each element, what we're going to do is
to use our function.
So our replace template function that we used before.
And so now it's really handy that we did this function,
alright, because all we need to do now is to pass
in the cards HTML, so data and then the laptop,
which in this case is the current element called EL, right?
So remember we need to pass in the original HTML
and the laptop.
And in this case the original HTML is this data
that we read for the card and the element
is the current element of this iteration
through the laptop data array, alright?
So let's just lock this to the console here
just so that it makes 100% sense to you.
I'm not sure it does at this point,
and so let's just reload.
This looks a bit weird, but don't worry.
Right now I'm only interested in the output here,
and so you see that we have now
the HTML for all these cards.
So it's an array actually, so an array of all these strings.
So we have the card, and here we have the next
element, so the next element in the array.
A new card, and so we will have five cards
for all the five laptops, okay?
Make sense?
Now we want this actually in a string,
and so all we have to do is to say join.
And again we did this before so this is nothing new really.
So we join this with an empty string
and if I reload this now,
you will see that the output is simply a huge string
with all of this HTML, so perfect.
So what is the next step that we need to do?
Well all we have to do now is to replace that cards
placeholder, so this one here with this HTML that
we just generated, okay?
So this data here.
And so let's actually give it a name here,
let output equal the data.
Alright, and so now all we have to do is to change
that output so that our original data here,
so the overview output, and let's actually call it
overviewOutput
to make it a little bit less confusing I guess.
So the overview output will be overviewOutput.replace.
And so the string is this one,
and now we don't have to worry about
any irregular expressions because there's only
going to be one of this.
So we're going to replace this placeholder by the cards
or with the cards output.
And now all we need to do is to render that overviewOutput
and that should be it.
Okay, let's try it out and bam, here we go, amazing right?
All that's really missing is the image again,
but again I'm gonna fix that in a minute.
But for now just see how it actually
dynamically on the fly generated this page
based on our data.
And if I go ahead and remove one of them of course,
let's say I remove this Dell product here,
just get rid of it and now reload,
then it's of course gone and now we only have
these four left.
So really it does it automatically, dynamically,
and on the fly.
So that is the power of Node.js
and JavaScript on the server.
As you see, you can really recycle 90% of what you already
know of JavaScript and take it to the server
to build these backend applications without any problem.
So now it's back and it's back here as well.
Okay, and with everything now working,
the last thing that we have to fix is these
images not working, so let's actually take a look at them
and inspect them and try to figure out
what is not working here.
So for all of this we have this error message,
the server responded with a status of 404 not found.
So why does this actually happen?
Well it does happen because Node.js doesn't serve
any files by default.
Every URL is always like a route.
And so for example, if we have this image here,
for Node.js this is just a simple request.
So let's try to figure out what happens if we were
to simply put it in here.
Like this, then we will get the URL
was not found on the server.
Alright, maybe you're thinking that's because
it is in the image folder in data.
Alright, so let's try that out.
Because you might think that this part here
is like the home folder and then we need to simply type
data/image and that's it.
But that is not how it works, actually.
Because on a Node.js folder, the concept of folders
and files does not really exist.
So everything is like a request.
And if we request this image here,
well then we need to kind of respond
to that request as well.
But right now we only request to the products route
and to the laptop route, right?
And so we now need basically a route for images as well,
so we can then surf these images on these requests.
Okay, and to illustrate this even more,
let's go ahead and log this path name here.
Okay, and so now you will see that there is not just
one request, right, so there is not just a request
for this product, but also for style.css
and for these five images, okay?
And so we loaded this page,
but that is not the only request.
All of the resources that are on the page
are also requests and we need to respond to them
if we want to display something based on them, right?
So in this case, these images.
We also have the style here,
but let me just get rid of that.
It's probably here in one of these templates right here.
This is actually the reason why I did the style in lines
so I put all the styles right in the HTML files
so that we don't have to deal with CSS as well.
Because then we would have to need yet another route,
and that's not really practical, alright?
So again with these frameworks like Express.js,
this is a lot easier.
You don't have to really do this manually,
but once again I like to really understand
how and why things work the way they do.
And I think it's also very beneficial for you as well, okay?
So let's now try to do a route for images in general.
Of course we're not going to do a route
for each of them individually, right?
We're going to have a general route
that works for all of the images.
So what we want here is another route.
So images.
Else if, and now what we need here is basically
a true false value indicating if the resource
that we're requesting is an image, okay?
And again if you need something like this
you can always Google regular expression
to find image extension, okay?
So basically that's what I did for this,
because it's really difficult and time intensive
to really learn how regular expression works.
I find it easier to just Google it, okay?
So we always start a regular expression with slash
and end it with slash, and then in there
there's some kind of magic happening.
And in this case it works just like this.
So basically we test if there is an extension
with just the dot.
So if there is dot jpg
or maybe a jpg written with E
because sometimes you see that or a png,
because we actually have a png, this one here.
And let's say we also might have a gif
or a gif, I don't know.
And so let's add that here as well.
Then we need this dollar sign here,
for some reason, slash i, alright?
And so this is all regular expression
and we will now test if our path name contains
basically this regular expression.
So we say .test which is a method that is available
on all regular expressions in JavaScript.
And then or pathName.
This one I don't need, and okay.
So this is our regular expression again,
and we will now test if our path name which is for example
this one here, this one or this one,
we will test if it contains .jpg or .jpeg
or .png or .gif, alright?
And if it does, well then we're going to read that image
and serve it or basically send it
back as the response, okay?
So let's just do that.
So readFile, then again we need the dirname
and now where is this image?
So imagine that we have macbook-pro-15.jpg as the request.
So what we need then is to go into our folder/data/img
and then our path name.
Make sense?
Because that is the name of the image
that we're actually trying to read, okay?
Now this time we're not going to do the character encoding
because this is not text, it's just an image.
And so now all we have to do is to pass in the callback
function which will be called as soon as we're done
reading the image.
And again it's important that this happens asynchronously,
and so that's why we're using the readFile
and not readFile async, alright?
Now as soon as we're done reading that data,
all we have to do is to really send the head as always,
and this time let's just do image
and then jpg.
Okay, so that's the content type.
There are many, and one of them is image/jpg,
so the type of data and then the file
extension actually, alright?
And then as always, res and then end and the data.
Okay, now in real world application we should also
have some error handling in place,
and that's why we always have access to this error
here as well, so imagine that the image
we're trying to read is not really there,
well then we would have an error
and we could handle that error.
But here in this case we're just going to assume
that everything works just fine, alright?
Okay, let's now test this.
Reload and bam, our images are now there.
Still one error, don't know what that is.
Ah, it's just a CSS for some reason.
Take a look, maybe it is in here as well.
No it's not.
The overview also shouldn't have it anymore.
Ah okay, it's here.
We can now close all these templates,
don't need them any more, reload,
and yeah, so now we have no error
and we have our images as well.
So again, each of these images is a separate request
and we're handling that request,
each of the requests actually here in this route.
So this route handles images with the jpg, jpeg,
png, or gif format.
So as soon as we have one of these extensions
in our URL, well then we will read the image
from the file system and send it as a response
to the browser, and so then like this
the browser is able to of course display it on a page.
And it's gonna work hopefully on these as well,
and it does.
So now we have the images here just like
in our original store, which we can now close.
And let's also actually try it like here
and indeed, our image is also now here.
So we can do this simple request here
and our image is gonna show up just like this, alright?
Oh what's going on here?
Not really sure, it's really called product.
And back, there's still an error in that code.
So in the HTML.
So let's open up that laptop and here should be a link.
Yeah, it sends back to overview.html
and it's of course not correct.
What we want is to send it back to products, right?
So reload this here and now as you can see, down there here
it will send us back to products and here we go.
So the Samsung here we see the Samsung.
And yeah, it now works.
So the project is really finished now.
Awesome, that's really really cool.
And of course we only barely scratch the surface here
of Node.js, right?
So this is really just the absolute fundamentals
of what you can do with it.
But I think it was still very exciting
and I hope that you found it useful
and hopefully you're going to want to learn more after this.
And if you do feel that Node.js is something you like
or something you might find useful in the future,
well let me tell you that I will actually be working
on a brand new Node.js course over
the next couple of months, alright?
So that course will have a ton more explanations
than just this small crash course.
It will have a lot of theory, lectures,
so that you really understand how Node.js works
behind the scenes and of course a huge
real world project where you're gonna learn
everything about Node.js, Express,
which is the framework that I just talked about,
and also use MongoDB as a real database
instead of just storing data in text files.
So of course, usually the data comes from databases,
not just text files like we did here, okay?
That course will be available some time
in first half of 2019 hopefully, alright?
So I hope you can wait for that.
In the mean time just keep coding,
keep building great projects,
and keep learning every day, alright?
So I hope to see you soon in some of my next videos
or courses and until then, have a good time.