So let's now render new workouts
in the sidebar of our user interface.
And so what I mean with rendering
is to basically create a list item like this
for each workout.
All right?
So each workout here contains this like short description,
containing the type of the workout and then the date
and actually that's also exactly
what we get here in the popup.
And then, of course, we have all the relevant data
of the workout in case.
And so let's now go back and do that
and here we are still in the newWorkout method.
And so down here is where we're gonna render the workout.
However, just like before,
we are actually gonna create a new method,
which is gonna be called renderWorkout.
And here I'm seeing that I forgot the underscore.
Like this.
And so now let's create renderWorkout
and so this function will also take in an object
of a workout.
All right, and so here,
all we have to do now is to call this method.
So renderWorkout and then pass in the workout
and so with this, we delegated this functionality
to this method and so let's now start working on it.
And so what we're gonna do here
is basically some DOM manipulation.
So we're gonna create some markup.
So basically some HTML
and then we will insert that into the DOM
whenever there is a new workout.
And so let's actually get the code right here
from the HTML and I already have it here commented out.
So let's actually go up a little bit more.
So you see that we actually have a ul,
which stands for unordered list called workout.
Then in there, the first child is actually a form.
Okay, and only after that,
we then start adding these list items
with the class of workout.
Now, the first one here is a workout for running.
And then the second one is a workout for cycling.
All right?
So let's basically take what both of them have in common,
which is basically this first part here,
which is the distance in kilometers
and also the duration.
So these are the same
but then on running, here we have the pace
in minutes per kilometer,
while here, we have kilometers per hour,
which is the speed
and here, of course, we have the elevation gain,
which has this emoji here,
while here we have these steps per minute.
And so let's start by taking the HTML here
that is common to both workouts
and then after that, we will implement this remaining part
of both running and cycling.
So I'm copying it
and so then here, let's create const html
and then as always,
we are gonna use a template literal for this
because they're really amazing,
they're really actually perfect
for doing this kind of stuff.
Okay.
So this indentation looks about right.
Of course, it would work just the same
as it was before but this then looks a bit nicer
because it follows the natural structure of HTML.
Okay, and now all we have to is to replace everything here
with the real data.
And let's start with the easy parts.
So this one here is, of course, the distance.
And so let's add workout.distance.
And then down here, we have workout.duration.
Dot duration.
Then up here, we actually also have the id
and so here we once again have this custom data attribute,
which in this case, I called data-id.
And remember that we use data properties like this one
to usually build a bridge
between the user interface and the data that we have
in our application.
And so in a future video,
this one here will become very important.
But for now, let's simply add the id here,
just like before, so workout.id.
Then next up, here we need to specify whether the workout
is a running or a cycling workout
because it's this class here
that will then give the list item that green
or that orange border.
So remember, that is stored at workout.name.
Then here, we have this emoji here, which is for running
but for cycling, we have this other one.
So this guy on the bicycle.
And I hope that you can see these emojis
just as well as I can here in the video
because I know that, I think on some systems,
this doesn't really work.
But in that case, that's of course, no problem.
It doesn't really matter if you can see the emoji or not.
But anyway, what I'm gonna do here
is to use the turnary operator
to check whatever the runner here
should be displayed or the cycler.
So that's easy.
Workout.name and then we just need to test
if it is running.
So if it is, then we want basically this to be the output
and otherwise, this cycler.
And here I need to close that
and that's actually it.
So one more time, the turnary operator
is super important.
So as you see, we are still using the fundamentals
that we learned right in the very, very first section.
So I said back then that they were important
and indeed, they were.
Now, finally, here we have basically this description
of the workout.
And it is composed of the workout.name essentially
and then also the date but nicely formatted.
And the way that we're gonna generate this description
is by adding a new method on the workout,
which will then create a description
like this one immediately
when the workout gets actually generated.
Okay?
So as I was just saying, here in the workout,
I will create setDescription.
And so this is where we now need this array
that I gave you in the beginning
with these months.
So I didn't feel like writing it all out.
And so here it is.
And by the way, I have this comment here,
which is something that we can use
to tell Prettier, so that Prettier extension
that we are using to format our code,
so this comment here we can use whenever we want
to tell prettier to ignore the next line.
So let me see what happens if I take this out.
So then you see I have everything here line by line
and I don't like that.
And so this is much nicer in this case.
Okay.
But anyway, let's now set the description.
So this.description.
So the description will be based on the name
of the activity
and actually, I don't mean name, I mean type here.
And I believe that down there,
I used name instead of type.
So let's check that.
And ja, for some reason, I used name.
Hopefully, you didn't get too confused by that.
So of course, that is workout.type and not .name.
So it's the type that can be either running or cycling.
All right?
And so that's what we will use now here
to create the description.
So a new template literal
and then here we actually want
to make this type here uppercase.
So the first letter
and so we can take this.type,
the first character
and then toUppercase
and so this is nothing new.
We have done this many times before.
And then simply the rest
of this type.
So slice starting from position one.
So that is the type of the activity in uppercase on
and so now we want basically the month
and also the day.
So we know already that we have the date
of the workout in this.date
and then we can use getMonth on that.
And so remember that this will be here,
a number between zero and 11.
And so that's very nice for a zero-based array
because we can now essentially use this number here
to retrieve any value out of our month array.
So if getMonth returns zero,
then month at position zero is gonna be January
and the same is, of course, true for all the other months.
So this one here will give us the month
and then all we need is the day.
And so this.date.getDate.
And that should be it.
So now whenever a new object is created,
then automatically the description should be set.
And so here we now need to do, of course,
this.setDescription.
Now, right?
And in fact, it should not be here
but it should be down here in each of the child classes.
So why is that you might be asking?
Well, that's because that's the class
that contains the type that we need for this calculation.
Okay?
So we need to cut that from here
and actually calculate it in each of these.
And of course, this will work perfectly fine
because through the scope chain,
this constructor method will get access
to all the methods of the parent class.
And so, of course, that includes this one here.
And so then as the method is executed here,
it will also get access to the type.
And so this is the reason why we can use the type here,
even though it is not defined in this class
but only in the child class.
So again, we could not call this method
on a workout object
because that doesn't have a type.
But that's no problem anyway
because we never actually create new workout objects.
Now, all right, but with all that being said,
let's now come back here
and use this here.
So workout.description.
So that's the part that is common to both.
Now let's get the rest of it.
So all of this but this one is only for running.
So let's copy it
and now here after this part,
or actually here, we can now say if
workout.type
equals running,
then we want to add something to the HTML.
So html plus equal and then this code right here.
So give it a save.
Then here let's fix the indentation
or actually, it's good like this.
Well, actually it isn't.
So I'm just using multiple cursors
and yeah, that's better.
Just do the same thing here.
Okay.
And so now here, of course, we need to change it
to a let variable
because otherwise, we will not be able
to add anything to that string.
And so here, let's now write workout.pace
and then down here,
so that's workout.cadence.
Now, this value here is actually calculated by JavaScript.
And so the result of this calculation
might be some very weird number
and so let's simply round that to one decimal place.
So toFixed
and with just one decimal place.
Okay.
And now just copying this part.
So if it's cycling, then we want to get just this part.
So again, this is the common part.
This is the one that is different.
So again, add on to the already existing HTML string.
And then each time the indentation is a bit different,
don't have any idea why that is.
But now it is correct.
And here, this is probably the speed
and then here it is the elevationGain
so I guess that's just called elevation
but I'm not sure.
Let's just go back there.
So yeah, it's called elevationGain here.
We could have just called it elevation
because that's how it's called in other parts
of the application.
But nevermind, let's just leave it like this for now.
And here, this speed is also calculated by JavaScript.
So let's round this one as well.
And with this, we actually have the HTML generated.
Now all we need to do is to insert that HTML
into our DOM.
So where will we inject this HTML?
Well, let's take a look here at the parent element
and that is workouts.
However, as I mentioned before,
the first child of the workouts
is actually this form
and only the second element
should then become the first activity.
And therefore, we cannot simply attach
the new workout element
to this ul element
because we could either insert it as a first child
or as a last child.
But we don't want any of those options.
So instead, we will insert it close to this form
but basically insert it as a sibling element.
All right?
So again, I will take the form
and then that is where I'm gonna call
the insertAdjacentHTML method.
So form.insertAdjacentHTML
and then here, remember,
I have to choose between four strings
and so that's these four here.
And so the one I'm gonna choose is afterend
because this one will basically add the new element
as a sibling element at the end of the form.
So we discussed these strings before already.
So you can always go back there if necessary.
Okay.
And with this, I think we should be complete.
We already called it up here.
Right?
And so let's now actually try it.
So let's just reload here manually.
Okay.
And now let's just add a simple running
and now we get a problem.
So toUppercase is not a function.
And indeed, it isn't.
So it has to be UpperCase with the C uppercase.
So let's see now.
And again, just putting any numbers here
and there it is.
So here is our very first workout rendered
to the user interface.
So that's beautiful, really cool.
Let's now try this with cycling as well.
And yeah, it does appear here
and also it appears before the one
that we had previously.
And so that is the effect of choosing the afterend string
in the insertAdjacentHTML method.
All right, so that's amazing
but what we need to do next
is to then actually hide this form
whenever a new input here happens.
Right?
And so let's go do that now.
And so we need to go back here to our, well, where is that?
Here in the new workout.
So here we want to hide the form.
And so let's create yet another method,
which is gonna be called hide form.
So I can already copy or actually cut this one here
and call the method before I've written it.
So that's no problem.
So hideMap will be the name of this method.
And now let's actually create that.
And of course, it's not hideMap, it's hideForm.
So let's do it here right after showForm.
So that makes sense, right.
So hideForm.
So the first thing that we need to do
is to empty the inputs
and then we need to add this hidden class back on.
Now, right, so that's add
but as we will see in a second,
this is not yet gonna be enough.
But let's actually see what I mean here.
So did you see this animation here
that happened in the beginning?
Well, we will need to undo that here in a second.
So you see that this one here,
basically did slide up a little bit.
All right?
But that's not what we want.
So here in this version of the app,
let's see what happens.
So as the form appears, everything slides down here.
And now watch what happens as I hit Enter.
So you saw that?
Basically it looked as if that form
was replaced with this new activity here.
And so to do that,
it's not enough to simply add back the hidden class here
because that will then also trigger the animation.
So instead, we need to hide the form immediately first.
So form.style.display.
So we immediately need to set the display to none.
But then we will actually have to put it back
after the animation had finished.
So let's take a look here
at the form style actually
so I can show you what I mean.
Okay.
So this is the transition that I mean
and it is because of this one
that the hidden class has that animation of sliding.
So that's this transform here, all right?
So this animations happens over one second.
And the original value of the display property is grid.
And so what we will do now
is to basically after one second set this display
back to grid.
So that's kind of a dirty trick here
but in order to build the layout like this,
this is what we have to do.
And it's also a good time
to bring back or setTimeout function.
And remember that all that setTimeout does
is to call a certain callback function
after a certain time.
So let's use a simple arrow function here
to make it really simple.
So form.style.display
should be set to grid.
And this should happen after one second.
So 1,000 milliseconds
and so yeah, let's see now.
All right, so again you saw
that animation happening there
but now let's see if we get our desired result
and yes, there it is.
So indeed, we did now immediately hide the form
and then after one second,
we brought back the original display property.
And so all that's really left to do
is to basically add the same description
that we have here
to this popup.
And we will also add a nice emoji,
so this running guy for running
and then cycling, as you see here, for the cycling workouts.
Okay, and this code we can actually get from here.
So from renderWorkout, we already have this.
So where is the marker?
Ah, here it is.
So here is where we set the content
and so again, a template literal.
All right, so this is how we set the emoji
and then all we need now is the description
of the workout.
.description and that should be it.
All right, so that works beautifully
and now just for cycling,
and yes.
So here's the cycling emoji,
here's the description
and so this now works exactly as it does in our demo.
Great, so we are almost finished actually
with our application.
So let's take a look at our flowchart here.
And so what we're missing now
is to move the map to the workout location
whenever we click on one of the workouts
that we just created.
And so that's gonna be the topic of the next video.