Modern JavaScript For Beginners: Part 2 | Chris Dixon | Skillshare
Search

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Modern JavaScript For Beginners: Part 2

teacher avatar Chris Dixon, Web Developer & Online Teacher

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Introduction

      2:23

    • 2.

      Project Folder Download

      0:59

    • 3.

      Share Your Work On Skillshare!

      1:09

    • 4.

      For Loops

      10:18

    • 5.

      For...in & For...of

      6:25

    • 6.

      While & do...while

      5:22

    • 7.

      If / Else Statements & Nesting

      5:56

    • 8.

      Else if

      4:22

    • 9.

      The Switch Statement

      7:57

    • 10.

      Conditional Operator (ternary)

      4:12

    • 11.

      Type Coersion & Conversion

      10:00

    • 12.

      Truthy & Falsey

      4:35

    • 13.

      Optional Chaining

      6:22

    • 14.

      Creating & Modifying New Objects

      5:47

    • 15.

      Object Constructor Function

      9:21

    • 16.

      Object Prototypes

      6:41

    • 17.

      Inheriting Object Properties

      10:09

    • 18.

      Copying Object Properties

      4:38

    • 19.

      CSS Style Objects

      4:35

    • 20.

      Looping With Objects

      9:26

    • 21.

      Dynamic Objects

      5:44

    • 22.

      Primitive & Reference Types

      5:27

    • 23.

      Comparing Objects

      6:41

    • 24.

      Section Introduction

      3:24

    • 25.

      Listing Orders

      12:30

    • 26.

      Listing Orders Refactor

      5:24

    • 27.

      Element Helper Function

      6:33

    • 28.

      Selecting The Current Order

      9:13

    • 29.

      Set The Current Pizza

      5:30

    • 30.

      Split & Join Methods

      10:50

    • 31.

      Adding Pizzas To The Oven

      9:24

    • 32.

      Starting & Ending The Game

      9:09

    • 33.

      Introduction To Javascript Math

      7:08

    • 34.

      Generating New Pizzas With Math

      8:36

    • 35.

      setInterval

      9:17

    • 36.

      setTimeout

      4:47

    • 37.

      Clearing Timers

      3:56

    • 38.

      Introduction To Javascript Date

      5:26

    • 39.

      Setting The Cooking Time

      4:43

    • 40.

      Introduction To The Canvas & Co-Ordinates

      13:03

    • 41.

      Setting Up The Ingredients

      7:45

    • 42.

      Drawing Circular Ingredients

      6:38

    • 43.

      Drawing Multiple Pieces

      13:00

    • 44.

      Clearing The Canvas

      4:33

    • 45.

      Wasting Pizzas

      2:35

    • 46.

      Checking Steps

      16:23

    • 47.

      Completing Orders

      12:48

    • 48.

      Removing Orders

      3:33

    • 49.

      Updating The UI & Stats

      9:55

    • 50.

      Introduction To Scope

      5:49

    • 51.

      Nesting Scope

      5:35

    • 52.

      Block & Function Scope

      3:35

    • 53.

      Hoisting

      7:48

    • 54.

      Temporal Dead Zone

      5:17

    • 55.

      Closures

      9:34

    • 56.

      A Little Bit Of Background

      6:25

    • 57.

      Callback Functions

      15:20

    • 58.

      Promises

      11:23

    • 59.

      The Promise Constructor

      7:51

    • 60.

      Handling Multiple Promises

      7:15

    • 61.

      Async / Await

      6:42

    • 62.

      Handling Multiple Awaits

      4:02

    • 63.

      Error Handling

      8:49

    • 64.

      Leaving So Soon

      8:01

    • 65.

      Image Carousel- Setting The Images

      9:15

    • 66.

      Image Carousel- Creating The Arrows

      7:01

    • 67.

      Image Carousel - Re-Ordering Images

      8:11

    • 68.

      Image Carousel- Swapping Images

      4:04

    • 69.

      Follow me on Skillshare

      0:23

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

367

Students

11

Projects

About This Class

Welcome to Modern JavaScript For Beginners!

This is part 2 of the class, building on the foundation you have learned in part 1. If you have not taken part 1, be sure to go through this class first, unless you have some JavaScript experience already and you want to cover the topics in this section.

Your starter project from the first part will continue into this class, if you don't have it, you can download it here:

Grab the starter files here.

Speedy Chef project stages can be found here.

Learning any new skill can be tough and Javascript is no exception!

Javascript has such a wide range of features and things it can do, meaning sometimes as beginners we have no idea where to even begin.

This is why I have created this class…

This class covers many JavaScript subjects including loops and conditional statements, a deep look at objects,  math, date, and timers, and drawing to the canvas.

This is all while looking at real-world examples and demonstrations, along with building a pizza chef game to combine many parts of what you have learned. This project will be reasonably big but we will break it down into manageable sections.

 Later on, we discover some of the trickier parts such as async JavaScript, scope, hoisting, and closures, before finishing off with 2 more projects, We build a small app called leaving so soon, which is an exit-intent popup to entice visitors with an offer when they try to leave your site. Before completing the class with a fully functioning  JavaScript image carousel.

Thank you for your interest in this class, and I will see you in the first lesson…

Meet Your Teacher

Teacher Profile Image

Chris Dixon

Web Developer & Online Teacher

Top Teacher

Hello, My name is Chris and I am a Web Developer from the UK. I am an experienced trainer leading web development bootcamps and also teaching online courses.

My main areas of interest are Vue.js, WordPress, Shopify, Javascript, eCommerce, and business. I am passionate about what I do and about teaching others. 

Whatever your reason for learning to build websites you have made an excellent career choice.

My personal motivation was to become my own boss and have more freedom and flexibility in my life. I also enjoy the technical challenge it provides and the way it constantly evolves. I built my first website back in 1999 and I have watched the web evolve into what it is today.

I try to make my courses enjoyable and try to remember what it was like wh... See full profile

Level: Intermediate

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction: [MUSIC] Hey, welcome to this class. As we all know, learning any new skill can be challenging and JavaScript is no exception. JavaScript has such a wide range of features and things it can be used for, and this can often leave beginners in a difficult situation wondering where to even begin, so this is why I've created this class. This is Part 2 of the class building on the foundation you've learned in Part 1. If you've not taken Part 1, be sure to go through this class first unless you do have some JavaScript experience already and want to cover the topics in this section. If you've not taken one of my classes before, my name is Chris and I've been building websites for over 20 years. I've also been teaching these skills for over seven years, both video classes alongside leading web development boot camps too. This class has many JavaScript subjects, including loops and conditional statements, a deep look of objects, math, date, and timers along with it drawing to the canvas. All these topics I've covered in a clear and structured way all while building it practical projects as we go, including real-world example use cases and also some mini challenges too along with building a pizza chef game to combine many parts of what you've learned. This project will be reasonably big, but we will break it down, so you can see how all the parts fit together. Later on we will discover some of the trickier parts such as async JavaScript, scope, hoisting, and closures. Before finishing off with two more final project,s we will a small application called Leaving so soon, which is an exit intent pop-up, which is used to entice visitors with an offer when they try to leave your site. If all completing the class faithfully functioning JavaScript image carousel. It includes a project folder which we'll add to as we progress throughout this class and it will also develop as a useful reference in future too. Thank you for your interest in this class and I'll see you in the first lesson. 2. Project Folder Download: If you've already completed part one of this class, you can continue on with the exact same starter files which we used in part 1. This part 2 of the class we'll begin at Section number 6, all the way to the end. I'll begin in the first lesson which is for loops. If you have this, you're completely good to go for the next lesson. If you're jumping into part 2 without taking part 1, which is completely fine too, but you will need to go over to github.com and download the starter files which we are going to be using throughout this class. Follow the link which you can see on the screen here. Once you land on this page, click on the green coal button, and then download this as a zip file. Open up this project folder inside your favorite text editor. I'm going to be using Visual Studio Code, but you can use any which you prefer. This is all you need to get started , and I'll see you next. We'll begin by taking a look at for-loops. 3. Share Your Work On Skillshare!: When taking any course, it's really important to not get in the habit of following along just for the sake of ticking off another lecture. Take the time to process each lesson, review the code which you write, and think about how you might approach these solutions yourself. With this in mind, this class is project-based, and this gives you the opportunity to really make something personal and unique. You don't need to get too lost and divert away from the class and you can even take a step back after you've finished the class and come back and make some project changes afterwards. This will really give you a good chance to practice what you've learned away from the class. Also, remember to share your project too here on Skillshare and only will I check it out, but it will also inspire fellow students too. For more information on the class project, head into the project and resources tab, where you can not only upload your project, but you can also see other class projects too. With this in mind, I look forward to seeing what you create and upload here on Skillshare. 4. For Loops: Welcome back. This section is going to be all about loops. We're going to kick off things with a for-loop. When we started to work with arrays earlier, we looked at some different ways to repeat certain tasks using these loops. The types of loop we looked at was map, and forEach, both of these were array methods. Loops mean we can repeat tasks a lot easier. Even though there are different types of loops they generally keep repeating a task a number of times. Often, the main difference is how we tell the loop to then stop these map, and forEach loops were array methods, but loops are not exclusively for arrays. There's also different types of loops we can use to be able to loop over pretty much anything we need to. This video is going to be focusing on a for-loop. This is how a basic for-loop looks. It sets out a bit like a function or an if statement. Notice inside of the brackets that is two semi-colons. These are used to pass in the free expressions which set up how our loop will work. Really simple example here is just to use it to increase the number and we will look at some better examples in just a moment. But for the first expression, it contains the initial or starting value for our loop. If we just want to start at a number zero or increase each time, we set up a variable to be zero, just like this. Second of all, we have a condition and here we'll see we have the number is less than 10. This condition determines if the loop is to keep going. If this is true, the loop carries on. If false, the loop will then end. Lastly, if we don't do something on each loop, the second condition will always be true. Here we increase the value of the number by one on each loop. Therefore we can check the condition after each one of these changes. To run through this example after each loop runs, the number will be increased by one until it reaches number 10, causing the second statement to be then resulting in false, causing the loop to then end. Meaning this particular example, we'll log 10 values, which will be zero through to number nine. If you have the variable already declared outside of the for-loop, you can leave out and just include the second and third statements, and things will still run the same as before. Also, it's worth noting you will see lots of examples with the variable name, the letter i, which is short for initializer or initial value. This generally is if we're only using this variable for the purposes of the loop and not needing a descriptive variable names elsewhere. Note, we must still keep the semicolons in place so we can clearly separate these three values onto some examples. Let's jump into our starter files. For this section jump into Section number 6, which is loops and conditionals. The first lesson, which is for-loops, jump into the index page, which is pretty much empty for now. Then we'll copy the path to this and then paste this inside of the browser. We have no content at the moment, just the for-loops title, and then the empty script down at the bottom for us to work in. Let's jump inside of the script section and we can start to create our first for-loop. As we looked up before, we use the for keyword, bracket start our free statements, and then the curly braces. For this example, we're going to simulate somebody eating a pizza with 10 different slices. Then we'll deduct a pizza slice after each one of these loops. First of all, our initializer or our variable, which we'll call slices. We'll set this to be the initial value of 10 and the next we'll keep the loop running as long as these slices is equal to or greater than the value of one add a semicolon. Then we'll deduct the value of slices by the value of one each time. Now just to recap, we're going to start off with 10 slices or the value of 10. Then after the loop is finished, this will deduct a slice to then be equal to nine, nine is greater or equal to one so the loop will therefore keep running. Then it will run a second time. Then this will deduct the pizza slices to be eight and then seven, then six. It will keep running until the value is greater or equal to one. Inside of the curly braces, we add the code which you want to run. Grab a simple example, we can do a console log with the value of slices. This is going to be deducted from 10 all the way down to one. After this, a second console log with the text of each slice. We can also add things like conditional statements inside of here too. This conditional statement is going to check if the slices is equal to the value of one. If it is, we'll in place in a console log with the text of no slices left. Let's save this and jump into the Developer Tools. right-click and "Inspect" into the console. We see the value of 10 on the first loop is then deducted by the value of one each time. We get all the way down to the value of one and then it takes a note of slices left. Something you may see, but probably not as much is a second value missing, which is this condition. We do need to leave in the semicolon in place though and before we test this, you may be already spotting a problem. If you have no condition. We have no way of stopping a loop. This will just keep running infinitely. This is something we need to be careful of when creating loops. We must make sure that the loops condition eventually becomes false. Otherwise, we would end up in an infinite loop, which would therefore cause the browser to crash. Don't do this and don't follow along with this example. But I'm going to show you what happens inside the browser. If we save this, refresh. We see the loop runs thousands of times, which takes up all of the browser's resources, causing it to eventually crash. To avoid this crushing or this infinite loop, we need to manually use the break keyword inside of the loop when we want it to then stop. For example, if we go to this bottom section, we know inside the if statement this is the last loop. What we can do is we can add the break keyword. This then break out of the loop and then stops the code from running. We can test this by opening up the browser once more. Open up the Index Page, and then jump into the Developer Tools and the console and our loop, it now works as expected. Another useful thing we can do with for-loops is to create multiple elements, such as list items. Using a loop, we can create, let's say, 10 elements with a lot less code than we would do if we wrote this out 10 times. Let's do this just inside the script, will create a constant called ul, where we'll create a new unordered list. We do this with document.createElement. Passing in the ul elements which you want to create. Just before we jump into creating the list items, we'll append our unordered list to the body. Grab the body with document.body.appendChild, passing in our ul variable. Just going back to what we looked at before, we're going to modify our pizza example and replace this with the variable name of i. Remember i is a common naming convention for a variable inside of a loop. We'll initially set this to be a value of one. We're going to do this in the reverse way from before. We'll start with the initial value of one, and then we'll keep the loop running while i is less than or equal to the value of 10. Therefore, we need to increase this by the value of one on each loop, which will cause the loop to run 10 times. We can move all of the contents from inside here and then create our list items. Let's create our list item we'll select the document.createElement pass in the list item. Store this inside of a constant called li. This will then give us an empty list item. We need to then place the content inside of the opening and closing tag. We can do this with documents.createTextNode, and we can place in any sample text we want to inside of here. Rather than a regular string, I'm going to insert a variable using the backticks. We'll say list item placed in our variable with the $ symbol and the curly braces. We know from above we have a variable called i, which is equal to the value of one. Then if you keep increasing by the value of one for each loop. We can check this out by placing this inside of here. This should start with the value of list item one, list item two, and so on. All this inside of a constant, say text. Then we can merge these two together by accessing the parent, which is the list item use appendChild. Then place our text inside of the list element. Finally, when we create each one of these list items, we then want to push us to our unordered list. In the same way as we did with our list item. We select our unordered list appendChild, where we pass in our list item. Let's check this out, refresh the browser. This just needs to be i to match the variable refresh. Now we see the value of list item one all the way through to list item 10. As you can imagine, if we created this 10 separate times, this would result in a lot more code. Using this loop makes it a much shorter example. 5. For...in & For...of: We're now going to cover two more types of loops, which is called for-in and also for-of. They do look pretty similar and they both loop over something as you would expect, but the key difference is what they can loop over. Let's open up the starter files and see what we have. Into the sidebar, jumping to lesson Number 2 in this section, which is for-in and for-of, and then open this up inside the browser. First of all, we see a for-in section which has a product object with various properties nested inside. As you may expect, this is how a for-in loop works. We use this type of loop to loop over the properties inside of an object, such as the name and the size. Now, this will have the for-of section, and this is used to loop over iterable objects. An iterable object is basically some of them we the loop over, such as an array or a node list. Let's begin up at the top with our for-in loop, and and we're going to use this to loop over our product objects. We can do this just below. This looks a bit like our for-loop from the previous video, we set up the for keyword, the brackets and then the curly braces. Jumping to the first set of brackets, and this is how a for-in loop works. We set up a variable, and we'll call this property since we're looping over all of the properties inside this object, which is in our product object. This is where the term for-in comes from, we have the for keyword and then the in keyword inside the brackets. We're looping over this full product object and then we're storing the value of the property inside of this constant. Let's see what it looks like with a console log of the value of our variable, which is property, refresh, and we see the value of SKU, the name, the size, and the color. This gives us the value of the key, but what about the actual property value such as cool shirt, medium, and also blue? Well, we can also do this by accessing our product and then using the square brackets. Let's take a look at how this looks inside of a console log. We can use the back ticks to insert a variable, and we'll start by inserting the value of property. This is just the keys which we'll see already inside the console, but afterwards add a colon to separate this and then insert our second variable. The second variable is going to be each one of these products. We'll grab the product, and then we can use the square brackets, to narrow this down to a particular property. We're passing in the value of SKU, name, color, or size. If we save this and refresh, we've now created a new string for each one of these properties, which includes both the key and also the value of the property. This is how a for-in loop works to loop over an object. Let's now take a look at for-of. I want to comment out this section and then go down to the bottom below our permissions. Again, this begins with the for keyword, the brackets, and the curly braces, and it also takes in a variable. Let's say const value, which is going to be set to each one of the values inside of the array. This time rather than using the in keyword we use of, and then pass in exactly what we want to loop over. In our case, it's the permissions array from just above. This is in permissions, and then inside of the curly braces, we can access our value. On the first loop, the value is user, the second loop is editor, and then admin, save and refresh, and there's our three values inside the console. As you can see inside of his comments at the top, things like a node list can also be looped over too. Remember, when we use something like query selector all to get multiple elements, a node list is what we get back. To try this out, we also need some elements to loop over. I'll jump outside of these scripts, create an unordered list with some sample list items just inside. Let's duplicate this two more times instead of spin Number 2 and 3, and then we can loop over our three list items, which will then return back a node list, therefore, we can use the for-of loop. Step 1 is to access all three of these list items. I'll just above our for loop, create a constant call links, grab these with document.querySelector, in fact, we need querySelectorAll since we're accessing multiple elements and once you grab our list items. Now, rather than accessing our permissions, what we're going to do is to access all links, which is our three list items and then change the variable name to the link. The value of link on our first loop is the first list item, and the second list item, and then the third. We can do anything we want to with these links. For this example, I'm going to access our links and then use addEventListener. Listen out for a click on any of these. This will then run a function, we're going to pass in the event information , create an alert. To access the contents inside of each one of these list items such as 1, 2, and 3, we can do this by accessing the events information, select e. target, which is the information about that particular list item which was clicked on, and then display the innerHTML of that element. Let's try this out. Now, if we refresh, have our free links at the top, let's click on Number 2, there's the innerHTML. Number 3, and also Number 1 works correctly too. This is a couple of really useful variance on the for-loop, which we can use to loop over things like arrays, and node list, and also objects too. 6. While & do...while: In my opinion, while loops look a little simpler than the four loops that we looked up before. The basic setup looks again similar to many other things in JavaScript, such as a basic function and if statements and even the for loop too. A while loop will keep running as long as a condition is set to true. For this example, we have a simple number variable and then the loop will keep running while the number is less than 30. This check is performed before the code in the loop is run, so if it's false the loop will then stop. As with the for loop, we also need a way of actually stopping things so it doesn't turn into an infinite loop. We do this inside of the loop by incrementing the value of the number by one on each loop. Meaning it will run 30 times before it then stops. Let's head over to our starter files and give this a try. The next lesson which we need is number 3. It is the while loop section. Open this up, and also inside of the browser too. As you can see, we have an empty starter file with the script at the bottom. What we'll do inside of here is set up a couple of variables. First of all, a constant called stadiumCapacity, and set this equal to a value of 100. This is the stadium capacity and next we'll set up a second variable, which is going to be for the number of fans which we've currently entered. Since this can be increased, we need to use the keyword and set this equal to a value of currentlyEntered, which will begin at the value of zero. What we want to do is to keep running a loop while the value of currentlyEntered is less than the stadiumCapacity. A while loop is ideal for this. We set up our while keyword, the brackets, and then the curly braces just afterwards. What we're going to do is to keep this loop running while the value of currentlyEntered, which is zero, is less than the stadiumCapacity. Basically, if zero is less than 100, the code inside of here will then run. Placing a console log with a text of enter, and we should be able to go over to the console and check this out. But just before we do this, let's take a step back and take a look at this loop. If we think about this, we want to take a look at our condition where they currentlyEntered is less than the stadiumCapacity. At the moment, we have no way of changing these two variable values. Basically this will always be the value of true. This will then result in an infinite loop and again cause a crash inside the browser. To only run this while loop a certain amount of times, we need a way of increasing the value of currentlyEntered on each loop. This is pretty simple. We just access our value and then use plus plus, which will increase this by the value of one on each loop all the way up to the value of 100. Once this gets to the value of 100 this condition will no longer be true, meaning this will then cause our loop to stop. Let's check this out inside the browser, refresh and jump into the console. Good and we see our text of enter has been repeated 100 times. The variance of this while loop is do-while. This is a switched around version of this while loop. Before inside the slides, I did mention that the code inside of this loop will always run after this condition has been checked. Basically, if this result in false, the code inside of this loop will never run even once. We can flip this and make sure that the code runs at least once and then perform the check afterwards. This is useful if we want to always make sure that the code runs at least once before the loop has stopped. To do this, just above our while section we'll create a do section. We'll say do, open up the curly braces, and since we always want this to run once, we just jump straight into the curly braces, we don't need to add any condition. Then we can grab our code from the while loop. Cut this out of place. Add this into the do section. I'm going to remove the curly braces from the while loop. As you can see, the code now sits inside of the do section, meaning this will always run at least once before we even perform our check. Our check is still true, this will keep running the second time, in our case, all the way up to 100. Let's check this. We can save this and refresh the browser. We still got the exact same results as before. We can test this by setting the value of currentlyEntered to be 100, which then sets this to be false. If we now save this and refresh, we see our single console log value of enter because our code runs first and then it will perform the check inside of the while loop. This is just an alternative depending on if we always want the code to run first or to first test the condition before running any code inside of our loop. 7. If / Else Statements & Nesting: For this video jump into the if-else statements section and also open this up inside the browser. You can see at the top we have a user object already setup and also if statement just below. So we've used if statements a few times already during previous examples. There's not a lot more to add to them than what we've already covered. They simply run some code between these curly braces. If the condition inside of here is set to be true. Using this example, we have a user object at the top. This would result in true since we have an object present, meaning our console log will work. If the user was logged out, it would maybe set our variable to be null, just like this, so that user to be equal to null, which would result in a false value and the code inside the if statement would not run. So here we are handling if the condition is true. But what about if we also want to handle if the condition is false? Well, this is where else statements come into play. We place these immediately after the if statement and this block of code will run in all of the cases which are not covered by the if section. We have this similar examples setup inside of the starter files and here we only handling the condition if the user is logged in. You may be thinking, why not just handle the logout condition below this. Or we could do something like this. We could do a console log or any code you want to, where we can say the user is logged out. Well, let's test this out and see what happens if we refresh and jump into the console. Here we can see the console log has run twice. We have the user is logged in and also the user is logged out. So obviously for something security sensitive, like a user being logged in or logged out, we only want one of these conditions to run. This, we can set up our if statements, which we have above, followed by the else statement. Let's remove the console log. I'm placing the else section and add our code inside of here. Let's refresh and we see user is logged in since we have a user object present at the top. If we also then change this to be the opposite and set the user to be equal to a false value of null. This should then be user is logged out. If we wanted to, we could also add in multiple if statements to and let`s just push our else statement down to the bottom. Then in-between we can add a second if statement, just like we did above. We can check a second condition such as a user or role, which is currently set to admin. We can check if this is a particular value and if it is inside the curly braces we`ll do a console log, say, Hey admin, test this, refresh. Now we see the user is logged in and they also the admin role. This works, but this also presents a problem too, we need to be really careful with this kind of setup. Because this else statement, which we'll have down at the bottom immediately follows the second if statement. This means now the else section will only run if the user's role is not set to admin, which makes no sense. So we had a user such as null, so with the we're not logged in. Refresh. This will now throw an error since we are trying to access the user dot role, which is no longer available because we no longer have our user objects. For this kind of use that example to make it a little bit more sense and to be more workable, we only want to check if the user's role is equal to admin, they actually logged in. To do this, we can nest our if statements by cutting out the second if statement. We can paste this inside of the first one. This brings us back to the first example. We have two top-level checks. We have the if statement, the user is logged in followed by the else section just below. Then the if statement which is nested inside, will only ever ruined if the user actually logged in. If the user is logged in, this console log will run. Then if they happen to be also logged in as the admin role, the second console log will also run too. Let's try this out. Refresh, and the error is now cleared. We see the user is logged out because the user is set to null. Let's reinstate this, the name to be equal to anything on the role back to admin. With this now in place, we now have a user. So the first console log should run. We also have a user role which is equal to admin. We should now see two console logs inside of here. This is how we can use top-level if else statements and also how we can nest an if statement inside too. If you wanted to, you could also go even further end just after the nested if section, we could also place in an else section too so we could do a console log. For this section, we know the user is actually logged in, but we'll want to also check if they are not the admin. So here this will run if they are the admin. Otherwise, we'll just say, Hey user, refresh. We still see hey admin since the role is set to this. But if we change this to be subscriber, the nested if statement is now false, meaning the hey user section will now run. If you want to. You could also go as deep as we wanted to by nesting multiple if else sections inside of the nested ones too. But we must be careful not to go overboard and make the code hard to read and also to understand for other developers too. As a general rule, we can usually cover most use cases without needing to go to deep. So if you find that you are maybe three or four levels deep with if statements or checks, there's usually a better way to do things. 8. Else if: Inside of this lesson's folder, which is the else if section, you'll find just below inside the script we have the same example from the previous video. Here we are handling two top-level conditions we check in. First of all, if the user is logged in and then else section capture what happens if the user is not logged in. Inside the logged in section, we also have a nested if else section too. Add a different greeting if the user is equal to admin. We have two options at the top level and also two nested options too. But what about if we wanted a third option too? For this, we also have else if. Let's take a look at this, we're going to simplify this example by removing the nested statements. Inside of here, we'll remove the nested if else leaving us with a simple logged in or logged out. If you remember from the previous video, we took a look at how to briefly handle a third condition by adding a second if statement, just like this. But the problem this gives us is the else section is now connected to our second if statement. Essentially, meaning our first if statement is now disconnected. If we still want to keep all three of these connected unrelated to each other, we can turn this second one into else if, some place else. Just before the if section, then we can add a second condition inside of here. First of all, we want to check if the user is logged in, and then using the double ampersand, we can also provide a second check. We can check if the user.role is equal to subscriber, and if it is, we'll then run the code inside of here. Now we'll just place in a simple console log saying the else if section has run, save this, and then over to the browser and we'll see what happens inside of here. We see the text of user logged in. You may be wondering why we see the text of only user logged in and not also the else if section has run because after all the user is present and also the user.role is equal to subscriber. Well, the reason is because only one of these sections will run. If condition has been met, the code inside will run and it won't go any further down the rest of these sections. Effectively, only the first match will be run. If we want it to be more specific with the first section, we could also copy this user.role drop this into the first section and we can also check if this is equal to admin. Since our user role is equal to subscriber, they should now be false. Because nowhere else if section to now run. Let's save this and test this out in the browser. The else if section will now run. Since this is our first section which results in through, so now we can do whatever we want in each one of these sections, we can show and hide content depending on the user's role. We can redirect them to an account area. We can disable features which the user may not be allowed to access or anything else you can possibly think of. We can also use multiple else if sections too. If we wanted to check more than these three conditions, we could also do the same just after the else if section, placed in a second one. It's probably conditioned from just above. This time, we'll check if the user.role is equal to author. If it is placed in a console log, give this a save and as you would expect, we should see the same result as before since we have the subscriber set, which is a match for this section. But if we now change this to be the offer, the if section is now false and then the first else if section is also false and our new console log with the text of author, would now run inside the console. Finally, if none of these, if or else if sections are true, so we change to be something like user, we should now fall back to use the else section down at the bottom. 9. The Switch Statement: Switch statement is a way to provide as many outcomes as we need based on a single condition. We can also provide multiple outcomes with if statements and if else statements like we looked at previously. But as we discovered, we need to add something to check against for each one of these conditions such as when we check things like the user's role for each one of these conditions. With a switch statement, however, we just test against the same condition for each one. Just here with our favorite pizza variable. The switch statement just below, again, looks similar in its setup to things like empty if statements and also for-loops. We then pass in what we want to check, such as our favorite pizza variable. Then inside, we then set up the different cases to handle what the favorite pizza is. Here we'll have three separate cases to handle what to do for each value. We can have as many of these cases as we want to. Let's look at the first one. We check if the favorite pizza is equal to pepperoni. If it is, we then run some code inside, such as this console log. We then provide the break keyword to break out of the switch statement once we have a match and this will stop all the rest of the code and all of the rest of the checks below from running. This is the same break keyword we used earlier in this section to avoid the browser creating an infinite loop. This will keep running until a match is found, but if one cannot be found, we can also add a default clause too. This will always run if there are no other matches. Over to the project and let's give this a go. This time we're in the switch statements section and inside the starter file, we'll just have a simple user object with the name property and also the role. We can set up a switch statement to check the user's role and decide if the user can edit something on our site. This, we can start it in a variable called canEdit. So canEdit is going to be initially set to a value of false, so the user is not going to be assigned any editing permissions by default. Then we can use a switch statement to check the particular role of the user. If the particular role of the user is equal to a higher level such as the admin or even an editor, we can then set canEdit to be equal to true. Just like we've seen in the slides, set up our switch statements and then we'll pass in the condition which is user.role. Open up the curly braces, then we can add our cases inside of here. The first case is going to be the user. This is just a regular logged in user. Add the colon. Then afterwards we add what we want to do for this particular case. Well, in our case we want to keep canEdit to be equal to false since they don't have the admin or the editor permissions. If this particular case happens to be true, I don't want to use the break keyword to break out of the rest of this switch statements. That's the first section. Then we go down to the second case and this one is going to be a subscriber. This would just mirror the same condition as above. We can set canEdit be equal to false. Add the break keywords. That's our second case now complete. The next one, we'll add a case for the editor. And as it sounds, the editor is a case where we want to allow the user to be able to edit. For this, we'll set our canEdit variable to be equal to true, then break out of the switch statement. Finally, the last case is going to be for the admin. In the Admin we do want to provide all the permissions which they need to then edit our site. Just like above, we'll set canEdit to be also equal to true and then break out of the switch statement. As we'd have seen in the slides, we also need to add a default case, which is going to be run if none of the cases above is a match. Very simple example, just place in a console log and we'll say the user role cannot be found. We'll also set canEdit to be equal to false. Now we just need to give this a test. When we first started off here we have the user role to be equal to user. This should set canEdit to be equal to false. Let's test this out by going down to the bottom, we'll placed in a console log, place in the value of canEdit. We'll see if this changes for each one of our cases. As we know no canEdit will be equal to false since we currently have the user role to be equal to user. Let's jump into the developer tools into the console. It's false as expected. Let's check our second condition by switching the role over to subscriber, refresh and as you would expect, this is false. The third one is the editor, this should now be true. Finally, we can test out the admin. This is true also. Just to catch the default condition down at the bottom, we should see the console log and they canEdit be equal to false if we don't have a match for any of these four conditions. Let's turn this to be something completely random. We'll just type in any random role inside of here. Refresh. This is false and the console log is now run as expected. Just one thing to watch out for if we have multiple matching cases. If I have two or more cases that both match, the first matching case will be used. Also as a shortcut if we have multiple cases, just like we have here, which run the same code inside. The user will set, canEdit to be equal to false and also the subscriber. This is a duplicated section, the same for the last two cases. Both of these set canEdit to be equal to true. We can shorten this code a little bit to make it a little bit simpler. For the first two, which are exactly the same, what we can do is remove the code from the first one. Both of these cases immediately follow each other. Then this code just afterwards will run for each one of these cases. The exact same for these two down at the bottom. We can move the canEdit and also the break. These two are essentially now grouped together. We can just test this out and if we refresh, we still see the default clause run at the bottom. Let's try the editor. It should be true. The admin true also. The user should be false. Finally, the subscriber. This is it for the switch statements. Just one quick thing before we move on. If we forget to put a break keyword in any one of these cases, all of the following cases would also run too until a break is finally found. For example, if we had missed a break clause inside of this section, we can remove this. If we have a match for the user or the subscriber, canEdit will still be equal to false but it would then run the code it just below, and then override the canEdit to be equal to true. Let's try this. We have the role equal to subscriber. Refresh. Now the subscriber canEdit has taken effect but the program has kept going down to the editor and also the admin section and cause an override so canEdit is now equal to true. 10. Conditional Operator (ternary): As an alternative to the if-else statements which we've looked at, Javascript also has a conditional operator, often referred to as the ternary operator, since it's made up of three parts. Since it works, just like if-else, the main reasons why it's used is to offer a simple single line alternative. Looking at this user object, we may want to check the user's age before allowing them in. The conditional operator can help with this. It's set out like a question. Here we're asking if the user's age is greater or equal to 18 using the question mark. Before, I said that the ternary is made up of three parts. The question is just this first part. The second and third parts are what we want to do if the question is true or false. If true, we can do anything but this simple example just has the text of enter. If it's false, which is correct for this example, the code after the colon will run instead. Let's now head over to the starter files and we can take a look at the example inside of there. Here we have an example of how we can use an if statement to check if a user is admin who can edit something on our site. The user object has the role of admin, and currently we set the canEdit functionality to be equal to false. The if statement is checking if the user's role, which is just here, is equal to admin. In our case, we can set the canEdit variable to true, allowing the user to go ahead and publish something like a blog post. If not, canEdit will be equal to false, removing any permissions which they may have. What we're going to do is to convert this example to make use of the ternary operator, which is going to simplify this example onto one single line. Just like we've seen in these slides, the first part is to actually ask the question. The question we want to ask is if the user.role is equal to the string of admin. Use a question mark, followed by our true and false outcomes. If the user is equal to admin, we want to set this canEdit to be equal to true, just like we do in the true section in the if-else statement. Set canEdit to be equal to true, then separated by a colon, we add the false statement where we say canEdit to be equal to false. Sometimes depending on your text editor settings or plugins, you may also see these two statements wrapped inside of the brackets. This is completely fine. What I want to do now is to comment out or remove the original if-else statements, and then we can save this and go over to the browser, refresh, and we see this example is set to true. This is true because the user.role is equal to admin. But if we change this to be something else, let's try subscriber, you should update this to be the value of false. We can also shorten this example even further too by directly assigning the outcome of this ternary operator to this variable. What we mean by this is rather than assigning canEdit to be equal to true or false, when cut the full conditional operator out of here, we can then remove the initial assignment of false, paste this in. Now rather than setting our variable, what we do is simply set the true value to be equal to true and the false value to be equal to false. Now the true or false result to this will be directly assigned to our canEdit variable. Let's test this out one more time. Currently we have this set to be false, but if we change this back to be the admin, this is now equal to be true. Both the conditional operator and the if-else version are both perfectly valid to use. The conditional operator, as we've just seen, is usually shorter and placed onto a single line. Some argue that an if-else statement is more clear and more readable, but in the end, it's your choice which you want to use, and which one you prefer. 11. Type Coersion & Conversion: In the upcoming few videos we're going to cover some type and also some true or false related things, which can give you some strange or unexpected results. Being aware of these could help you understand things like why and if statement is not running correctly, and also save you lots of time debugging. The first one is type coercion. We already know about types such as objects, strings, and Booleans. Type coercion relates to how the values of datatypes are converted to other data types. Looking inside the lessons folder which is type coercion and comparison, jump into the index.html where we have a simple example. We have two variables at the top with numbers and then we're going to add both of these together and store them inside of the total. One thing to notice between these two numbers is the first one is wrapped inside these quotations so technically this is a string. The second one is a number, as you would expect. But what do you think happens when we add both of these together? If we were adding together strings we may know what to expect, because this may be combined to make a sentence or a word. If we're also adding together two numbers, these two numbers would be added together to make a new total. But here, since we are adding a string and a number, what do you think will happen? Well, rather than cause an error, JavaScript is designed to choose one datatype to convert to automatically. This is called coercion. But this example it can choose to convert so they are both strings or they are both numbers. Well, let's not guess. Let's save this and go into the console and see exactly what's going to happen. Jump into the console tab and refresh and we see the value of 72. The value of 72 means that this is being converted to a string because we have the value of seven followed by the value of two, rather than the value of nine, which would happen if these were converted for both to be numbers. This conversion has happened automatically for us and this can be referred to as implicitly and this implicit conversion is what coercion is. Not to be confused, but something similar is type conversion. This works similar to coercion by converting a value from one data type to another. But we can also do this ourselves manually. If we wanted this to be converted to a number manually, we have a number function available. The way we can use this is to cut our number one, which is a string. We can access a number function and then place inside what we want to convert to a number. Here we convert a string to be a number. Now if we save this, we should see the value of nine in the console, meaning that both of these attract as numbers. To recap, coercion happens implicitly or automatically. Type conversion can also happen manually too, just like we're seeing with this number function. Sometimes these words are used interchangeably, but this is the official line on both of these. If you wanted to, we could also do the opposite. Rather than converting this one to be a number, we could convert the second one to be a string. We do this with the string function. Pass in the number which you want to convert to a string and this would then return back to the string value of 72. For this reason, it may be good to always convert incoming data to be exactly what data type we want it to be. If, for example, we're getting data from a third party, such as a server or an API, we can eliminate bugs and errors by making sure our data type is correct. For this reason, you may have heard of tools such as TypeScript, which enforces us to declare the type of data which you want to use upfront, which can therefore eliminate any errors in our code. This is how things work with the plus operator, but the other operators can also give us an expected results too after coercion has applied. We can also see this coercion in action with the greater than or the less than operator. See this will change the console log up with the value or the results of number one is greater than number two. Let's see what happens. We get the value of true. This may seem a little strange because here inside the console log, we're still comparing a string with a number. But in this case, JavaScript is comparing them as though they were both numbers. This is crazy behavior for people who are used to other programming languages, which is strongly typed. Meaning the data is constrained to a certain type and not converted. Although this coercion happens behind the scenes, sometimes the examples which we'll see have some pretty sensible or predictable behavior. But often we do see some strange results just like this. We can also see some strange results when it comes to incrementing too. See this, instead of having a constant for our string, what we're going to do is change this to be let. Therefore, we can update this value of number one. Let's do this just below. We'll access our number one variable then use plus plus to increment this by the value of one. Console log the value of our variable and let's see what happens inside the console. Refresh and we see the value of eight. This may seem strange because we know that number one is initially set to be a string. Technically we shouldn't be able to increase this by the value of one, like we would do with a number. What happens behind the scenes with coercion is number one is converted to a number therefore, we can use the incrementor. I think you'd see the value of eight in the console. As another example, imagine this was also an array. If we surrounded this inside the square brackets containing our string inside, what do you think would happen now in the console? We still incrementing this value. Lets say this and see what happens inside of here. Refresh. Again, this makes no sense. We still get the value of eight, but this is the world of JavaScript. What about if we commented out this plus, plus and directly added a value to this array. Let's say plus 2, save, refresh, and we see the value of 72. Again, this may seem like crazy behavior, but what's happened behind the scenes, as you may have guessed, is this has been converted to a string. If you wanted to prove this was a string, or if we wanted to double-check, we could also use typeof inside of the console log. I'll type of juice before our number one, save this and this will then output the datatype which is a string. Also here is something else really strange too. This is a string as we've just seen but what do you think would happen if we re-introduce the increments? Well, let's uncomment this out, save and refresh, and we're now back to a number. What about if we also remove the typeof and we can see what happens when we add together the seven and the two and then also use the increment. Let's save this. This now gives us the result of the numerical value of 73. Meaning that what happens originally for number one is our was 7 and 2 get added together to create a string of 72, just like we've seen earlier. This is still a string, but when it gets down to the next line, as we also seen earlier when we use the plus plus, it then adds the value of 1 giving us the value of 73 inside the console. In addition to all of this craziness, the equality operator also introduces a whole new world of things to watch out for two. For example, in our console log, we can check if 1 is equal to true. This is true. But what about if we convert this to be a different number such as 11? This now gives us the value of false. Just to recap, the value of one was equal to true, but the value of 11 was equal to false. Let's try one more number such as two, refresh and this is also the value of false. But this is another quirk of JavaScript, but just before we explain, I just want to add a few comments at the bottom. So true is number 1 and 0 is equal to false. To understand this better, we need to understand that when using the double equals, just like this, this is the loose equality meaning we're not checking for any datatypes unlikely triple equals, which we've seen before. All we're doing is checking if two values are equal regardless of the datatype. Since we are comparing a number here with a Boolean on the right, we're not checking it through equal types. JavaScript will convert using coercion and in this case it converts the Boolean to be a number. Just as we wrote before, the number one is equal to true and JavaScript will use the number zero to be equal to false. We can test this in the console log. We can check if the value of one is equal to false, which is not true. It should give us the value a false inside the console. However, if we change it to be the value of zero, zero is equal to false, just like we've seen below and it should then result in true. That's a lot of quirkiness to take in and it doesn't end there either. JavaScript has so many of these things which you have to watch out for. I don't expect you to remember them all at this stage. But knowing that this behavior exists and give you a good head start knowing where to look if you're encountering bugs inside of your code. 12. Truthy & Falsey: In a lot of these examples in this section and JavaScript coding in general, we check if a value is true or false. If it's true, we then run some code, and if it's false, we do something else. But it's not just a Boolean value of true and false, which we can use, as we've seen in the last video other values can also evaluate to be true and false too. Such as zero evaluates into false, and the number wants to be equal to true. There are also many more examples too, such as a string of text is true, and an empty string is the opposite of false. This is referred to as truthy or falsey. Truthy is when a value is evaluated to be true, such as our string of texts being present, and falsey is when a value evaluates to false, such as our empty string or our number zero. Jump into our editor, and we can take a look at some examples down inside of our empty script. If statements will run for not only a Boolean value of true but also any other truthy value too. Let's say this by first setting up an empty if-else statement then inside of here, we're just going to place in it too simple console logs. For the first section, we're going to evaluate something to be true, we'll pass in the text of true V. In the L section, will do the opposite. Adding the text of falsey. Of course, this won't run at the moment because we don't have any condition inside the if statement. But we'll start with what we already know. Previously we looked at the values of zero and one, where the value of zero is equal to false. This would be evaluated to falsey, however, the opposite is true with the value of one. Also, we can test the string which you mentioned just before. We have a string with some contents inside, such as the text of hey. This will also evaluate to be truthy too since we have some value inside the string. But if we were to remove this and have an empty string, this would evaluate in JavaScript to the value of falsey. The coercion we've talked about is happening behind the scenes, and values such as our numbers zero and one and also this string value here is being converted to have a Boolean equivalent. We can determine if things like these if statements are to run on not. Falsely values, as you would expect, are generally empty values such as zero, which we just looked at, and also these empty strings too. Let's take a look at some more examples such as no. This is also falsey. Undefined this should also be falsey too. Generally, anything which doesn't have a present value, so the word false. As you'd expect, this would also evaluate to falsey. Finally, note the number, which is NaN. This is also falsey too. We can consider pretty much everything else to be truthy, such as the strings which we just looked at, arrays, numbers other than zero, and in fact, any object type such as a function, array, or an actual object will result to be truthy. This is also true regardless of if we use the constructor or a literal type, just like this. We could use the constructor. We've looked at things like new array, and new object in the past. This will be truthy. Let's try a function constructor which will also be truthy too, and finally the object. In the exact same way if we want to use a constructor like this and we use this literally like we have done more commonly in these videos, such as creating an array with different values inside. This would be truthy just like the constructor, along with placing in an object in a literal font too. This coercion, combined with understanding how values are converted to be truthy or falsey, is a good thing to understand inside of JavaScript since it can really help you out to both avoid problems in the future and also help with debugging issues too. 13. Optional Chaining: This video is going to focus on something called optional chaining, which was introduced in JavaScript in ES2020. As we already know, we need to have access to certain some inside of an object, such as our name and also our role of admin. Also as we know, we can go even deeper by accessing objects nested inside of an object too. What happens when properties inside of this chain are not there? Look at some examples of chaining in the events section, where we access the event object. We then went deeper into properties such as the target, the parent node, the children, and then into the inner text value. If at any point in this chain a property does not exist, we would then get an error. This is not a bad thing though, as we should get errors if we do something wrong. But what about if the property is only sometimes there and sometimes not? An example of this is what we've been using already inside of the script. It will have the current user which is set to a logged in user object and we have all the information which we need, such as the name and the role. Therefore, when we go down to the if statements and check if the user's role is equal to admin. We know this should work without any errors, but with users though we don't always have them to be logged in. The current user is not always set to be an object like this. For example, if the user is not logged in, in place of this user object we may see the value of null. Now, if we try to run the if statement, we don't have access to this.role property. Therefore, let's go into the console and see what happens. Inside the console we see this red error message, which tells us there's a problem with reading our role. This happens because the current user is no longer an object which contains the role property, therefore causing an error. But we still need a way to keep this role active inside the if statement. But after the user has logged in. This is where optional chaining comes into play. What we can do is we can insert a question mark to declare the property may not always be there. We add this just before.role. Now if we save this and refresh instead of the error inside the console, since it's now evaluates to false, the else section will now run inside the console. What happens inside of here is we get to the if statements. JavaScript will then read the current user, which is the value of null. Therefore it knows not to go any further with the rest of our chain. It now skips the error and instead it returns back a value of undefined, which we can check inside of the console log. Currently we know the else section is running because we've seen the value of false. But instead what we can do is we can access the current user, a question mark since this is not always going to be there at the optional chaining. Then we can add on the value of the role. If we save this and refresh, we can now confirm we get back the value of undefined. This is really useful if we know upfront a certain object property may or may not always be there. It's common for objects like this to grow over time and we don't always know how our app may develop in the future. We may need to add extra features or collect more information. This optional chaining can avoid any errors. For example, in the future we may need to add more information about the user's sign up source. We could add a nested object inside, just like this, we will return back to the user object. Let's reinstate the name and the role. Then a second nested object inside which I'm going to call the sign up data, this is going to be a nested object inside. We will place in the date. But now an empty string is fine. It doesn't really matter and confirmed to be equal to true. Then even further down the line as our app developed even more, we may need to go even deeper into this object. For example, we may want to collect further details about the user's sign up source inside of this object. We may also add the source, which is also an object where we saw the URL of the sign up source. Again, this is just an example so we can add anything inside of the string on the browser which the user came from. Now we need to longer chains to access this nested information. If we just remove these if else statements, and we'll simplify this with a console log. We need to first access the user objects, which was current user. The object inside which was sign up data, so.signupdata, For example, if we wanted to access the browser, we'd also need to jump into the source just before this. The source object and then the browser, refresh and this should now be the value of Chrome. But remember in this example up, all of this was added to the object at a later stage. Some of the earlier sign up users won't have the sign up data associated with their objects. What we can do, we can simulate this by commenting this section out, which will then cause an error, just like we've seen before. Again, optional chaining can help us out with this by allowing our code to fail silently rather than displaying an error inside the console. Inside the sign up data would no longer have access to the source or the browser. We can add the optional chaining inside here, refresh and now we see the results of undefined. Overall errors are good to let us know when we've done something wrong. But in cases like this one, we know we have a property which may or may not be there, optional chaining can really help us out by failing silently and therefore allowing us to handle the errors ourselves. 14. Creating & Modifying New Objects: Pretty much anything we can think of has certain properties can be a good use case for an object in JavaScript. For example, a person can be an object and the properties could be the name, age, height, and any other piece of information which we want to give to a person. A computer could be an object too with properties such as the brand, the model, the CPU, the year of manufacture, and also the memory. When we think of objects like this, the use cases become huge. As with arrays, there are different ways to construct an object, and the style we've looked at so far is called the object literal. This is used to create and define a new object with the curly braces, which includes some properties, just like we have here. Over to the start files. Jump into this lesson's file, which is the object constructor, and open this up inside the browser. As previously mentioned with the slides, we have two different ways we can create an object. We have the literal approach, just like we've used previously, and we also have an approach called the constructor. The constructor is nothing new. We've looked at this previously with arrays. Typically, we've created arrays using a literal approach, such as a pizza array, and set up our properties inside of these square brackets. As well as this literal approach, we can also create an array using the constructor. For example, if we wanted an array of ingredients, we can set this up using the new keyword followed by array. This is a literal approach and this is how we can create an empty array with the constructor. We can then access our empty array and add new values with methods such as push to add any new value to this array. In the exact same way as our arrays just here, we can also do the same for other objects. What I'm going to do is to comment out this literal approach and recreate this using the object constructor. First of all, we'll create a new variable called user to mimic the above objects and set this equal to a new object. This new object is going to be an object wrapper which is empty, and then we can go ahead and push new properties to this object. We do this by accessing our variable. Then we can set the name of the property directly to our object. First, It's going to be the key, just like we have here. Then we assign this to a certain value. This is equal to a string of Chris. Then the second one is for the last name, also a string. The third one was the occupation. Next, we have the logged-in Boolean of true for user.logged.in. This is a Boolean so we don't need the quotations. Then finally, we can also assign an array to all foods property. I'm just going to copy this array from just above. We can test this is now working by doing a console log for the value of user, and then jump into the developer tools into the console. There's our object with all of our properties nested inside. We can also access individual properties too using a dot notation. This works exactly like we did with the literal approach. We can use user.first. This will print out our first name inside the console. As well as this dot notation, just like we've used previously, we can also access our properties with the bracket notation too. What we need to do is to surround our property name in these square brackets, remove the dot. This also needs to be a string. Both of these give exactly the same result. If we wanted to, we could also directly update one of our properties too, so user.first. We can then reassign this or update this to be a new value. Then we can print this out to the console. This will give us our updated value. As a side note, if we accidentally have more than one property which is a duplicate, just like here where we've got the first name twice in our code, since ES 2015, the last occurrence will be used rather than throwing an error. As well as this, we can also delete any one of these properties using the JavaScript delete operator. What we need to do is to add delete, which points our first name, save this, and refresh, and we'll just print out the full user object. Open this up, and this will now remove the first name from our use object. These is two different ways to create an object in JavaScript. Personally, I prefer the literal approach which we had at the very top since to me it seems more clean and simple to use. But this is completely down to your personal preference. In upcoming videos, we'll cover how to set up a template-like function for creating multiple objects. 15. Object Constructor Function: Great. We're now aware of two different ways of creating objects inside of JavaScript. If you jump into this lesson's file, which is object constructor functions, we see we just have an empty script inside of here. The two different ways which we've created objects is to create a new variable just like this, and then we can add our properties directly inside of the curly braces. Alternatively, we can also use new object, which is the constructor approach and this will give us an empty object at our properties too. Both of these approaches work fine, but they're also limited to only creating a single object. It would be more helpful if we could have a object template so we can create multiple objects based off this, each showing the same properties and methods. We can also do this with the constructor function. What we'll do is we'll remove this and create a new constructor function. It's also good practice to name these constructor functions with a capital letter. We use in our user example, it's an uppercase U, and then create the rest of our function. The purpose of this constructor function for our user is to create multiple users based off this template. Inside of our function, we're also going to pass in some values which we're going to need inside of here. The first one, we'll keep this pretty simple, we just say first, last name, and occupation. We'll come back to this function in just a moment. But before we created a new object, just like this, so we used the new keyword and then the object function. But now instead of creating a new empty object, we want to create a new instance of our user. Rather than new object, we'll say new User capital U, where we're going to pass in the actual values which you want to use for our function. We need to pass in the first name, the last, and the occupation and these are going to be the actual three values we need for our user. We'll say Chris, the last name, and finally the occupation. We can also duplicate this as many times as I want to, because as we mentioned, the whole purpose of creating this constructor function is to act as a template to create as many objects as we want to. We create our second one, has a different name, and also eight different occupation too. With both of these new users, we can also store this inside of constants or variables so we can access them later on. So say const chris equal to our one, and then the second one is equal to homer. Great. Now what we're going to do is to log the value of any one of these new users. Placing a console log, the value of homer, and then jump into the console. As you can see, we've got a user object. But if we open this up, we don't have any properties inside of here. All we have is an empty user object. This can be expected because our constructor function which we created earlier is empty. We don't have any code inside of the curly braces. We receive in the values inside the function but we're not actually doing anything with these just yet. To do this, we need to set something to be equal to these three values. We need to set something to be equal to our first, some things to be equal to our last, and something to be equal to our occupation. But what do we do to turn these into our object properties? Well, to set a property, we need to make use of the this keyword. To understand the this keyword a little bit better, I want to quickly take you back to an earlier file in this project folder. If we jump back into number three, which is functions, and then number five, which is a function or a method, jump into this index page just here. Inside of here, you may remember we created an object called check recipes. Check recipes had some properties such as the current number of recipes, the maximum recipes, and also a method called recipes left, which deducted the current number of recipes from the maximum. Remember a method is just a function which is located on this object. Inside of this method, we made use of the, this keyword to access other properties on this object. We access the max recipes, which is on this object and also the current recipes too. The this keyword can be a complex thing to understand in JavaScript, but in these circumstances, it will simply point to the object which owns here. Meaning we can access any of the other properties inside of this object. With this in mind, back to our current file, we can now add all properties in the exact same way by using the, this keyword followed by the property name. For the first will say this.firstName and also the same for the others too, this.lastName, and finally, this.occupation. This will now construct our two user objects with the properties which we pass inside. Save this and with our console log still in place, refresh. Our Homer user is now constructed correctly and we can also duplicate this for our first user to. This now gives us two unique objects, which are both based off the same template. If we need to add extra properties and methods, we have some options too. We can add them directly to one of our objects like this. Just like we looked on the previous video, we can access our variable such as homer. We can say lives, and set this equal to our value. We can also add methods to our objects too. We can access our object, which is homer and then we can give this a property name which is going to be full name and set this equal to a function. The responsibility of this function is going to be to return a new string, which is the first name added to the second name, so return our string, which is homer.firstName, add an empty space in-between and then add onto the end homer.lastName. Let's give this a try. First of all, we'll try the lives property. Add this to the console, refresh and we get the value of Springfield. Then next we can try our method which was full name. Refresh the browser. Whoops, we've got a value of undefined so let's check this out. We've got homer.firstName, that's fine. Just a spelling mistake up at the very top of the air so we'll change this. Now we see this is Homer Simpson this so this is working completely fine. But these are only added to our single objects. These are only added tall Homer variable. If we did try to access in our Chris variable and try this in the console, we see an error inside of here. This approach is only useful if you want to change one specific object. If we want to make these apply to all of the created objects, we do need to place these on the constructor function at the top. So first of all, we need to pass in the property of lives to our function and then we can add these to our two objects below. Chris, value of UK and Homer, the value of Springfield. We also need to modify our function body. We'll duplicate this and we'll say this.lives is equal to the value of lives which you pass in. We also need to pass in the method too. The method will always be the same, it's just using the existing first and the last name. I'm going to just cut and paste this into our function. Cut this, paste this into our function. This time we're going to remove homer, replace homer with the, this keyword. Also the same inside of our function body too. Remember, just like the previous example in the earlier video, this keyword will point to any other property on this user function. Finally, we can also remove homer.lives. We no longer need this, so now we can save this and refresh. Now the full name method works for both of our objects. 16. Object Prototypes: If you did not quite understand the role of the prototype in the early videos, hopefully now seeing it in action with our own objects may help to make some things click. In the starter project, we begin with the object prototype section with the same example from the previous video. We have a constructor function to create templates or blueprints. This means we can create multiple objects with the same properties and methods available. We then looked at how to add properties and methods, both for a single objects and also to the function so they apply to all new objects created. Along with adding to the constructor function, we can also add directly to the prototype too. But before we do this, let's first refresh what we know about the prototype. Down to the bottom, we're doing a console log with the value of homer, which has created a new user object from our constructor. If we open this up inside the browser and jump into the Developer Tools into the Console, and let's take a look at what we see inside of here. Refresh, and we see our user. Let's open this up. It contains our properties. We've got the first name, the last name, and all of the values which you see down at the bottom. Then down at the bottom we have this prototype, which is a link to the prototype chain. Open this up. Inside, we can see our own constructor, which is our user. Also alongside this, a second prototype objects. The first protocol, which is the one up at the top here, this points to our own prototype additions, which we'll look at soon. Then the second one which we just opened up, this has now lots of things inside of here, which we didn't add ourselves. We have things like valueOf, toString. These are not things which we created ourselves. Remember, from earlier, JavaScript objects inherit properties and methods from parent objects. At the very top of this inheritance chain is the object. Let's now log this to the console for reference. Just with Homer I'll do a second console log with the value of object. Now let's save this and refresh the browser, leaving us with the main object type alongside our own home object. This first object value is an empty object, which you can see if you open this up. It's empty in terms of having no properties of values inside like we have here. But the purpose of this top level object, even though it's empty, is to contain the bare minimum properties and methods that pass down to other objects through the prototype chain. We can see this if we open this up. This contains all of these properties and methods which we can now have access to through our own created objects. If we now open up our own home object, go down to the prototype. Then the second prototype inside here, you can see this has inherited the same properties and methods from our top level objects. This now means these are now available to use in our own custom objects. As we looked at earlier, this is why things like custom arrays have methods available, such as for each push and pop. We didn't actually create these methods ourselves. But instead, they are inherited from the prototype chain. All the rays can make use of them. We shouldn't add our own properties and methods to objects which we've not created ourselves, but we can add them to our own custom constructor, such as this user. We can do this by accessing the prototype property on this user. Just below this. Let's make some space. Access our user constructor. Then the prototype. We can set a new property on here, so any value. This can be other data types such as strings, numbers, or even methods. We can also remove the first object, leaving our second homer object in place. Refresh, open this up, jump into the prototype. Now, I'm going to open up this prototype object. We also see the custom property, which we have just set. We see cool is not placed on the original object alongside the first name, for example. But if we try to access it, cool, then be looked up on the prototype chain. If it was not on our prototype chain, which you see here, it would look even further up the inheritance chain. We can test this out. Jump into the console log. Now, homer.cool. Remember,.cool is not available on our original constructor. It's then going to look down the prototype chain, refresh. We get the value of true. The same goes for methods too. We can also add different methods to the prototype. Rather than having this method available on our constructor, what I'm going to do is to copy this and comment this out. Paste this outside of our user. This time, rather than accessing the object through this, we're going to access our user.prototype , just like we did before. This time, full name is going to be equal to our function. Let's test this out down in our console log. The name this time was fullName. With this being the method, we also need to access this with the brackets. This should now return our firstName, added it to our lastName. Good. If you also want to check this is on the prototype alongside cool. We can remove fullName. Log to the console, the value of Homer. Open this up, jump into the prototype, and our two new editions are inside of here. To begin the prototype may seem complex, but it's just a way to inherit properties and methods from a parents object, even from a parent which were created like our user, or from the top level object which JavaScript provides. To recap, the prototype is a property on an object. It will make available to be inherited by other objects. An example of this was our fullName and our cool additions. Both of these were added to our prototype, meaning these have now been made available for other objects to inherit, such as our Homer user down at the bottom. 17. Inheriting Object Properties: We've talked a bit so far about how we have this main parent JavaScript object, which has a prototype, and how one would create new ones they automatically inherit certain things through the prototype chain. But what if we wanted to also allow our own objects to be inherited too? In a start files we have a similar user example from the previous video. We have a user object, and we may begin to realize that this user object has some limitations for our particular use. Here we are creating real people such as me and also just below a fictional character. But if we think about this, real and fictional people may need different properties. We may, for example, want to add the name of the show which the fictional character was from. But this would not apply to a real person. This now makes it difficult to expand this object much further. What we can do though, is use this user object as a base, including only the bare minimum properties which apply to both the real and the fictional user. Then we create two more objects, which will both inherit from this original user. We still have access to all the things like the names and the occupations. But then it will also have specific properties which we need for each use case. To do this, we have an object method called create. Just before we add this to our current example, let's take a look at how we can do this with a regular standalone object. First, let's add any regular object down at the bottom. Remove our console log for now, create a new object called product1. Open up the curly braces and we'll add our properties. The title, again, this is pretty generic, so an amazing blue shirt. Also the description. Simply all blue shirt. As a standalone object is a generic object which could apply to multiple blue shirts. The title and also the description will be fitting for other blue shirts. We could also change some details such as the brand or size for other products. We could then use this object.create method we mentioned before to create a second product based on this, install this inside of a variable called product2 and set this equal to object.create. Inside of object.create, we pass in our product1, meaning it will create a new product called product2 based off our original product1. Let's log this to this console, product2, and see what happens inside of here. Refresh. Let's just update this link inside the browser. Initially, we see an empty object. We don't have any properties or methods associated with this. But if we go ahead and open up the prototype which is attached, we have access to our title and also our description which is inherited from our product1. This is how the create method works. It creates a new object and uses the existing object we pass in as the prototype. Again, notice how we also have a second prototype too. We have our own first, which is the description and then title. Then further up the chain we have all of the properties and methods which we've seen earlier, which is inherited from the top of the chain from the object. As we've already learned, even though our own object is empty, we can still access these inherited properties from product1 by their name. product2, remember this is completely empty as we've just seen in the console. We can access the inherited values such as title. We can also add our own properties and methods too, as you would expect. Just underneath our product2, we can access this by the name and then set new properties such as the size, such as small. Log this to the console, which then updates our object. Now we can remove all this example and we can use this knowledge which we've just learned. We can now try to apply the same example to our user. But the key difference here is we have a constructor function rather than an actual object. If we were to do the same as before, let's create a variable called copy, which is set to object.create. Then if we try to make a copy of our user, let's see what happens inside the console. Save and refresh. The copy is a copy of the function, which is not what we want. What we're looking for is a way to create more constructive functions which all inherit the properties of this user. Let's start with the character. Just below our user, create our new object constructor called character. Remember the purpose of this function is to inherit all of the base properties from our user objects. We're also going to add some additional properties which only apply to our character. This extra information which we're going to pass in is the show which the character is from. Then just like above, we'll access this.show, setting this equal to the value which is passed into this constructor. Now, what we do is to create a new character object with the show property and also inherit all of these properties too. But this, we need to go into our character and first access our user constructor function, which we can then access a call function on. This call method is available on a function's prototype and it allows for a function belonging to an object called inside of a different object. Meaning, we can now call a user function from inside our character function. This call method is not exclusive to this use case. It can be used anytime I want to access a function or a method located on a different object. This user function also takes in these four parameters. We can copy these and also add this to our character. Now, remember Homer is a character, so rather than basing this off the new user, we're going to base this off the new character. As the fourth arguments I'll show, just after Springfield, we can pass in our last value, which is the Simpsons. These five values now match the five character values passed to our constructor. Let's try this out. We can remove our copy from before, and instead we'll log the value of Homer. This now shows that Homer is a character object. It has the show property with the value of the Simpsons. We know homer.show should now also work. But what about the other inherited properties? We could see before the Homer object it would only had access to the show property on the top level. We didn't have anything else such as the firstName and lastName, the occupation or lives. Well, let's try this out and see what happens. First, try the occupation. Refresh, and we get back the value of undefined. Let's try one more. homer.lives and this is also undefined too. The inherited properties don't seem to work here. This is because we're missing some details when calling our user function inside of our character. First of all, we need to copy over all of these parameters which are passed in and also add this to our call method. But in addition to this, we also need to pass in this keyword. We mentioned earlier that this keyword can be complex thing to understand. We'll have more on this later. But this is basically saying that when running our function, we can access the values using this. Just as we were above. Scrolling down, we're still trying to log homer.lives. Let's refresh this and we now get the value of Springfield. We can try one more, the firstName. This is all working correctly. Just as a recap, because this can be pretty confusing, we're creating a new Homer object based off our character. This character constructor function only has one property of its own, which is the show which the character belongs to. But it's also inheriting all of the properties and methods from our user objects, which we are passing in just here. In fact, we also don't need to add this shows since it belongs on this particular function. With all of this complexity, if we want to check which one of our constructors created a particular object, such as Homer, we can use something called instanceof. We can check this inside the console log. We can check if the homer object is an instanceof character. Should be the value of true since we're basis of our new character. But if we were to pass in our user, this one will be false. This is how JavaScript does things. It has objects right from the very beginning that we can inherit it from. As a newcomer, we don't even know this is happening behind the scenes. But if we were to dig a little bit deeper like this, we can begin to understand that this is so each new object, objects also referring to other types such as arrays and functions and have a set of helpful properties and methods which we can use each time we create our own objects. As we just discussed, we can also take advantage of this prototype inheritance by our own objects if needed. 18. Copying Object Properties: In the past videos, we've gone pretty deep into objects with things like object constructors, and copy and prototypes. But sometimes we simply just want to copy the properties from one object over to another. There are a couple of different ways to do this. First of all, we have the base character with information which could apply to all new Simpsons characters we create. Pretty generic information, and then below we also have a homer object with some properties which only apply to this one character. For homer and also any other characters which we create, we also need to merge in all of the properties from the base character too. A straightforward way to do this is just to reference this base character inside of the homer object. We got add this as a property, has it in the base character, and test this over in the console. We already have a console log for the value of homer. If we open this up, we have the four original properties and we also see our base character. This works completely fine, but it does create a base character object which we need to open up and dive into. Our base character is nested one level deeper than all of our other properties. But it would be better if we could grab all of these base character properties and effectively put them alongside what we already have. One way of doing this is by using objects spread, which we looked at earlier, which was the three dots. Passing the three dots before our base character object. Now we don't see the base character object which we need to dive into. Instead, we see all of the base character properties alongside our homer ones. We could also use this technique to spreading as many different objects as we wanted to. For example, if we had a homer Simpson character with superpowers for one particular episode, we could do something like this. We could create a new object called a superHomer. SuperHomer would also need to inherit the base character and also all of the existing information from homer. We can also remove this too. We can use spreads pass in both of these objects. The base character and also the existing homer information. In addition to this, we can also pass in our own properties, which is specific to this single object. For example, we could set powers to be equal to true, and this should now display one big object inside the browser. Let's just change over our console log to be superHomer. Refresh and now we have nine different properties on this object. We have the fall from the base character, the forefront of Homer object, and also the powers set to true. We could remove or comment out this object, and we'll now take a look at another way to copy over the object properties to a new object. This is done with an object method called assign. Access our main object, the assign method. This is going to take in it two things. First, the target object which you want to copy to. We'll copy it to our homer object, and the second one is the object which you want to copy. Using our original example to move all the properties from our base character into homer. Pass this in as the second value. In the console log to be homer. Jump into the console. This now merges all the properties from base character into our homer object. Effectively works just like the spread operator which we looked up before. Also if we needed to, we can store this new object into a variable such as mergedHomer. This should also work exactly the same. This assigned technique and also the previous ones, are really useful and something which you may often use in JavaScript. It has lots of use cases such as if we had a user and an order, we may want to attach a user object to our order before saving to the database, so we know who actually placed the order. You will also probably find many use cases of your own too. 19. CSS Style Objects: In the DOM section, we created our own HTML elements. Then we looked at how to add CSS styling to these elements using JavaScript. In the Style's file we have an example of this down at the bottom, a simple header section with a title no meat burgers. Then below this inside of our script we have multiple style properties applied. This works fine as we can see inside the browser, but it can be a pretty long way of doing things. It's not re-usable on other elements either. A solution to this is to create a style object containing all of the CSS properties and values which we need. Let's go down to the bottom and we'll comment out all of these existing styles and we'll recreate these inside of a style object. Store this inside of a variable called styles. Say this equal to an object, and we'll effectively replicate these inside of here. First of all, the display is equal to the value of flex. Since this is an object, we need to separate this with a comma and the next one is justifyContent. Since this is JavaScript, we also need to make this camel case, justifyContent and every word after the first one needs to begin with a capital letter. The value, this can be the same, this can be space between. Next, we have a padding value. Again as a string, zero top and bottom, and 10 pixels on the left and right. Background. What do we have here? We have an RGB value. Let's copy this over. Finally, the color. Let's grab the value which we already have , paste this in. Let's go over to the browser and refresh. We don't have any styling applied. Now we need a way to actually apply the style object to our header element. Just like the last video we can use object.assign. This will copy all of our style object properties over to this header element. Down at the bottom of the script object.assign. We want to apply these to the header. The object properties which you want to apply is our styles. But just as it is like this, it doesn't work if we refresh the browser. The reason why is just like we did originally, instead of applying these to the header element, we need to apply these to header.style, so at.style and refresh and it should now all take effect in the browser. At the moment you may be a little bit confused as to why an object method such as assign is working on an element such as header. Well this is because our elements, like many things in JavaScript are also classed as objects. We can see this with a console log. We can use the typeof operator, and the value of header. Then let's see what happens inside the console. Refresh and you can see that the header, even though this is an element, is a type of an object. When we create new elements, we're actually creating element objects and this is how we can have access to properties, methods, and events. We've already used properties such as accessing the attributes, class list, and inner HTML to name a few. Methods which we have used include queryselector and addEventListener. These are all available on this element object. But why create a style object instead of regular CSS? Well, CSS is probably easy for many use cases, but this way has its own uses too. The main one for me is the fact that it is controlled with JavaScript. We can change values dynamically. If we had a game, for example, we could change the background to be red if the game was over. We can make a count down flush faster as it's getting closer to the end and so many more great use cases by updating any one of these values dynamically. 20. Looping With Objects: Objects can have many values as we know and just like with arrays, looping is a convenient way to repeat something for each property. There is a couple of different ways we can use to loop over objects, and first, we take a look at the for-in loop. Inside of this lesson's file, we have a constructor function up at the top, which we've seen before to create a new user. Notice the prototype additions are commented out and we'll see why soon. For-in loop should look pretty familiar. We've already looked at this in the loop in section, but I want to show you something else related to it. As a refresher, this is how it looks inside of our code. It begins with the for keyword, and for this example, we're going to loop over our homer object. We need to create a variable for each one of the properties inside of here, so the first name, the last name, the occupation, and lives. This inside of a variable or a constant called property inside of our homer object. Now we'll just open up the curly braces and then inside here, we can do anything we want to with this property. But now we'll do a console log, open up the back ticks so we can insert our property variable, which is our property name, such as first name, add a colon, and afterwards we could also access the value of the property. Again, we'll insert this as a variable so we need to access our full homer object, and inside the square brackets, we'll pass in the property we want to grab the value of. Save this, refresh, and we see each one of these four properties inside the console. We see the actual property names such as first name, and then we use this to select the property value from the homer object, such as homer. We can then use these values to construct elements to now add it to the DOM. First, an unordered list is required, which we can use as a wrapper for all of these values, so jump up to our body section outside the script, has an unordered list, and the first step is to grab a reference to our elements. Const ul is equal to document.querySelector, pass in our unordered list. This now gives us two things. We have a loop, so we're looping over all of the properties inside of our object, and now this gives us an element to attach this to. With this being an unordered list, we need to create a new list item for each one of these values. Const li for our list item, we'll create this with document.createElement(). An element is in li. Remember when creating new elements, this is generally a three-stage process. We create the elements, we create the contents, such as the text node, and then we merge these together. The second part of this is for the text which goes inside of our list element. We do this with document.createTextNode(), replicate what we've seen inside the console. All we need to do is to copy the contents from inside of here, and paste this inside of our method. Remove the console log, merge these together by first accessing our elements and use the method called appendChild. We will pass in our text. This has created a new standalone elements or a standalone list item, and then for each loop we need to merge this or insert this into our unordered list. Just like we did above, we'll grab our unordered list and use the appendChild. Passing it the list item we just created. Save and refresh. There we go and this is a really good way to structure our objects to show inside the browser. But back to this prototype, which you mentioned before, which is currently commented out. If we uncomment this out, let's save this and now again, refresh the browser. We also now see these two prototype values inside of here. This is something we need to watch out for and if we don't want to loop over these prototypes, which is often the case, we can eliminate them using an object method called hasOwnProperty(), which we can use inside of the loop. Let's go down to our for-in loop, and at the very top, add an if statement. We will pass in homer.hasOwnProperty(), passing in our property variable. What we're doing here is we're accessing our full homer object and then checking each property one-by-one. We are checking if the particular property belongs to this homer object, or if it is inherited via the prototype. If this is true, we want to run our code below. If not, it will be a prototype value and therefore ignored. We can now cut this out of place and add this inside of our if statements. Refresh, and this is a way to ignore our inherited prototype values. Another way of looping over objects is to first convert them to be arrays. Object has some methods available which you can use to do this, and depending on if you want to access the object's property, the value of both of them as a pair. Let's begin with a method first called entries at the very bottom, place in a console log for objects.entries(), and our object value of homer. Test this out, jump into the console, and it still returns back in array. Not only is this returning back in array, each one of the properties is also an array too. It contains the property name and also the value as you can see here. This method does not include the prototype values like it does with for in. If we were using this, we could ignore the if statements that we have just here. To give this a try, and keep the same example, up the for in example, and then comment this out. Paste this in just below. I must mention, we don't need this if statement since we don't need to eliminate any one of the inherited prototypes. Remove the wrapper, leaving these four lines inside. This time rather than it looping over our homer object, we're going to now make use of object.entries. We're going to move this, and just like we did inside the console log replacing objects, data entries with the value of homer. Save and refresh. Inside the browser, we see the values of undefined. This may not be obvious at first to why this is, but this is because of the type of loop we're using. We currently using a for in loop, which is used on objects. But now we're converting homer to be an array. This now means we need to make a small change and instead use a for loop, so change in to be of, and remember now this property, instead of returning a single property as it was before, is now going to point to an array which contains two values such that our first name and homer. What we can do instead of this is to D structure using the array, which will give us the key and also the value. The key in this case is equal to first name, and the value is going to be equal to homer for each one of our items. Pass this in. First of all, the key, and then also pass in our value. Save this. Reload. This again works as expected. This is a really good way of looping, which doesn't involve the prototype. If we want to, we can also access the keys, all the values individually too. The way to do this. As an example in our console log, if we just want to access the keys such as first name and last name, we can use an object method called keys, where we pass in our homer object, and there's our four keys without the values. On the other hand, if we just wanted to access the values and not the keys, we can use object.values, and this will return this back inside the console. This is also commonly used in if statements just like this. We could say if object.keys(), pass in our object, and access the length property is greater than zero. We can then do something inside of here. This checks if an object is not empty before running some code, and it just depends if you want to access either the key, or the value, or both. 21. Dynamic Objects: This video is going to convert creating more dynamic objects. By that, I mean both the key and value can be changed using JavaScript. When we create new objects, just like we did with this home object, we're using simple primitive value such as strings, but our programs are not always going to be this rigid. We may also need to insert data which may change, such as a variable. Also, even with the key names such as firstName and lastName and occupation. This could all be dynamic too. I'm going to now show you some ways to do this. First, the more traditional ways, and then a way which was introduced in ES2015. We begin by inserting variables as values, and this is pretty simple to do. Let's first create a variable called firstName and set this equal to homer. We can then reference this variable inside of our property value when we create our new homer user. Remember, since we're now referring to a variable rather than a string, we need to remove the surrounding quotes. Save this and refresh. This works just like before, but this time we are now pointing to a variable. We already know we can add new properties also like this. We can access our object, access the likes property, and set this equal to a string. Save and refresh, and this is also added to our object. Currently, value of likes is set to be a string. We may also want this to be dynamic too. Let's try and set this as a variable rather than a string. Remove the quotations. I'm going to create this as a variable just above, const likes, and insert our string inside the back ticks so we can insert our variable all passing our firstName. In this case, it will say homerlikes, followed by a particular value. I send firstName, a text of likes, and now our likes inside of here will point to our variable, which is now shown in the browser. It also takes into account our firstName variable too, and places it in as part of the string. If we had multiple likes, we may also want to number them. We can begin by creating an initial value. We'll say let number be equal to an initial value of one. Then append this number value to our variable. As we would expect, we only have the single number 1. If we were to duplicate this and change this to be a second value such as Donuts, we could increment this number by one using plus plus. This will be increased for each one of our values. Remember that all of this is constructed using our object constructor function up on the top. We can also do all of this using the object literal approach. At the bottom, let's create an object literal, and we'll call it homer2, and set this equal to a literal object where we set our properties such as firstName or we can also make use of our firstName variable too. Log this to the console. As you can see, our variable can also be inserted using this approach too. But this may start to look a little bit confusing because here, we point to all firstName variable, but also the property name is still pointing to this firstName variable too. So why do we see this output as a string rather than the value of homer? Well, for the key, we don't need to wrap this name in quotes. This will always be displayed as a string. So how would we go about making this property named dynamic if we can't use a variable just like this? Well, one option would just be to create an empty object without any properties inside. Then we could add properties just like we do above using the square brackets or alternatively using an ES2015 feature called computed property names. We could use the square brackets directly inside of our objects. So surround our firstName property with the brackets, which now says that the code inside of these brackets is not to be treated as a string. Instead, it's evaluated as a JavaScript expression, meaning if we now display this inside the browser, instead, we now see the value of homer, which is our variable. Even this full control over the properties key, and also the properties value using JavaScript. We could also pull in our properties just like we did from above. We could access this without the homer prefix , paste this in. The only difference is rather than the equals, we need to change this via colon. We can also add our second one to of Donuts. Add a comma, place a colon. Let's try this in the browser. Open this up. So this is now inserted, but instead of the values of one and two, we see the values of two and three since we already incremented this just above, we can comment this one out. It's taking us back to our original example. This is how we can use computed property names with our objects to make both the key and also the value more dynamic using JavaScript. 22. Primitive & Reference Types: We use variables a lot in coding and JavaScript to store our data. But if we go a little deeper, there are some important concepts to understand and that is the we values we store fall into two groups. To better understand this, I want to first refresh what we already know about data types. We have primitive values, which are simple values, such as a string or a number which has no methods. We also have object types too. These two groups directly relate to what we're going to look at now and this is storing primitive and reference types. A string variable would be a primitive, and an object type, such as an array variable would be classed as a reference type. Both of these types impact the behavior of values when we pass them around and compare them. Let's first jump into our starter project and take a look at primitives. In the script for this lesson's file, we'll create a new variable called Dog and set this equal to a string. Next, create a second variable called newDog, and we'll set this equal to our original dog variable. This one is effectively a copy of our first variable. Then we're going to reassign newDog to be something else. Remember, the way to do this is to select our variable name, and set this equal to any new value. The next thing to do is to do a quick test with a console log, beginning with our first dog variable, and then a second console log for our new dog. Let's see. Well, this froze up inside the console. We see the value of poodle, which you would expect from our first console log, and the second console log of newDog. Even though this was originally assigned the variable of poodle, this has been updated to be the text of Labrador. Nothing unexpected here, even though we've copied a variable originally, the new one is still a separate value, completely independent of the original. Basically, we can modify the original dog, or the new dog and they will not affect each other. This is the behavior of primitives. The variable points to the actual saved value. Storing object types behave differently. Let's do an example using an object which we can copy just like we have done here. First of all, we'll create our variable called laptop 1 and set this equal to an object, which of course is an object type. The properties or brands, and the data inside of it doesn't matter. The model set any value as a string, and then just below, we'll make a copy of this, just like we did with our newDog. This one will be called laptop 2, which is equal to laptop 1. In the same way we did at the very top with our primitives, we'll update or re-assign our laptop 2 then we'll add a new property, such as the size. This time for the console logs, the first one is laptop 1. I will also see what the value of laptop 2 is. Test this out. Refresh. We'll see both of these values are exactly the same. This may seem really strange because we have the size property on both laptop 1 and also laptop 2 even though we've only added this to our second variable. Meaning that seems to be a link between laptop one and laptop 2. When we created our variables stored in a primitive just above with a string, the variable points to the actual unique value stored in memory, and these are all unique values. However, though, when we create a variable containing an object type, the object is still stored in memory. But these variables, such as laptop 2, holds a reference to that object's location rather than the actual value, hence the name reference type. Here we're creating our original laptop one, and then each time we create a copy such as laptop 2, it all points to the same original object. Since all copies are pointing to the same value, this is why when modify any of them, such as here, the original will also be updated too. Some other languages allow us to change this behavior. But with JavaScript it's fixed. Just as a quick recap and maybe clarify if you are unsure. When we create a variable to store in a primitive, such as a string, the variable points to an actual unique value stored in memory, meaning our Dog and also our newDog, are completely unique and independent values. However, though, when we create a new object type based off an original object, the copied version will hold a reference to the original object's location in memory, hence the name reference type. This is something which you probably don't care too much about it until we maybe run into an issue where you change one object and they all change unexpectedly, and you don't know what is causing the issue. With this in mind, next, we'll cover how we can compare two objects. 23. Comparing Objects: What we learned in the previous video is that a primitive value is unique and stored by a value and an object type is stored as a reference. This will now help us better understand the behavior we're about to see when comparing two objects, it's that inside of our starter files we have two similar objects with the same properties. They both have the brand and also the model and also the same values too. We're going to use these to compare quality. From a sensible guess, you would think that if we compared both of these, that they will be considered a true match. This would be a fair assumption since both of these have the same brand and also model too. Jumping into the console, if we do a comparison with primitives, this is pretty simple. If 1 is equal to 1, this would return back the value of true. This is simple because primitives have their own unique value stored in memory. Comparing values works as you may expect. Objects though are little less obvious. As you may expect, comparing the same object like this results in true. Laptop 1, if we compare this to itself, which is laptop 1, this is also true. But if we change laptop 1 to be equal to laptop 2, even though these both have the same brand and model, we get back a value of false. Even though these two objects have the exact same contents, they are not considered equal. The reason is because these are reference types. Remember, a reference type variable points to a location in memory, not the actual value. Here we're not actually comparing the contents of both of these objects. Instead, we're comparing two different memory locations. This is why the comparison is false. I know this can seem a little confusing, but this is just how JavaScript works. Going back to what we looked at in the previous video, what do you think will happen if we copied an object? For example, if we set the constant with laptop 3 and set this equal to laptop 1. Well, let's test this out. We can check if laptop number 1 is equal to laptop 3. Remember, here we're making a copy and this results in a value of true. Now, this one comes back true because when we created laptop 3, we didn't copy the contents of laptop 1. Instead, laptop 3 will now point to our original laptop 1 location in memory. Regardless of how all of these variables are stored behind the scenes, we may still need a way to compare the properties of two objects. We need a way to compare laptop 1 with laptop 2, which is going to result in true. One way to do this is to use a JSON method called stringify. We'll look more into JSON data. Stringify is a way to convert an object into a string and it looks like this. Parsing JSON, a method called stringify, we're going to parse in the value of laptop 1. If we test this inside the console, we can see our object is being converted to a string. Comparing a string version of laptop 2 with a string version of laptop 2 will make our comparison much easier. We'll do the same. We'll check if this is equal to json.stringify. This time we'll parse in the value of laptop 2. Jump into the console. This is equal to true since both of our string values are exactly the same. One of the issues though with using this method is the properties must be in the exact same order for this to work. If laptop 1 and the brand is our second property, this would result in false. To fix this, we have a couple of different ways to check this. The first one, which is only really good for comparing simple objects like this is we could create a function called check equality, which is going to manually check our two objects. When we call this, we're parsing object 1 and object 2. Then we'll return back the value of if object 1. The brand is equal to object 2. That is our first comparison. Afterwards also we want to check if the model is also the same. The double ampersand, check if object1.model is equal to object2.model. This is a long way round. It's a manual way of doing things, but it would work. We can check this out by calling our check equality function. Our two objects is going to be laptop 1 and also laptop 2, these are the two which you want to compare. To see what the return value is, we can parse this into our console log, refresh. Object 1 one not defined, I would just need to make sure these have a j, refresh, and this is the value of true. Now it doesn't matter which way around our properties are in each one of the objects. We can still do a simple or manual comparison of each one of these. Another option is making use of object methods to access the keys and the values. We've already looked at these in the looping with object video. Remember that we access the object, a capital O. We can then go up the keys such as model and brand or laptop 1, like this. There's model and brand. Also, we can do the same for object.values too. Using this approach, we can modify our check equality function for all of the keys and values and check if we have a match. This way also means that the order of the properties is not important as it was with the first stringify method. As you can see, object types can be a complex thing. If you don't understand how they work in JavaScript, it just takes a bit of experience to get used to. But I don't expect you to remember all of this first-time. But just being aware of things like this will really help you out in the future if you run into any object related issues. 24. Section Introduction: Coming up, we'll have a great project for you to work through and this is going to give you lots of practice with what we have learned so far. This is going to be our project which is named Speedy Chef. The whole idea is we're going to cook pizzas that come through via orders and try and get as many completed as we can, so with the chef and we can start the game, which is going to start the service for the kitchen and then we can see our orders coming in over on the right. When we want to start working on an order, we simply click on one and it then pulls it over to the working on section, which tells us what pizzas we need to make. For this example, we need one ham and pineapple, and two pepperonis. Currently, we'll start with the ham and pineapple. Go through the steps on the method just here and the first one is to roll the dough. Click on this. We then need to add our sauce, pepper, cheese, add 12 pieces of ham. Finally, 12 pieces of pineapple and this is all updated on our section just here. Once we are done, we can add this to the oven and if you were to make a mistake, we can also add this to waste. Click on this and then behind the scenes, it also does a check to make sure we have all the correct ingredients which we need for our pizza. There's a ham and pineapple, which goes into the oven. We can move on to the pepperoni, and then once we're done with this, we can complete our order and move on to the next one. Also we need to keep on top of things because these orders will keep coming in as the time progresses. This is a reasonably big project compared to what we've built so far. But most of which you will already know. It's just a case of building one small feature at a time and you'll be perfectly fine. Along the way, I will give you a series of tasks to try things out by yourself, but don't worry, you are not on your own. I'll also run through each stage too so we can compare and remember, as always, there is multiple ways we can approach things. If we both come up with different solutions which both work, this is fine. Inside the starter files, we have a basic starter with our index page, which adds all of the initial layout which we need. We also have some styling in our style sheets and this just means we can jump straight into our JavaScript and focus on this. Even though it looks the same as the final project, nothing actually works yet and we will be coding all of this during the class. As a starter, I've also included the pizza.svg and also a JavaScript file which is linked in our index page, which contains three arrays. These three rays are going to save us a lot of typing. First is a pizza's array and inside here, we have various pizza objects with the pizza name, a method to make this pizza and also the required steps which we use in the project to check if the chef has made the correct pizza and also placed the ingredients on in the correct order. Then just below this, some sample orders to get the game going and we will also be generating these dynamically too. Finally, a list of ingredients we need inside the kitchen. Great, so this is all now ready to go. Open up this project folder inside the browser and then jump into the next lesson where we'll get to work on listing these orders inside the browser. 25. Listing Orders: This video will only have one main objective and this is to loop through all orders and display them in the browser. Remember that just above, provided with this folder is the oldest array which we're going to loop through and display inside the browser. The location for this will be over on the right-hand side, in the side section. In the index page, we have two main sections. We have this main wrapper and this contains all of the contents, which has the white background. Then the aside with the idea of orders. For now, this just has a level 3 heading. But what we're going to do is to loop through all of these orders and place these into this section. To do this, we'll create a function called createOrdersList. This function is going to loop through the above orders array. For each one of these items in the array, we'll construct a div, which looks just like this section here. Certain parts of this are going to be dynamic. For example, we'll have the order number. This is going to be dynamic along with the name of the pizza and also the quantity for each line too. You don't need to worry about these comments. These are just but a visual guide to give us an idea of what we're going to do. We'll begin down at the bottom by creating our function. The function is called createOrdersList , the function keyword. The next thing is to loop over each one of these orders. We know how to do this. We can use a loop such as forEach. Grab our orders array forEach. Remember that forEach is going to run a function for each item in our array. Places function just inside. We'll give each one of these items the value of order. Now, we need to basically construct our elements just like we did above for each one of these orders. We'll begin by creating this main wrapper, which is the div. We'll add a class called order wrapper. We'll get to work at in our content inside. We know how to create elements. We use document.createElements. As in the elements' tag name, which is a div inside of a variable or constant called orderwrapper. Then add our class name by selecting the variable name of OrderWrapper. The property called ClassName. Just as we see above, this is going to be Order_Wrapper. So we'll just add a comment. This is the main wrapper. Then after this, we'll add a comment. This is going to be to add the order number. This is our first section inside of our order wrapper. This will be a level 4 our heading. Store this inside of a constant. I remember when creating elements like thses, we need to create the actual element and then the content inside. So we need two variables. The first one is orderNumber L, which is shelf elements. So document.createElements. We need a level for heading. Next, the text which is going to go inside, and this is the order number. The constant name of order number and we create this with document.createTextNode. Since this is going to be dynamic because each order has a different number, which we're going to grab from this unique ID. We'll place this inside of the backticks to make this dynamic. First, the text of order, which is this part just here, followed by a dynamic value. The dynamic value can be inserted using the dollar symbol and the curly braces. First, we select our individual order, which is stored in this variable, and then the property of ID. As always, when creating an element, just like this, we have two standalone pieces of information and we need to merge these both together. We do this by accessing the parent, which is the orderNumberElement.appendChild, where we'll pass in our actual contents, which is order number. This now leaves us with our div, which is the wrapper. Then our first element, which is our level 4 heading, but we still need to add this heading to our wrapper. Grab the Order_Wrapper and then we'll again use apendChild, which will take in our order number element. So we've got the first section just here, and then the next part is to create our own order list. A quick comment, so we know what we're doing here of great pizza UL for each order, and the wrapper so document.createElements. The elements was an unordered list. Places into a constant called Pizza list. This now gives us an unordered list, which is the main wrapper for all pizzas. But remember, we can have multiple list items because each order may have more than one pizza. So because our orders have multiple pizzas inside of an array, we again need to do a loop such as for each. To do this, we again jump into our individual order. We'll select the array, which is called pizzas. Use the for each loop to run a function for each item or each pizza inside of the array, store this inside of a variable called Pizza. Then we can get to work with constructing each one of these items. Each one of these items will be a list item. But first, we need to create this content inside. We have the quantity such as one, and then a dash, then a span element followed by the name of each one of these pizzas. Jump into our function and for each one of these items we'll create a span element to wrap our title and store this inside of a constant. This one is order quantity L, so document.createElements. Elements is going to be the span and then next the quantity of each one of these item, document.createTextNode. This section needs to be dynamics or placed in the backticks. Insert a variable. We can access the quantity by first selecting our pizza. In each one of these pizzas, if we take a look at the array, has a property called quantity. We'll also use the name of property soon. For this one, this is pizza.quantity, followed by a dash just afterwards. Thinking about this, it may be a little bit easier if we just add this quantity into our span. Rather than having them one outside, we'll maybe place this inside of an element, rather than having this outside on its own. We'll do this by accessing the order quantity elements.appendChild that's in the quantity variable, followed by our pizzaName. For our pizzaName, this needs to be wrapped also in a span element and then the contents inside. We need to do exactly the same as just above, we'll create a constant called pizzaNameL document.createelement. Element is a span followed by the pizzaName, which we need to create with create text node, grab our individual pizza. Then just as we've seen before, we have the quantity followed by the name property. We can access this with pizza.name. Merge these two together. PizzaNameL.appendChild wasn't in the text content, which is pizzaName. Great, so we've got two separate spans here. We have our first span, which is wrapping our individual number or the quantity of pizzas. Then a second span which contains our pizzaName. Both of these items need to be merged into a list item. Then the list item needs to be added to our parent. So let's get to work. As a new comment just to keep this clear. This one is create a list item. Show the quantity and pizzaName. First elements stored in a constant called pizzaItem, document.createElement. This was a list item. We've got our surrounding list item and then we need to merge our two elements from above. The quantity which is this variable, and also the pizzaName. Let's grab our pizzItem. Since we're appending multiple child elements, we can simply use append and that's now our first one, which was the order quantity element. Then the pizzaNameElement. We're almost done now, we have our list item will be created without two pieces of content inside and now we need to add these to our unordered list. Your on order list is stored in the constant called pizzaList. Add this just below its list.appendChild wasn't in our pizza item. We're almost there. Now we have our list items added to our unordered list. But now the unordered list also needs to be added to our wrapper. The wrapper is just this order wrapper variable here. But we do need to add this outside of our loop. Make sure we locate the end of our loop. What I did just below this line here. Select the orderWrapper.appendChild, passing in our pizza list. This is now our full order rapid constricted. The next step, or the final step for this, is to now add this to our web page. We need the sections of these two. This section is the aside. We can grab this with the idea of orders. Just below our order wrapper, use document.querySelector to grab our orders.appendChild wasn't in our order wrapper. Let's try this out, now we need to actually call this function for it to work. Let's grab three orders list, call us at the bottom, refresh the browser. The good news is we can actually see the orders on the screen, but it doesn't quite look as we expect. Let's take a look inside of our code and see what we need to change. We're currently missing the quantity before the actual pizzaName, which is this list item just here. We're adding the order number. I think this just needs to be the order quantity. This looks a lot better now we've got the order number at the very top, each one of these is in sequence, followed by the name and the quantity of each one of the pizzas on the order. As you can see, this is a pretty long function, and ideally, we want to refactor this into smaller, more focused pieces and this is what we'll do next. 26. Listing Orders Refactor: As we write our code and especially as our project grow. We want to regularly refactor our code where possible. At the moment, our code works completely fine. This is what we want to be focusing on at first, but it's also important to look over things regularly and see if we can improve things. This video is going to involve us refactoring this one single function which you have. Break it down into smaller ones when possible. It's a good idea to have smaller functions which focus on single tasks and this helps with readability and debugging. The way you approach is, it is up to you and often personal preference. But the closer we can get a function to do it in a single task, the better. The first step we're going to take is to remove all of the order creation process from this function and place it into a standalone function. We'll take out all of the contents which is used to create our order, leaving our "CreateOrderslist" function with a simple task. This task is to loop over all of the orders array and then add them to the aside section. To do this, create a new function just above. This one is going to be called to "CreateSingleOrder". Since this function is going to be repeated for each order inside the array, we will also take in the order as a variable moving down and jump into our function. Starting with "OrderWrapper" inside of the loop, drop all of the contents from here, right the way down to where we add this to our "OrderWrapper". Cut this out and we should just be left with our loop. Then the section where we add this to the aside. Now this is cut-out. Jump into our "createSingleOrder" and paste this in. Now, if we jump into our loop where we just cut this code out. We can now call this "Stand-alone function" which was called "createSingleOrder". "CreateSingleOrder" also needs to take in the order since we're passing it in just here, which is then used in the rest of our function. Now if you think about this, this is just simply call no function. It's not actually doing anything with it. All we need to do is we need to return the order from this above function, store this inside of a variable and then we can add this to the DOM. First we'll grab our orderWrapper, which is the full order section, and return this back from our function. This return value can then be stored inside of a variable called "singleOrder". SingleOrder can now be added to our sidebar. Let's try this out, "Save" and "Refresh", and everything still works just like before but this function is still pretty long. We can also reduce the size of this two. Again, how you break this down is down to personal preference. But what I'm going to do is to outsource the "pizzaList" creation to a new function and this could also be used in the future too. The pizzaList section is this loop. We also need to grab the one order list, which we store this inside of so copy this and also the loop. Then create our function and just above called "createListOfPizzas". Just wanted to take in the pizzas. Then "Paste" in our new section. Just make sure the correct section is pasted inside, which is our unordered list, followed by our four each loop. In just a moment when we get to actually call this function. Remember this is going to take in all of our pizzas so we don't need this order section. We can call our pizzas directly and it's variable. Now we can call this function from the place where we just cut out this code.The function name was "createListOfPizzas". This needs to be passed all of the pizzas for this order, which we can first grab from our order and each order has the property of pizzas. Just as we did below, we need to store this inside of a variable and also return back something for our function. The thing we need to return back at the very end is our "pizzaList". The returned value can then be stored inside of a constant. If we call this constant "pizzaList". It also ties in nicely with our variable name which we used before, which is then added to our "orderWrapper". Give this a "Save" and try this out, "Refresh" and all the orders still work as expected. Refactoring functions like this may not always be for you and you can decide how far you want to go. Nothing is changing in terms of the way the project works. We still only see the orders on the screen but now we have three clear functions with a specific task. We have at the very top, "createListOfPizzas", which is returned back from this function. This list of pizzas is then added to the DOM when we create our single order and a "singleOrder" is then looped over in our last function and then added to the DOM. 27. Element Helper Function: Another refactor we can do to save us a lot of code is to look at what we're repeating currently in our functions and see if there's a way to outsource it into a reusable function instead. If we take a look at our code at this early stage, and we'll go up to the createListOfPizzas function. We already have some things which we are currently repeating. We're repeating creating these elements in our three steps. Is part of the quantity. We're creating a span element. We're creating the TextNode, and then we're merging these two together. We're doing the same for our pizzaName. We're creating an element. We're creating a TextNode for the contents, merging them together, going down a little bit further to createSingleOrder. We're also doing a similar thing just here we're creating our text element, which is in a level 4 wrapper. We're creating the contents and then we're appending these together, and this is all completely fine. This is something which we need to do to create our elements. For each time we create a new element in any one of these functions, it's a three-part process taken three lines of code. It would be nice to create a helper function to reduce the amount of code, and this is going to be the task for this video. We'll create a helper function which is going to take in the element's name. This is the create elements section. You'll take in the contents, which is the TextNode, will merge them together, which is typically our third line, and then we'll return this new element to whatever calls our function. Let's get to work. Create a new function which is going to help out with this called buildElement. BuildElement also needs to take in it two things. It needs to take in the name of the elements such as the h4 and also the content which goes inside. Will pass this in when we call this function, and the first one is going to be the elementName and the second one is the elementContent. Inside the function is going to be pretty familiar from what we've already done, and in fact, we can copy any one of these examples. Solving createSingleOrder. Have all three lines of code where we create the element, we create the contents, and we merge these together. If you want to, we can copy all three lines, paste these inside. Then we need to make this a little bit more generic. Beginning with the first constant. This is for the element. The second one is for the content, and then inside of both of these brackets, we can pass in the data which is passed to all function. The first one is for the elementName and the second one we can remove what we currently have, place in elementContent. Change the variable names. This one will be element.appendChild, passing in the content to this element. The final thing we need to do, we are currently create an element. We also need to return this back from our function, it can be accessed within our code. Will return the full elements after it's been merged, and this function can now replace any one of these three lines of code which builds an element. If we grab our function name and also the brackets with the contents, we can now replace any one of these sections just above. We'll begin with createSingleOrder, for all order number elements, the order number, and then the third line which merges both of these together. I'm going to replace this with our function elementName. This is a h4. For the content we can replace this with the exact same content which we used just above. Grab this and paste this inside. Keep our naming consistent since we are currently using a constant called orderNumberEl, and we access in this just below, also need to store this inside of a constant with the same name. what happens here is we are building our elements inside of our new function. We then return this back from the function, which is then stored inside of this constant, which we can then use in the rest of our code, it just below. If you want to, we can remove the free existing lines of code, and then we can move up to our first function which is createListOfPizzas. We have all three lines just here. I'll comment this out so we can use it as a reference. We need to pass in our buildElement function, passing in our two values. The first value is our span. The second one will copy our template literal. Now this in. Also for this down at the bottom, we used in the original constant name of orderQuantity element. We can copy this and store it inside the return value. Remove these three lines if you want to. Next, the pizzaName. These three lines out. We'll create our constant, which is the same name of pizzaNameEl. Order function is also takes in a span element, and the content is pizza.name. Remove these. Both these are the same, we just need to change is over. This one should be the pizzaNameEl. We'll bring this one over. Good. Now let's save this and over to the browser and we can test. Everything is still working fine. Jumping into the console, we don't see any errors inside of here. Our sidebar has our generated orders over on the right. We have the order numbers, we have the pizza names, and also the quantities too. This all seems to now still working fine, and hopefully you can see the benefits of doing things like this. Even though our function has taken a few lines of code, each new element we create will reduce three lines of code into one. We can also use this many more times in the future during our project to save even more code. It's not just about readability and organization. A single line like this means fewer chances of typing errors, and also an increase in speed as our program grows. 28. Selecting The Current Order: We have some orders on the right right get us going, and soon we will create new ones randomly too. Just before we move on to this, I want to show you how things will work so you you can picture what we're going to be doing. Once the game has started, our orders will begin to come in and show on the right. The chef who is the player, will then click on an order to begin working on, which will then move this order into the working on section. This section is what we're going to be focusing on now. Later on, we will then go even further by clicking on a particular pizza in the working on section. Then this will display the method and also set it as the currently working on pizza inside the kitchen. Now we can just focus on clicking on an order and moving it into the working on section. As you may have guessed, to do this we're going to create a new function just above our create orders list. It's a new function called selectCurrentOrder. To call this function, we need to listen out for a click on any one of these orders. To do this, we need to move up to our createSingleOrder function. If we take a look for this section, we need to add an event listener to each one of these orders. We can click on this and then move that particular order into the correct section. Just underneath where we add this class. Grab the order wrapper, which is the div surrounding each one of these orders. Add an event listener. That will listen now for a click which will trigger our new function called selectCurrentOrder, gives us the test by doing a console log inside of our new function. Pass in the event information so we can get the correct elements which is being clicked on. Then we log this with e.target. Let's check this out in the console. Now what we need to do is click on any one of our orders. You see the margherita. We see the ham and pineapple. This is not exactly what we want. We can click on any of the order numbers, any in the contents. But what we want to do is to make the whole order section active so it's just one single clickable area. Better understand this, let's jump into the Elements tab and take a look. Now we'll jump into the aside section which contains our orders and click on any one of these divs with the class of order wrapper. What we want is to only be able to click on this div with the class of order wrapper and ignore all of the clicks which are on the nested elements. A way to do this is to listen now for a click on any one of these nested elements, such as the list items or the Level four heading. Then climb up the element tree until it finds the first div with the class of order wrapper. To do this, we can listen out for exactly which element was clicked on, such as the unordered list. Then we can keep climbing up the chain to check if the parent element is this order wrapper. There is a couple of different ways we can do this. We could store a reference to which child element was clicked on, such as our unordered list. Then we can keep checking inside of this loop if the parent element is this order wrapper. Or an easy way is to use an element method called closest. The closest method will take an element such as the one we click on. Then it will keep climbing up towards the document root through all of the parent nodes until it reaches a selector match. The selector can be a class, an ID, an element name. Just like we can do with query selector. Let's take a look at how to do this inside of our function. First, we'll start a reference to our elements which is clicked on, which was e.target. Then we'll find the closest parent elements with this class of order wrapper. We can do this by accessing the element which is clicked on, call the method called closest. Well we're passing at the query which we are looking for. In our case, we want to look for the order_wrapper. With this being a class, we add in the dot as a prefix. This inside of a constant called OrderWrapper. Then we can check this out by logging this to the console. Now if we refresh and we can try to click on any one of these orders. Make sure the Console tab is selected. If we try to click on anything outside, we don't see anything in the console which is expected by the pizza title. This returns back towards the parents order wrapper. We can open this up and check this is Order 1. Let's try a different one. This is Order 3 and also Order 2. Good so now regardless of which part of the order which we click on, it always climbs up to the parents order wrapper, to grab the full contents of this order. Using this method, if no matches are found, we will get back a value of null. We can also check against this before adding our order into the working on section. Just underneath where we select our order wrapper, add an if statement where we pass in our order wrapper, we can check if this is not equal to null. If we have successfully clicked on an order wrapper, we now need to grab this order wrapper and move it over to our working on section. Step 1 is to grab a working on section and store this inside of a constant called the orderDiv. That is equal to document. querySelector, and the query selector which we need as a idea of working on. Then using append child, we can add our order wrapper. The orderDiv. appendChild passing in our order wrapper which was clicked on. Great let's give this a try. We can close the console and try any one of these orders. Let's try Number 3 and this now appears in the sections since we've appended this as a child elements Order 2, Order 1, and this all works great. However, we only want to be able to work on a single order at a time. We need a way of checking if there is only a single order selected and placed in this div. A way of doing this is to first access the working on section and we can check what child elements are nested inside. See it is better we'll grab a reference to our div place this inside of a console log. Then we can chain on the end.children. Jump into the console. Click on one of our orders to add this to the section. If we look closely, the first thing we have is a HTML collection with a Level 3 heading. After this, we have our div with the class of order wrapper, which we just added. We can also confirm this if we go to our index page that is working on section only has a single Level 3 heading. With this in mind, the number of child elements can now be used to stop the function. If the number of child elements is greater than one i.e I we have our Level 3 heading followed by any one of our orders, we can do this back in our select current order function. Remove the console log, replace this with an if statement. We can check if the children. length is greater than one. If it is, we'll simply return alter this function. We can also remove the curved braces and replaces with our return statement. Let's try this out. Save and refresh. I click the first-order this works fine. Now we can't add any further orders. The final thing to do, we want to move over the order into the working on section is to also remove the event listener. We no longer need this section to be clickable, so we can remove this from our order wrapper. We can do this just before we add this to our div section. By accessing the elements which is stored in order wrapper called removeEventListener. The listener we want to remove is the click events followed by selectCurrentOrder which matches our event listener. Where possible event listeners like this should be removed when no longer needed. It helps keep performance up since the browser no longer needs to do an unnecessary task, but also to eliminate unexpected behavior. Next, we'll cover selecting the pizza, which we are going to be working on inside of the kitchen. 29. Set The Current Pizza: Look at the flow of our project, we've already done the first step which was to move the selected order which we click on to the Order section into the Working on section. Next, we need to be able to select the pizza to work on by clicking on it. This selected pizza should then show in the kitchen area and also display the method, all the steps to create this. If you take a look here I've created some steps which we're going to use to fulfill this objective at the top which is to make the pizza names clickable and then move them in to the kitchen area. If you want to you can follow along with these five steps and try to recreate this yourself or if you prefer to you can follow along with me. First of all to be able to click on these pizzas, Step 1 includes adding a class of pizza name to each one of these items. Let's jump up to the createListsOfPizza's function , we'll locate this. And then this is where we create each one of our pizzas inside of the span elements. Just before we do any appending, we'll add our class by selecting the pizza name element variable. Select the ClassList, the method called add, where as a string we'll pass in the name of pizza_name. That's Step 1, taken care of. Let's scroll back down. Step 2 is to locate the SelectCurrentOrder function. Since we may have multiple pizzas, we need to select all of the span elements. And remember if we have multiple elements, we need to use a querySelectorAll. We can grab all of these elements using this pizza name class, which we just added. So let's locate this function SelectCurrentOrder, then at the top we'll use querySelectorAll to grab all of these pizza elements, store these inside a variable called pizzas document.querySelectorAll. We can grab these with the new class name which we just created, which was pizza_name. Remember the objective is to be able to click on one of our pizza names, such as our ham and pineapple or all pepperoni. So we can just now free click on any one of these names. So grab our variable, which is pizzas. We can use forEach to run a function for each one of these items. Each one of the individual pizzas will store on a pizza variable and then we can add an EventListener to each one of these pizzas, so pizzas.addEventListener. Event will be a click, which will then run a function which we haven't created yet called setCurrentPizza. Okay? So let's create this function down at the bottom, function setCurrentPizza. Since we trigger this using a click event, we can also pass in the event information to our variable and check this is working with a console log. So to grab the actual elements which you clicked on, such as ham and pineapple or pepperoni. To grab the text, we can do this with e.target in a property called innerText, check if this is all working correctly. Let's try this out, jump into the console, and refresh. So the first thing to do is to click on one of our orders, oops it's thrown an error at the EventListener. Let's take a look at what could be causing this. We've got unused variable, so this just needs an s, because this contains multiple pizzas. Let's try this out now. We can click on our order. That works great. Now if we click on the text of ham and pineapple, we see this in the console, Pepperoni. Good, this is exactly what we want. Now if we go back down to our setCurrentPizza, obviously, the objective is not to log this to the console, what we want to do is to save the pizza name into a variable and then add this just after our text of Currently making. If we jump into the index page and locate this section, we can see just afterwards we've got a span with the ID of current_pizza. So we're going to store this text into a variable and then place it into this span. Let's do this inside of our function with a console log and store this inside of a constant called pizzaName. Grab our span area with document.querySelector. Use #, since this was with the ID of current_pizza. Set the innerText for this element equal to our above variable. Let's try this out. We don't need the console anymore. Move any one of these orders over to the working on section. Click on "Pepperoni" and there's our text displayed, "Ham and pineapple" and also the "Margherita". Next, we'll use this selected element to display the required steps inside of the method section. 30. Split & Join Methods: Previously we set the current pizza name inside of the kitchen when this was clicked on. Now we're going to move on to displaying the method to make this pizza inside of the methods section. The method is all the steps needed to create each pizza. We have this at the top of our JavaScript file. Inside of our index page, we can go into all pizzas array, and this has the pizza name which you've already used, and also the method too. If we take this Margherita method as an example, this is going to have three steps. The first one is to roll the dough, the second one is to add the sauce, and the third one is to top with chees. We will validate the chef has completed the steps later using the required steps, but for now, all we want to do is to focus on displaying this method inside of the browser. As you can see, this method is all one single string of text, and what we're going to do in this video is to split each one of these steps up to display them in the browser. So we need step 1, we need step 2, and also step 3 to display these in a formatted way. To do this, we could go into our set current pizza function, but to keep things cleaner and more abstracted, I'm going to create a new function down at the very bottom. Jump down to the very bottom of our project. It's a new function called displayMethod. This is also going to need to take in the pizza name so we know which method we need to get, so pass this in into our function, and we need to call this function each time we set the current pizza, ie, this function just above when we click on the pizza, and this is displayed inside of here. When this is clicked on we know which pizza will need to work on. This makes sense to call our function from inside of there. Let's do this. We'll call our function, which is displayMethod, and remember this also needs to take in the current pizza name, which you have stored inside of this variable. Over to our index page, is currently already has a section called method, which you can see here. This has the ID of method a level 3 heading up at the top, and then we have two sections. We have the pizza name followed by the method which we are soon going to insert. As you can imagine, this is the section which we're going to be working with. We can begin up at the first section which is the pizza name. Into our function, we've already got the pizza name so we can use documents.querySelector('pizza_name').innerHTML which would have seen the inner text content will be equal to our variable, which is pizzaName. Before we go any further, try this out in the browser, I need to refresh and pass over an order into the working on section. Click on "Pizza" and we can see our pizza name inside over here. This also updates as we click on different ones. The next step in our index page is to grab our pizza method and place a method inside of here. Remember, our pizza object has this method property which we can access, and to find this we can use the Erase find method is find method we can use to filter this particular borne by the pizza name which we already have, and then we can select the method for each one. Back to our function bravo full pizzas array method, which is find, and find is going to run a function for each value inside of our pizzas array, and you can place an irregular function if you want to, but because this is going to be a simple statement, I'll add this on its own line with an arrow function. This function is going to take in the individual pizza, then access each individual pizza's name on the loop, and we can check if this is equal to our pizza name, which is passed into this function. The current clicked-on pizza name is equal to any one of our pizza names in the array, we'll store this selected pizza inside of a variable or constant called selectedPizza. Next, we'll do a console log and check this is all working fine, the constant of selectedPizza, and let's refresh this inside the browser. Jumping to the console. First, click on an "Oder," select one of the pizzas. This is ham and pineapple, and we can see the full among pineapple object has been returned. Let's try one more. The pepperoni. Great, so this all works and we can now filter this down to only return back the method. Try this again. The steps which we need inside of there, and it's different for each one of these. Great, so this now returns back a string of text, and we need to split up this string and display each step as a list item. For this JavaScript has a built-in string method called split, which strings inherit through the prototype chain. This method will take our single string, which we have now, split it up at a certain point which we specify, and then return a new array containing all of these substrings. This is how it looks in our code. This is our method, so we can just remove this from the console log chain onto the end, the JavaScript split method, and we want to pass in which section of the string we want to split this apart, and then our case, a full stop is ideal, and this is because if we look at our string, each one of these steps which we have ends in a full stop. This is perfect for breaking up our string, and remember this will return back a new array, which we can store inside of a constant. Finally, before we go any further, we'll do a console log passing in our constant, which is methodSteps. Let's try this out. Select an order, select the pizza and this now returns a new array with all of our steps in place. We can also do the opposite too if we wanted to, and that is to take an array of values just like we've got here and convert them into a single string. We can do this with the method called join. Remember, methodSteps is an array. We can do the reverse by passing in the join method. Join is into a single string. We can test this out by clicking on a Pizza. Have a single string return back towards and each value is separated by a comma. If we wanted to, we could change this separator to be any other character, such as a dash. Try this out. Now have a dash between each one of these values. This is useful if you need to join an array of values into a single string. We know now that we can loop through arrays and do something with each value, and in the HTML, we've set the pizza name currently with this section here, and the next step is to grab our second div with the id of pizzaMethod. I'm placing our array values. Grab this with documents.querySelector('#pizza_method').inner HTML and here I'm just going to set this to be equal to an empty string. If a method has already been previously set, we can clear it out before adding our new one. Then, we'll list our steps by grabbing our array, which is methodSteps. Since you have multiple values, we'll loop through each one of these with a for each loop, which runs a function for each value. We can solve each one of these values in the variable called method. Then construct our elements. Install this inside of a constant called elements. We have documents.createElements plus the elements which you want to create. I'm going to choose a p element, and next the text content, document.createTextNode, and the contents which you want to pass in is the text from our method. Placing in the method inside merges together elements.appendChild passing in our text. The final step is to again grab our pizza method section, so we'll copy this, paste this in, and then we can add this using the appendChild passing in our elements. We'll save this and refresh, select a new order. Pepperoni. There we go. There's our pizza title and also the required steps for each one of the pizzas. Good. This is all now working and looking good. There's just one little re-factor we can do. Remember, we've created a new text element just here, but we've also got a helper function called buildElements, which takes in our element name, contents, and returns is newly constructed value. Back down to our loop. We can store this inside of a constant called steps. This is equal to the return value from our buildElement function. Passing the p elements. Then the contents, which is the method we're going to move these next three lines and pass in our steps. Let's try this out, select a new order. This all works exactly the same, but we've saved a few lines of code. This is another good step completed for our project, and if you are a beginner, I know that can be a lot going on here, but the important thing to remember is we've already covered the majority of what we're doing here. It's just the case of breaking it down into smaller tasks, making sure each step works along the way. 31. Adding Pizzas To The Oven: The final stage of moving this pizza around is to move it from the kitchen area up to our oven. We've not yet created the pizza, but we will look at how to do this soon along with checking we've used the correct ingredients. But for now, we can use this pizzaName which we have and move this up to the oven section. Now our oven is going to be an array to store multiple pizzas, we'll also need some other variables too. Let's create these both our functions well up, and just below our ingredients, create our oven with the let keyword, which initially will be an empty array. After this, we need to set the maximum number of pizzas which will fit in our oven, which is the ovenCapacity. I'm going to go for a value of six. Next, we need to keep track of the pizzas which we have made for a particular order. If you take Order 3 for example, it says four pizzas, Order 2 has three pizzas and we need to keep track of how many we have currently made. let pizzasCompletedForOrder, which will be initially zero. Now we have these, we can create our first function which will be used to push the pizza to our new oven array. Down to the bottom, create a function called addToOven. For now this oven is going to take in the current pizzaName. We can grab this from our kitchen if we go to our index page. Down to the kitchen area, remember we have this span with the ID of current_pizza, and this stores our pizza name. Grab this with document.querySelector ID, which is current_pizza. Then the innerText. Store this inside of a constant called pizzaName. Remember that we don't always have a pizza selected. Currently we've got the value of ham and pineapple but if we refresh this element is often empty. To check against this we'll place in an if statement. We can check if the pizzaName is present. If it is, we'll then add this to the oven with the array method called push, pass in the pizzaName and then a temporary console log to check this is all working. Let's have the Console, jump into the browser. We can check this log in just a second but first we need to actually call this function. We'll call this function by adding a click listener to the button which we already have, which is inside of our kitchen section and just below our current pizza. Have this button to addToOven. It currently has a class, but we can add an ID. Select this addToOven and then grab this oven in our script. documents.querySelector, the ID value of addToOven, then we can add an event listener. Event listener will listen out for a click on this button, which will run a function called addToOven. We'll try this out. With the Console Open, click on one of our orders. Select the pizza. Currently we're on ham and pineapple, and trigger our click listener with oven and we see ham and pineapple is pushed to the array. We'll try pepperoni. Click on this, and again, this keeps adding pizzas to our oven. Great. Now we know this works, we can extend this a little along with adding a pizzaName to the oven. Currently we just see inside of the array, but we also need to list this in the oven section. Along with listing the pizzaName, we can also set the time which was put into the oven. This is because later we'll also add a cooking time too. So for this, create a new object and we do this inside of our if statements. Just above where it pushes to the oven, we'll create an object called pizzaForOven. The first property is the pizzaName which is stored in the pizzaName variable, which you already have and then a property called timeAdded. For now a simple place-holder value is fine, we'll come back to this later. The final step for now is just to put the constant of pizza for oven into our push method. Just before we test this, remember we added a variable called pizzasCompletedForOrder. We can increase this by the value of 1. Let's just check this all works inside the Console. We've got a pizza, add this to the oven and there's our new object. The oven array is now getting the pizzas as we can see. Next a function to run through this array and display them in the oven section. Just after we push our new pizza to the oven, we're going to call a new function called displayOvenItems. We call this each time we create a new pizza and add it to the oven, which is going to update the user interface. We haven't created this yet, so let's add this just above. To begin inside of the index page, we need to grab our oven section and if we take a little look through our code, we've got the oven wrapper which has the level 3 heading and then this empty div with the ID of oven, and this is the location where we add our new pizzas. We can grab this document.querySelector, the ID of oven and then first we'll set this to an empty string. This clears out our oven before we update it. Wrap our oven array, and since this isn't an array we can use forEach. We run a function forEach value inside of there, each value is going to be a particular pizza which we'll wrap in a div. const pizzaDiv is equal to document.createElement, creates our div section. We'll add a class to this for our styling, so pizzaDiv.className is equal to pizza_div. Remember, inside of our starter files we also have an SVG image for our pizza. This will be used to display inside of the oven each time we add a new pizza to the oven. What we can do is we going to treat this as an image or create a new image element. We have document.createElement, the image elements with IMG. Then we can set the source property to be equal to our SVG. This one is called pizza.svg, and it's also in the same folder but we can reference this by its name. We've got a wrapper with a class, we have an image, we'll also need the pizza name. To do this, we can make use of our function called buildElement to create these photos and store the return value in a constant called pizzaName. Our helper function, which is buildElement, this can be a p element and since the pizzaName is going to be a variable, we'll insert this inside the back ticks, with all the symbol and then calibrate this and then remember, each one of our oven items is stored in this pizza variable so we can access pizza or name. This is all the elements we need. Now it's just a case of adding these to our pizzaDiv wrapper. We'll select this pizzaDiv. We can use append to add multiple values, add some new image on the pizzaName. The final section is now add this to our oven. Just like above, we'll use querySelector to grab our oven, appendChild, placing in our pizzaDiv. It's a bit going on there, but let's refresh and test this is all working. Place in a new order, select the pizza, add the pepperoni to the oven. There's our image which we created just here, and also our pizza name below, ham and pineapple. Great, and this is all now working. As mentioned, we still need to come back to actually create in the pizzas, but we now know this step is ready when we do. 32. Starting & Ending The Game: This lesson, I have solved some steps to try things out yourself. What we're aiming to cover is creating two functions. One function will be used to start the game and one to end it. These functions are going to be called from our HTML buttons, which we can see in our index. This is the game control section where we have our two buttons. The idea behind these two buttons is to clean up the user interface, to only show the correct things, such as only showing the end game button when the game is actually running. We use the start game button to begin the orders coming in and so on. These functions will also be useful later on too when we add to our project things like stats and timers. What we need to do is to first create our two functions called startOfGame and endOfGame. Then we can call these by adding an event listener of the two buttons we just looked at. We'll create a new variable, which is game started, which will be a Boolean. This Boolean will be true when we start the game and false when we end the game. We'll do a conditional check inside of startOfGame to return out of this function if this game started variable is true. Step 5, remember that all orders have this class of order_wrapper. I'm going to clear all of these orders in our startOfGame function. Since we have not started the game yet and createOrdersList is responsible for creating these orders. We can also move this inside of our startOfGame function onto the CSS. When the game start, we'll show the end button and hide the stop button and then do the reverse when the game has ended. Not forgetting our end game button also needs to be removed or hidden when the game initially loads. As ever, you can try these out on your own or follow along if you prefer. Down at the bottom, remember the first step is to create our functions. The first function was startOfGame. Then our endOfGame function too. Both of these functions need to be called by clicking on the two buttons in our HTML. We'll do this by grabbing our start and end button, and adding an event listener to call these functions. These buttons, at the idea of start and end button. We can grab these now with document.query selector. Here's the hash. First, the start button. Add event listener for a click event, which is going to trigger a function called startOfGame. Duplicate this. The second one is for the endBtn, which will trigger the corresponding function. Also move down our event listener from above to keep these grouped. Actually it's just wants to be add event listener to make sure that this is completed. Then before we go any further, we can add a console log into each one of these functions to check they're all working correctly. The first one is start. The second one for end. Then jump into the console. Just separate out the minutes, so we'll just reattaches. There we go. Back into the console and our two buttons at the top. Start triggers a console log and also end works too. That's Step 1 and also Step 2 taken care of. The next one is to create a gameStarted Boolean. Let's do this up at the top and the rest of our variables. Let gameStarted, which will be initially false. We can update this variable from our two functions. Remove the console logs and when we start the game, gameStarted will be equal to true. Then inside the endOfGame function, gameStarted will be equal to false. Now when, if this game is started or not, it's going to be really useful and in particular for the startOfGame function, we're going to be doing some cleanup work such as removing any existing orders. We don't want to use it to accidentally run this mid game. We can return out of this function if this is true. If gameStarted is equal to true, we'll then return all to this function before running any more code. After this, we can move on to removing any orders from the previous game. Let's grab our orders and store this inside of a constant with document.getElementByClassName. We are using class name here because remember, we have this class of order_wrapper. Pass this in brackets. Then we can loop through and remove all of these orders. If we access the main array object with a capital A, we can then have access to a method called from to create an array from all of these items. When using getElementsByClassName, this will return back a HTML collection. Then we can use this to create a new array from these orders. The from method, passing the orders. Now we have this converted to an array. We can make use of array methods such as forEach to run a function for each one of these. Passing the function, each order will store it in the order variable. Access this individual order, and then call the JavaScript remove method. This takes care of removing these orders when we first start a game, but we also need to actually create them in the first place. Currently we have a function called createOdersList. If we scroll up to find this. Just to get this function is responsible for creating all of our orders. Would make sense to call this when the game has started. Currently if we do a search for this, we can see this is just called from inside of our program. Instead of calling this as soon as it loads, we'll cut this out of place and then move this down to our new startOfGame function. Now all orders should only show when the user clicks on this start button. Let's save this and try this out. Now, since we've moved our function call, we don't see the orders, like start. Now they appear inside the sidebar. The orders are showing and we know this function call is working correctly. But we can't get to tell if the previous orders were cleared. Where we used order.remove. This doesn't matter much at the moment since all the orders of the same. But later we'll generate random orders which will be different. As a temporary measure to test this, comment out our function call. Then we can add a temporary elements into our HTML and check this is being removed. In order section of P elements. Remember all of these have the class of order_wrapper placed in any text inside. Now, if we save this, refresh, we can see all the run. Click on Start. This element has now been removed. Great, so we now know this is working. We can remove our temporary elements and also reinstate our function call. Then the next step is Number 7 and 8. This is to use the style property to show and hide these two buttons. At the startOfGame, at the top of the function, use document.querySelector. First grab our start button. Access the style property of display. We can hide this by setting this to be a CSS value of none. Duplicate and then for the end button, we'll reinstate this by setting this to a value of inline. Copy both of these. Jump into the endOfGame function and paste these in. Then we could reverse the values of both of these. The stop button will display with a value of inline and then end button can be removed with none. Let's try this out. Refresh. Click on Start, and this removes the end button. Click on end and this shows the start button. You'll also notice as soon as the page loads, we do see both of these buttons. Since the game has not yet started, we only want to show the start button. We're going to move this by setting the style property of display to be equal to none. For this, we've already got the code as our second value inside of here. Copy this and then we can call this up at the top of our code. Anywhere around the variables is fine. Refresh. The end button has been removed. We start and we only see the end button. Now I'm in the game. We only see the stop button. 33. Introduction To Javascript Math: In this section, we'll continue with our Speedy Chef project but we're going to be focusing on some handy math, date, and time of functionality which JavaScript offers. Starting soon, we will look at how we can use JavaScript math to generate random pizzas and orders. Currently, with this orders array we have, we only generate these same three orders each time the game starts, but we can generate new ones with have been more randomness. These orders will keep on coming in as the game is running. We'll have different amount of pizzas and also different types of pizzas for each order. To do this we need two new functions at the very bottom. The first one is going to be called generatNewOrder. This will be responsible as it sounds, for creating a new order with an order number. I'm going to parse this in, generateNewOrder. Then this second function is going to be called generateNewPizza, and generateNewPizza will create random pizzas, which will be called from our order function. Test this out with a console log, parsing in the JavaScript math object. Just before we can see this, we do need to call our function. So grab this and then call this function anywhere below. Refresh, open this up, and this returns a lot inside of here. We have lots of different properties and methods, and I'm not a mathematician, so some of this is beyond my knowledge. But you don't need to be great at math to be able to use some of this. It's all here to help us. There are some constants which we can use such as the value of Pi, which you may be familiar with. We have something called Random if we scroll down, which is a method. It's what generates a new random number between zero and one. We have something called ceil and floor to round up or round down and we'll look at these in just a few moments. There is a method to round to the nearest number. We can find the smallest and largest number with min and max, and also lots of others too. Let's go back to the function and see how we can use them. Jump into generateNewOrder, and just below our console log, let's change this to be Math.random, which is one of the methods which we've just seen inside the browser. Let's test this out. As mentioned before, this will generate a new number between zero and one. So zero is included, but the value of one is not. We'll only go up to the value of 0.999 recurring. Often we do need this number to be a different range, such as the value of 0-10, 1-50, 0-100 and so on. To do this, we can't parse in any range to Math.random. Instead, we must multiply this by the amount we want to multiply it by. If I multiply this by the value of 100, this will give us a value between zero and 99. Remember that zero and one is the original Math.random. Even multiplying that 0 by 100 will still give us 0. Since 0.99 is the highest value, multiplying this by 100 will give us the value of up-to 99. Save. Leaving us with some larger numbers inside the console. Let's store this inside of a constant. I can pull this out of our console log, const random. Then we can round up this random number to the nearest whole number. It was an example. Rather than getting 53.4, we can round this up to 54. We do this by, again, accessing the JavaScript math object, a method which we've just seen inside the console called a ceil, where we parse in our constants of random. Now each time we refresh this, it will round this up to the nearest whole number. We've actually got pretty lucky there because we've got the value of 100 in the console. This is because the original random constant will give us a number such as 99.9. Then this will round this up to 100. With this rounding up, any numbers beginning with zero will be rounded to one. This should give us a number between 1-100. We can round down by changing ceil to floor. But you won't notice much difference inside the console. But this will round down rather than rounding up even as a whole number between 0-99. Also mentioned when we looked at the math object was the min and max methods in the console. Let's begin by finding the largest number value. To do this, we'll create a new constant called highest and set equal to Math.max. Math.max is going to take in multiple values. We'll go for 1, 77 and 34. Just parse in any random numbers inside of here, then log this to the console. In my case, 77 is the highest value inside of here. This is returned back in the console. As you would expect in a similar way, we can also store the lowest value. We have Math.min. Log in any numbers inside of here. Log this one to the console, and it should return back the value of one. This isn't always practical to wrap our numbers inside of the max or the min function. Often these numbers are stored inside of an array. Then we need to access this array and find out which is the highest, and lowest value. Well, to say this, create a new constant called numbers and store this inside of an array. Saved numbers are fine. Count these ones out. First of all, maybe to reproduce what we had above with our highest one, and then parse in our numbers to Math.max. Let's do this and see what happens. Console log the value of highest. You may be expecting to get the value of 77. Well, if we save this and refresh, we see the value of not a number inside the console. The reason we get this is because inside of here we're parsing in an array, rather than the actual values which were contained inside. To extract the values from this array and compare, we need to make use of the JavaScript spread method based on the three dots. Refresh, leaving us with the correct value. Also if you wanted to, this can also be used with Math.min. It works exactly the same and that is other methods and properties available on this math object, as we've seen earlier in the console, depending on your particular needs. Now we're going to put this into practice by generating random pizzas, and orders. 34. Generating New Pizzas With Math: We can use what we now know about JavaScript Math to generate random pizzas and orders. First, let's clear out our generate new order function from the previous video and jump into generate new pizza. We use this function to generate a random pizza from our pizzas' array. To start off, we'll create a random number between one and three, to generate the quantity for each pizza. Remember to create a new random number, we use Math.random. This will generate a random number between zero and one. But we also want to make this between one and three. The first step is to use Math.ceil to round this value up, cut this out. We use Math.ceil and inside the brackets pass in this random number. With this between zero and one, this is always going to round this up to the value of one. But we want the value of 1-3, meaning we need to multiply this returned value by 3, store this inside of constant called quantity. Then do a console log to check this is working. Say this, and we need to console log this value by calling generate new pizza. Changes, refresh 1, 3, and 2. Seems to be all the numbers which we need in our range. This is our random quantity, but we'll also need to select a random pizza. Just before we do this, ultimately, what we want to be aiming for is to be creating a new pizza object, const pizza. This pizza needs to take in the quantity which you've already created just above and we'll also need a pizza name. This is a step which we now need to create. Comment this out so we get no errors. We take constant to store this in, for all at random pizza. This is going to select a random pizza from our pizzas array. Remember the arrays always begin at the value of zero and it needs to go right through to the end of our array. We're now going to grab this with pizzas.length. Using a similar example from above, we'll copy this without the semicolon, pass this in. As we know, this will return back a value from 1-3, but we need a value of zero all the way through to pizzas.length. To get zero, we use Math.floor, which currently will give us the value from 0-2. But rather than multiplying this by 3, we'll multiply this by the value of pizzas.length. This also means that if we add new pizzas in the future, this will also be taken care of. Now back to this name property, we can set this equal to our random pizza. But remember, our random pizza is selecting one from the array. If we look at the array, this contains an object with the name, the method, and required steps. We only need to access the name property, so we can access randomPizza.name. Finally, since the job of generate new pizza is to generate new pizza. This is what we've done with this object, so we can return this back from our function. Good, let's try this out. Rather than calling this directly at the bottom place this into a console log, generate new pizza. Call this function, refresh as our first object. We've got a random quantity of three and the name of ham and pineapple. Again, one vegetarian, two vegetarians, and one chicken. This is effectively half of the job done to generate our new order. We've got all of the pizzas return back. But rather than console login, this value, we need to call this from generates new order. Jump into this function and we'll begin by creating a new pizzas variable and set this equal to an empty array. This empty pizzas array will be used to build a random amount of items for our order. Because remember, even though it generates new pizza, it generates multiple values, it's still only one line item. By this, if we refresh, starts up again. What I mean by this, if we click on one of our orders is, for example, we only generate in one line, such as one ham and pineapple or two pepperonis. Pizzas is going to store an array of all of these line items. In this game, I'm going to restrict the number of line items to be up to five, so we don't have too many huge orders. We already know how to generate a new number between one and three. Let's copy this, store this inside of a constant called order item, rather than the value of three, changes to be five, given us a number between one and five, which you can change if you prefer. Now we know we've got a random number between one and five. Next we'll create a loop to push each one of our orders, which is generated from this function into our pizzas array. We'll repeat this for the value of order item. Pass in a for loop, i will be initially set to one. The loop will keep running where i is less than or equal to the above value of order item, so this is 1-5. Then after each loop we'll increment i with i plus plus. For our empty pizzas array, use the push method to add a new value. The new value to push is this value which is returned back from generate new pizza. We should be left with now a pizzas array, which is set to a number of line items between one and five and then the random pizza objects inside. This now leaves us with our pizzas array for the order, but now we need to construct our order objects. This creates a new constant to store this in, called new order, let this be an object. Each order needs a unique ID. We could go ahead and generate some long random number or string. Of this case, a simple order number is fine. What I'm going to do is just outside of this function, creates a new variable called order number, and set this equal to our orders array dot length. If our current amount of orders is three, this will return back the value of three. But since we're creating a new order onto the end of this array, we'll add plus one to the end. There should be always one more than the number of orders which we have. Therefore, it's going to be unique. We can pass this in as the ID, place in at the pizzas array from above. What do we actually want to do with this new order? Well, up at the top, remember we have our orders array which contains the three sample orders. We need to push to the end of this array. This is pretty simple. We'll grab our orders.push place in our new order, and then finally would increase our order number for next time, so add order number plus plus. This should always be unique. Let's grab our generate new order function, and we'll call this at the very bottom and try this out. Save and refresh. Click on "Start." Then we have our three original orders from our orders array, and then a random order down at the bottom. We've got the next index number of order four. We've got a random number of pizzas and also a random name. Let's refresh and try one more. Order four, this one's a little bit longer and it's got four separate line items. Remember, we could have up to five line items. This is good progress with our game and we will build on this in the next lesson and generate new orders after a certain time delay and also revisit JavaScript Math, where we'll look at drawn with the Canvas. 35. setInterval: We know our orders are working and also generating randomly as soon as the game begins. But we also want them to keep coming throughout the game too. But this JavaScript provides us with a method called setInterval, and setInterval run a function after a certain time delay. It's available on the window object, so we can simply call it on its own. So call setInterval, and setInterval is going to take in two things. First, we pass in a function which you want to run, and we could pass in a new function directly just like this, or we could reference an existing function by its name. The function which we want to run is generateNewOrder, so pass this in without the brackets, and we can also now remove this from just above. Separate it by comma. We pass in a time delay, and this is the time delay between each function call. It's also in milliseconds, so 3,000 milliseconds is equal to 3 seconds. This function will be called every three seconds. We check this works, move up to our generateNewOrder function and we can pass in a console log, place in the orders array. Refresh the browser. After three seconds, we should see a console log with four orders. Three seconds later, we see five orders, six orders, and so on. Good. Now we know this works. Earlier, we created a function called createOrdersList. Let's take a look for this. Scroll up and here we are. This is our function just here. This function took the orders array. We then looped over each one of our orders and placed this into our orders section. All we need to do now is to call this function each time we generate a new order. Instead of our console log, which we placed them before, inside of generate new order, remove the console log and replace this with createOrdersList. Let's say this and see where this leads us. Refresh the browser. After three seconds, we see our set of orders come through. We have number 1 all the way through to four, and then the seconds later, we get a new batch of orders. The problem here is though, we don't just add the new orders which have been generated, we also add in the existing orders too. This now leaves us with two problems which we need to fix. The first one is that orders are coming in before we even press the "Start" button at the top. The second one, as we've just seen, we only need to add the new orders rather than add all of the existing ones too. Fix this issue, we can clear out all of the orders before we add our new ones to this section. This can be done by going to the createOrdersList function and clearing the order section before we add the new ones. Let's jump back up to createOrdersList. Here we go at the very top. Before we add our orders into this section, we'll clear this out with documents.querySelector. Grab our orders section, inner HTML and set this to an empty string. Let's try this out. Refresh, give this three seconds. There's our first four orders. Order 5, this is looking good. Order 6, great. These are all now coming through but rather than adding all the existing orders, we are adding it to the end of the ones which are already there. The next thing we want to solve is to only add these orders to the sidebar after we've actually clicked on the "Start" button. For this, rather than directly calling our setInterval at the bottom, we can remove this, quit this out of place, and wrap this inside of a function called ordersTimer. Place this back inside. Remember, when we click on the Start button, this triggers our function called startOfGame. If we locate this just here, we can then call our function, which was the ordersTimer. Let's say this and try this out. First, refresh and give this three seconds and we shouldn't see any orders now in the sidebar. Good. This has stopped the initial load. Click on the "Start" button. Now our order is beginning to come through. SetInterval is also useful to create a countdown timer for the game, so it only runs for a certain amount of time. As soon as you click on "Start," we'll begin a countdown timer from a certain amount of seconds. For this, we need some variables to keep track of this. Jump up to the top where we have the rest of our variables. The first one is going to be a constant called gameLength. Set this equal to any number of seconds which you want to. Mine is going to be 300, and the second one using the let keyword, since we'll update this, is going to be equal to the countdownTime. Countdown time is going to begin at the initial gameLength. Then we'll reduce it by one second with setInterval. Initially, we'll set this equal to gameLength, then we'll reduce it as the game goes on. We also need to display this on the screen. We can do this with document.querySelector. We need to find a section which is up at the top so next to our buttons. This is the game control section where we have the start and the end game button, and we also have a span with the ID of gameLength. Pass this in, set the innerText. Since we're inserting the gameLength variable, we need the backticks will say the game length is insert the variable, which is our gameLength number, followed by the text of seconds. Reload and there's our text at the top. We now need to do two things. The first is to create a function to deduct this variable by one second. Then we can call this function once every second using setInterval. First at the bottom, create our new function called countdownTimer, which is going to be responsible for grabbing our variable, which is countdown Time and deducting this by one second. Each time we do this, we also need to grab the same elements up at the top and update it with this new time. Just like we did at the top, we use document.querySelector, pass it in the same section, which was gameLength, the innerText , open the backticks. This time we'll say the time left is equal to our variable just above. This function doesn't actually do anything on its own. It's simply responsible for selecting our countdownTime variable and then deduct in one second. To also assign this to the existing variable, we also need to place in an equals, and then this adds this to the DOM. This function is responsible for deduct in a second, but we still need to call this function every second. To do this, we'll jump into our game start function. Into the bottom, we'll setInterval once more, pass in our function, which is the countdownTimer, which will run every second. Let's try this out. Refresh and we'll see our text at the very top. You can start. Then our timer begins to count down. However, though, if we start this once more, you will notice a small issue. If we look closely, the countdown doesn't begin for the first second. We'll click. We have to wait one second before the countdown. This happens because setInterval will not call the function immediately. Instead, it waits for the time delay first and then calls this afterwards. This is a pretty simple fix. All we need to do is to grab our countdown timer and call this once just before our timer starts. Now, if we refresh, click on "Start," our timer begins immediately. This is how we can use setInterval, which is a really useful method to learn as is another timing function called a setTimeout. This is what we're going to cover next. 36. setTimeout: SetInterval which we just looked at, repeatedly calls a function or runs some code with a time delay between each call. Another timing method we have available is called setTimeout. SetTimeout to run a function or some code once after a time delay. We can use this to run the endOfGame function once the timer is up. It looks similar to setInterval. Let's take a look at this down at the very bottom. This one is setTimeout, which like setInterval, also takes in two things. First is the code which we want to run and in our case, we want to run the endOfGame function. Separate it with a comma, the time delay before running this function again in milliseconds. So 2000 is a two-second delay. We can test this works by jumping into the endOfGame function and login to the console. Any text, try this out. So let's go for ended. Open up the console. Gives us two seconds and our function is now being called. But we want this function to run at the end of the game. So we can set the time delay to be the same as the length of the game. We have this stored inside of a variable at the very top, which is called game length, currently set to be 300 seconds. That's how this works rather than having to wait 300 seconds for our function call, I just drop this down to a small value such as three. Down to the very bottom, we can now set this as our time delay. So as we know that the game length is in three seconds with a time delay is in milliseconds, meaning we need to convert this by multiplying this by 1000. Okay, let's try this once more, refresh, and after three seconds, our function has now been called. So a little bit cleanup work before we move on, we'll remove our console log and the end of game function. Reinstate the game length to be at 300 seconds. Good. So this now works fine, but to save this code from running when the game is not started, we can wrap this into a function. So create a function called gameTimer, put this inside and this function can now be called when the game at first starts. So jump up to our start of game function , call our gameTimer. Still within this function, we can pass a message to the user. So what we're going to do is if we look at these messages area, we'll place in a message to say, "Chef, our first orders are coming in as soon as the game starts." We use setTimeout, then clear this after a certain amount of seconds. So the message is not permanently there. To begin at the very bottom, we'll grab the section with query selector. Let's take a look what the selector is for this part in the message area and we have this p with the ID of message. This is an ID, so use a hash, select the innerText content. My message is going to be, "Chef, our first orders are coming in." Then, just afterwards we'll then run a function after three seconds to remove this message from the screen. Once again, we can use setTimeout. As we've already learned, setTimeout and setInterval can either call a function by its name or can pass in a function directly. We can copy this line of code, paste this in. In fact, just before we do this, we'll remove these brackets. This needs to be set to an equals because innerText is a property rather than a method. The same for our second one. Let's set this one to be an empty string and then just after our brackets or the curly braces, we can add the time delay of 3000 milliseconds. Refresh, click on "Start" and our message is now placed into the messages area, and three seconds later it's now been removed. Good. So this is an introduction to JavaScript timers using setInterval and setTimeout. You can see how useful it can be in projects like this. We also have some more timers to add very soon. But next, we'll take a look at how to clear these timers when they are no longer needed. 37. Clearing Timers: We've covered both of these timers now which was setTimeout and also setInterval of these methods. Also have a clear count part 2 of clearTimeout and also clearInterval. These clear methods will stop the timers when we no longer need them, and this is useful for when the game is over. We can stop things like the countdown, so we can restart when needed. Not use up any of the browser's resources unnecessarily. To be able to clear a timer, we first need to store the original timer into a variable. First of all, we'll have our ordersTimer, which contains our setInterval. We reference to this inside a variable called orderTimerRef, that is equal to an empty string. Now to this next function we have the countdownTimer, and inside this doesn't contain a timeout directly. But if we take a look first, this one is called using setInterval. We'll place available just above this. This one is the countdownTimerRef. Also an empty string. Last one is the gameTimerRef. Notice here how we've declared these left variables outside of each function. This is because if we declare them inside the function, we won't be able to access them later on in other parts of our code. We will need to access these to clear the timers. We will cover this in more detail in a later section. This first one is going to be equal to our setInterval. The game timer reference is equal to our setTimeout. Also know this middle one, the countdownTimerRef, doesn't directly contain our timeout. What we can do is go up to our function, which is this startOfGame, and set this up there. So this startOfGame function. Set the countdownTimeRef to be equal to setInterval. These are all now stored inside of variables. Just before we clear this out, we first need to prove they are running. Console log can help us with this inside of our generateNewOrder function. Function generateNewOrder, place in a console log. It's actually is fine inside of here, such as order. [inaudible] the browser and refresh. Start the game. Our timer begins to countdown. We see our message has now been removed after three seconds. Our orders still keep coming in, and also our console log here too. But you'll notice if we click on "End," stop our game, our timer still counts down, our orders still keep coming. To fix this, we can clear all of these timers when we call the endOfGame function. Take a look for this and then inside, we call the clearInterval method, parsing in our orderTimerRef. The second one is also an interval, so we use clearInterval. This is the countdownTimerRef. For the third one, our game timer was a timeout. So we use clearTimeout for this one. Try this once more. Refresh. Starts our game. See the countdown, we see the orders. Click on the "End" button. Everything has now been stopped. If we again click on the "Start" button, everything carries on from where we left off. We see the timer continues from where it was paused, and also the orders keep coming in from where they left off too. But this is fine, we'll do some cleanup work very soon to fix these issues. The main thing here is our timers can now be stopped, when they are no longer needed. 38. Introduction To Javascript Date: Many applications and websites require being aware of the current date. We can track a user's sign-up date, the time between two events, and lots more, but this JavaScript has some built-in objects which can help us. To begin, we can call date as a function, just like this, with the brackets. Then store this inside of a variable, that date equal our date function. Then let's try this out with a console log. Place in the date variable and see what happens. Refresh and into the console, which will then return back the current date and also the time as a string, as does the constructor function, which we looked at earlier when creating new objects I placed in the new keyword. With the new date though, we can also pass in some values to create a different date too. Jump into the brackets in order we can pass in the year, the index number of the current month, the day, the hours, minutes, seconds, and milliseconds. We' re placing any year we want to, then the month index, which also begins at zero. January is zero and December is 11. Next, the date. Save and refresh this inside the console. This now reflects a date which we just placed in. This means this constructor function, it gives us the option to either get the current date or to set any date we want to, just like this. Working with date values like this can be difficult. If we want to compare two different dates, what we may need to do is to take the current string just like we're have in the console, split up our string and then compare each individual piece. As you can imagine, this is not an easy task. An alternative date format is to use a method called now. We can move the contents from date. With the new keyword, call it now method. Let's try this out and see what happens in the console. This gives us back a strange looking number. It may look a little strange, but it's a number in milliseconds since January the 1st, 1970 UTC. If we keep refreshing, each time we do this, this number will keep increasing. Although it's still not ideal, it can be a simpler way of comparing dates or times. For example, when a user signs up to our website, we could use Date.now to store the current time in milliseconds. Then on future visits, we can get the current time and compare the difference between these two numbers. The milliseconds would need to be converted to seconds, minutes, and days also, depending on what you needed to do with it. We'll look at this in a little more detail in an upcoming video. Available on the dates prototype is a range of methods which we can use to also set the date too. Let's take a look at these in the console. We could move the now method. Access the prototype object, refresh, and open this up. As we've just seen, we have the date constructor function and lots more of the use cases too, such as get the hours, get the full date, get the day. We've also got the setters, so we can set the current date, we can set the time. I'm not going to go through all of these since they are very specific to different use cases, but it works just like any other method. Use them since methods are on objects. We again need to use the new keyword to create a new date object. Let's remove this, place in the brackets, add the new keyword. One of the methods we've just seen in the console was getMonth. We've got this on our date variable. Let's see what returned back inside the console. This returns back the date of the current month. Again, this begins with zero, so January being zero, and February is number 1, and so on. GetDay will return the date of the current week. Let's try this. GetDay. That's what you've seeing with the prototype before. We also have access to some methods that also set the date too. Maybe we'll have an event which we'll already have saved and we'll maybe want to change the month or the year, which we could do just like this. Here, we've got the basic current date. Let's just remove this. Then below this, we're going to change the current month to anything which you want it to. Let's store this inside of a constant called updated date. Grab our current date variable, access one of our set methods such as setMonth, place an index number of 11, which will be December. Then a second console log just below, again with the date. We should be able to see the updated version with our second log. Refresh this. We start with March and then set our month to then be December. This is a basic introduction to JavaScript date. Up next, we'll make use of this date and time inside of our project, keep track of how long the pizzas have been in the oven. 39. Setting The Cooking Time: What we learned in the previous video, the task now is to set the cooking time for the pizza using JavaScript date. We are going to move the examples from the previous video. Now inside the add to oven function, we created a placeholder date early on. Let's take a look for this function, at the oven. Here we set the time added to be a string. This can now be updated to make use of the current date dynamically. As we've seen, we access the date object and the method called now. Remember date.now will be in milliseconds, so we can remove this from the oven after a certain amount of milliseconds have passed. But first before we do this we need to set the cooking time which we want to apply. This variable is perfect, so jump up to the rest of variables. Set up a constant called cooking time, which is equal to 20 seconds. Now to the very bottom of our script, here we can place in a new function which will loop over all of the pizzas inside the oven once every second. We'll then remove any pizzas which had been in for our set cooking time. Function, check oven. To check the oven once every second we can use a set interval. If you wanted to, you could create a separate standalone function or we can place in the function directly. This function is going to loop over all the items inside of our oven array. This oven array is stored in the oven variable, loop over using for each. Again, for each takes in a function which has access to each one of our individual pizzas in the oven. At the end of our set interval brackets, we can place in a time delay between each one of our function calls, which will be every second. For each item or each pizza inside of our loop facing an if statement. This if statement is going to check the time difference every second. We can say if date, but now, which is the current time in milliseconds, then deduct the cooking time. Remember the cooking time is in milliseconds. Let's convert this, multiply this by 1000. In its current calculation will give us the time 20 seconds ago. We can check if this value is greater than the current pizza.time added property. If it is, it's been in over 20 seconds and we'll need to remove this from the oven. Access our oven. The shift method, which is going to remove the 1st item from our array. We also need to access the 1st item because remember, the 1st item is going to be in the oven for the longest. This is always going to be the next one to remove. After we've removed this item from the array, we'll then need to reset the oven contents with the function, which is display of an items, which will effectively redraw the oven. We can also keep track here of the number of pizzas we have cooked, By increasing a variable. The variable of complete pizzas, an increases with plus plus. We haven't created this yet, so we jump up to the top with the rest of our variables. Let completed pizzas to begin at the value of zero, and this section will be useful later on when we add start to our game. Finally, we've actually created this function, but we've not yet called it. What we need to do is call our check oven function when we start the game. Jumping to the start of game function, places in down at the bottom. Let's try this out. Refresh the page. Start of game. Click on any order, add this to the oven, add a few more. Give this 20 seconds, and our pizza should then begin to be removed. The 1st one gone, or 2nd one just afterwards. Followed by our final two pizzas. 40. Introduction To The Canvas & Co-Ordinates: We can still stay within our project for this one and take a look at some examples down at the bottom. This video will cover some of the canvas basics. Then in the rest of this section, we will draw our pizzas and show the different toppings as we add them. First, let's cover an essential part and this is to understand using co-ordinates. There is a HTML element called Canvas which allows us to draw to it using JavaScript. We set the width and the height of the canvas, and then we can navigate this pixel-like grid using co-ordinates. The x-axis runs left to right, and the y-axis runs from top to bottom. Using these x and y positions, we can move to any location on the canvas and x,0, y,0 is the top left corner. We can then move across or down any amount we want to just like we see in this example, where x is equal to 10 and y is the value of 3. We'll soon see how understanding these co-ordinates are essential to drawing on the canvas. Back to our project and into our HTML file. We have a canvas elements already setup. If we take a look for our kitchen area, have this canvas elements with the ID of pizza area. It has the width of 250 and also the height of 250 pixels too. Jump into our script and let's go down to the very bottom of our script. Create a constant called canvas to store this inside of. Just like any other elements, we can use something like document.queryselector. As we've just seen, we can pass in an ID. This one is equal to pizza_area. Then we can call a method called getContext. Grab our variable, call the getContext method. Passing in a string of 2D. In this context is an object containing properties and methods we can use to draw to the canvas. We're only going to be needing the 2D features for these examples. Install this inside of a variable or a constant, which is generally called CTX, but this can be named anything which you want to. When using the canvas, two concepts which are important to understand is stroke and fill. Stroke is like a pencil line or an outline and fill, just like it sounds, fills a shape with a solid color. To draw a rectangle, we have strokeRect and also the fillRect method. Let's take a look at strokeRect to begin with. Although drawn features are available on the context. To draw the outline of a rectangle, we'll use strokeRect, and then we pass in four values. The first two just like we've seen in the slides, is the x and the y location for the top left corner of our rectangle. If we want this to begin at the top left, we set this as 0,0. Then we have the width and the height of the rectangle which you want to draw. This could either be a rectangle or also used to draw a square if we're passing equal values. Let's take a look at this. We'll say this and jump into the browser, give this a refresh and we see the outline of our 200 pixel by 200 pixel square. As well as also passing in hard-coded values just like this. We can also access our canvas variable from above. Pass this in and access the width property. We've already set these both inside of our elements. We've got 250 pixels for both of these values. We can insert these as variables. Try this out, refresh and because this is 250 pixels, this is now a little bit bigger than we originally had. Using these variables is really useful and we can also provide calculations based on their size. For example, if we only want this to be half the width of the canvas, we could divide this by 2. If you want this to be a solid rectangle or a solid square, we can change stroke to be fillRect. This will fill this with the default black color. The standard black generally doesn't look great, and we can also change this color to this. Let's duplicate our rectangles and we'll make the first one to be a stroke, and the second one we'll just make this a little bit different. Let's go for 100 by 100. Places, 20 pixels in from the top left of the canvas. Now we have a stroke and a filled rectangle. We can provide different colors for each one of these, starting with the stroke. Again, access the context. Since we're using a stroke and pass in the strokeStyle. Set this equal to a CSS-like value, such as green. I'm going to see to the green color has taken effect. Then just above our filled rectangle. We can also access the context and provide the property called fillStyle to affect this second square. This equal to any other color. Save this and refresh. This is how we can set different colors for each one of our shapes. This comes API also has an arc method to help with drawing arcs and circles. As always, we access this on the context ctx.arc. Unlike the squares which we've just drawn all the rectangles where the starting location is based on the top left, with a circle, this is based off the center. We can access the canvas width for the x-axis. Divide this by 2 to places in the middle of the canvas and also the same for the height. This is the starting location for our circle, but we still need to provide some more information. The next one is the radius of our circle. If you're unfamiliar with radiuses, this is basically half the width of the circle. The value from the center point to the outside. Let's go for 100. Then the last two values at the start and the end angle. These values are in radians rather than degrees. To begin, we'll add a starting angle of zero and then the end angle, a value of two radians. Let's give this a save and see what happens inside the browser. If we reload, we don't see any drawings on the canvas. This is because we need to say if we want this to be a stroke line or a solid fill like we did above. Just afterwards access the context. Hold the fill method, refresh, leaving us with a nice smile-like curve. Or we can just do the line with a stroke with ctx.stroke. You can also see that now we're doing the stroke line. This will also inherit the stroke style of green. To go full circle in radians, we need to multiply this value of 2 by math.pie which is the degree equivalent of 360 degrees. There's our green circle and as you can see now we've got a full circle. This is also placed in the center of the canvas because of our x and y locations. Just before we actually draw this to the canvas using stroke or fill, we can also set some additional properties such as the line width and also the color too. Let's start with the line width property, which we'll set to a pixel value of five. Then also available on the context is the strokeStyle. This is the same value we used above to set this to be green. But now we'll override this to be a different color. Before, I mentioned this is a CSS-like property so as well as just using the words like green or hot pink, we can also pass in the things like the x-value and set this to be a different color. I'm going to go for f5cf89. Try this out, leaving us with a 5-pixel line in a different color. Alongside these methods to draw preset shapes, we can also draw freehand lines too like a pencil tool if you've used a drawing application in the past. To demonstrate this, we can replicate this green outer rectangle or square and draw this free hand. We can comment out the first rectangle, which is these two lines here. Then draw this ourselves using co-ordinates. These are all available on the context. The first method is going to be moveTo. MoveTo is basically like picking up our pencil, moving this to a certain part of the paper which we want to begin from. This will move our co-ordinates without actually drawing a line. Just like our original square, this will begin in the top left of the canvas. To actually draw, we use the method called lineTo, which will draw a pencil line from our starting location to location which we set inside of here. Just like above, we can place in hard coded values just like this or we can access the variables such as canvas.width and canvas.height. Make this a full width of the canvas to go right across, access the canvas.width. Since we don't want to go down on the x-axis, we can leave this at the value of zero. Let's refresh. We don't see the line on the screen just yet because we need to call ctx.stroke to draw this onto the canvas. This is our first part of our square. The next part is to go downwards and draw this vertical line from our current location, access ctx, the lineTo. We still want to remain over on the right-hand side which we can access with the width of 250 or, again, using the canvas.widthproperty. Pass this in, canvas.width. Then to go down to the bottom of the canvas, we can access this with canvas.height. Duplicate this. We'll stay at the same height value of 250. But now we need to move over to the left-hand side, which is the x-value of zero. Save, refresh. Just one more to go. But now we need to move up to the top left corner, which is the position of 0,0. Good. This is r squared now on the canvas, we can also add a method at the very beginning, hold begin path, also available on the context. We'll place this at the very start just before we begin to draw our shape. This is useful because it clears out any existing paths from above, so we don't get any conflict. It also means the starting position is remembered. We can use closed path to return back to this location at any point. To see this, we can remove our last line, refresh. Rather than draw this manually, we can now return back to our starting location with ctx.closepath. It should work exactly the same as before, returning back to the original location. As well as creating squares, rectangles, circles, and also freehand drawing, we can also write text on the canvas too. First, we can set the font which we want to use, ctx.font, and set this equal to a string. The string can take in the size of the fonts and also the font family too. The method to draw our text is ctx.fillText. As you've probably guessed, there is also a corresponding strokeText method too. The first value is a string of our text, I just say Canvas API. Then a x and y location, which is the baseline of our text, so 20 and 200, Save and Refresh. There's our text and it's also pink because it will inherit the previous fillStyle property, which will have from above. Canvas can also be used for lots of other things too, and also other methods which we can explore and we can also even add images to the canvas which we can edit by accessing the pixels. In the upcoming videos, we're going to use a canvas to create the pizzas and also display the toppings which we added in the kitchen. 41. Setting Up The Ingredients: In the top of the script section, we have an ingredients array with some ingredients which we need to make out pizzas. This strings, all match the ingredients which are needed in the required steps from above. So if we go to the pizzas array, we see the required steps array. This contains the strings which match our ingredients. If you change any of these pizzas to use different ingredients, make sure the ingredients array is also updated to match too. This will be really important soon. What we'll do in this video is to loop through all of these ingredients, and then display them as buttons in the kitchen area. Once a pizza has been selected, the chef can then follow this method, and make the pizza using these buttons. Also making use of the canvas, each button will draw the ingredients onto the pizza. Let's now scroll down to the bottom of our project, and clean up the examples from the previous video. So we don't need anything such as the text. We don't need the freehand section. We don't need the circle. Don't need any of these squares or rectangles. But we do need to keep access to our canvas, and also the 2D context. After this create a new function which is called listIngredients, which will loop over all the ingredients array from above, and display this inside the browser. To access our ingredients array. Since this is an array, we can use the forEach method, which runs a function for each one of these values. This function is also going to take in an ingredient which is each array value. Then we need to create a button element for each one of these ingredients. So we could create one manually or remember, we also have access to our helper function called buildElement. This takes in two things. The first one is the type of elements we want to create, a button. The second one is the text content to display. This is the ingredients from our array, store this inside of a constant called ingredientElement. Then for our styling, we can also add a class called ingredient to access our constants, and add the class name of ingredient. The final stage is to add this to the DOM, documents.querySelector. The query selector which we need. Let's take a look at the index page. We need this div with the id of ingredients. Inside here we'll place in all of the contents of our array. Pass this in as a string. We use appendChild passing in our constant from above. So we could call this new function immediately. But it probably would make sense to add this to the gameStart function, take a look for the start of game. Inside of here, we'll call it from the bottom. Save, and then let's try this out. Refresh. Click the Start button, and all of our ingredients are now placed in the kitchen at the bottom. For the next step, we need to be able to click on any of these ingredients, and then do something. This something is going to be a function to keep track of the steps which we've taken down to the very bottom. Create a new function called stepComplete. Then a second function which is going to draw the ingredients onto the canvas. Function, make pizza. This stepComplete function needs to be called when the user clicks on any one of our ingredients from just above. So for this, just before we add this to the DOM, we can add an event listener by accessing our ingredientEelements.add event listener. This now for a click, which will trigger a function called stepComplete. Since this is a click event, it's also going to take in the event information which we can store in the variable. This stepComplete e function can also now be used to disable the button once it's clicked on, and also keep track of these steps we've taken. So step 1 is going to disable the button when the user clicks on it. So we can't be clicked on twice. I'm going do this by accessing our elements with e.target. We can set an attribute. Attribute is disabled with a value of true. Then step 2, we need to access the actual text content of our button. So we'll know the ingredient name. For example, we need to grab the roll dough text, the pizza sauce, or the cheese, and so on. Store this inside of a constant called step name, access our elements with e.target. Then the inner text content. Before we go any further, let's check if this is working. Place in a console log. We have step name. Onto the browser, and into the console. Start the game. Click on any one of our buttons, such as cheese, pizza sauce. These buttons are also now disabled too. Keep track of the steps which we've taken, all the buttons we've clicked on. We need to store this inside of a variable containing an array. So jump up to our variables. At the bottom let completed steps to be equal to an empty array. Down to the bottom. We can now remove the console log, access this variable of completed steps, access the push method, and then we can push a new value to this array, which is our step name. The last thing is to call our make pizza function to draw a new ingredient to the canvas. Of course, it doesn't do anything just yet, but we can place this inside of the function. So make pizza. Pass in pizza ingredient of step name. Now since we pass in an ingredients, we can set this inside of our function, and test if this is working with a console log. Let's just remove any other console logs we have. So we've got the order wrapper, got the oven, text of order. Then refresh, start up again, and click on any one of these ingredients. There we go. There's our new ingredients from make pizza console log. This now leaves us ready to actually draw a certain ingredients to the canvas. For example, if the make pizza function receives pizza sauce, it will draw some red sauce on our pizza. This is what we'll move on to next. 42. Drawing Circular Ingredients: Down at the bottom of our script, we currently have this makePizza function and this is being called each time I add a new ingredients. It's also been past this ingredients. What I'd like to do now is to create a switch statement to handle which ingredient has been clicked on. We can then draw this ingredient onto our pizza by the canvas. Since we have different ingredient options, as we just mentioned, we'll replace this with a switch statement to handle each one of our cases. Passing the ingredient which is being clicked on, and then we'll create a case for each one. The first case, this is going to be a string and if we scroll up near the top, we have our ingredients right here and each one of the cases is going to match each one of these strings. Back down, the first one in capitals was for ROLL DOUGH. We'll handle what to do in just a moment, but for now we'll just break out of this and we'll just copy each one of our ingredients. The second case, this one was PIZZA SAUCE. The third one for CHEESE, and then PEPPERONI. Next one was for HAM and PINEAPPLE. I'm just going to leave this as the set of ingredients for now and you can add all the rest if you prefer, but I'm going to move on because this will be really long otherwise. Now inside of each one of these cases, we can set up some canvas drawing functions to represent the particular ingredients. For the dough, for the pizza sauce and also for the cheese, these can be reasonably simple, we just need to draw some circles. We'll start with the roll dough. We know from previous videos that to draw a circle on the canvas we use ctx.arc, then we provide the starting location which is going to be in the center. canvas.width divided by two and also the same for the height. This is the starting x and y position. The next one is going to be the radius. Let's go for 100 pixels. Just like earlier, to create a full circle in radians, the starting position is zero and then the end position is two multiplied by the value of Math.Pi. Remember that from earlier videos when we used ctx.arc, it didn't actually initially draw anything onto the canvas. What we need to do is to either use ctx.stroke or ctx.fill to draw this, but in fact, we're going to actually use both of these. The reason being is we'll use the fill method to draw the full pizza base onto the canvas. We'll also do an additional stroke method, which is also going to add a 15 pixel outer circle onto this dough. The reason being, we'll set this to be a slightly different color to give us the effect of the outer crust. First of all, what we'll do is we'll concentrate on the crust and we'll do this with ctx.lineWidth, set this to be a value of 15 pixels, then we'll set the color with strokeStyle passing in a string which is going to be a hex value of f5cf89 and to finally draw this, we use ctx.stroke. This should now give us an outline based off our arc. Let's try this out, refresh, start up again, select any one of our pizzas, the roll dough, and we now see the outer circle of our pizza. As mentioned, this is the crust, so we also need to add the fill method to also fill the inner part of the circle, but a slightly lighter color just after the stroke. Put the color for our fill method and this one is going to be f5d69d, then fill the circle with this color. Let's try this out. Jump in again and start over again, select any one of our pizzas. Roll dough. We shouldn't have this black color so let's take a look. This fillStyle actually just needs the hash just before. Start. Select one of our pizzas, roll dough, and it's now looks a lot better. Now, down to our pizza sauce, which is also going to be a circle but slightly smaller than our dough. We don't have any conflicts from above. We'll begin this section with ctx.beginPath. This also needs a circle, so we can copy the ctx.arc method from above, which also is going to need to be in the center of the canvas. We do need to change the color. This is going to be filled, so we'll use fillStyle, and this one will be ed4434, finally, call ctx.fill. Next, we'll also move on to the cheese, which is still a circular join function. We'll copy all of the pizza sauce section, paste this into our cheese area, make the circle a little bit smaller so we can still see the sauce around the edge, but we do also need to change the color. This one is f7bc4d. Let's save this and try this out before we go any further. Again, we can select any pizza, pineapple, roll dough. This is fine as we've seen. Next we'll try out the pizza sauce and this is all fine and this covers the same fill section as the above dough area, but we can still see the stroke outline from above. Next, we'll have the cheese, which is a slightly smaller circle, so it doesn't fully cover up all of the tomato base. Good. We'll leave this one here for now and in the upcoming video, we'll take a look at the next ingredients, which is going to be a little bit more complex than these circles. Rather than creating circles like we're just doing, we're going to involve multiple pieces at different locations. We'll see you in the next one, where we'll take a look at how to do this. 43. Drawing Multiple Pieces: Going off my version of this switch statement, I still have the pepperoni, the ham, and also the pineapple pieces to create. Since these are all separate pieces, we're going to be drawn lots of different shapes onto our pizza-shaped Canvas. To begin, in the pepperoni, just underneath the case, since we're using multiple pieces for these ingredients, we need to create an array of locations. Const, pepperoni positions, which is going to be an array. In fact, this is going to be an array of arrays because this is going to be an array of multiple values. Also, each one of these values needs to have an x and a y location for each one of these pieces. The first one, and of course these all need to be kept inside of the dimensions of the pizza. But these are all random numbers. We can add these in and play around with them if you want to afterwards, or you can copy along with mine. The third one is going to be 147 and 57. Remember that each one of these sub-arrays is going to be new piece of pepperoni. The fourth one, you can add as many or as few these as you would like to, 116, 134, 125, 190, 162, 165, 190, 85, 192, 142, 150, 115, 76, 95. I want to start a couple more pieces. Let's go for 80, 190, and the final one, 61 and 135. Make sure this is just before the break clause and before we do anything else, let's think about exactly what we need to do here. A piece of pepperoni is just a small circle. We know how to draw this using the arc. But the difference will need to repeat this arc for each one of these locations. This is where a loop can come in. What we'll do is we'll grab our constants of pepperoni positions. Then we'll call a for each loop on this array. Pass in a function which takes in the variable name of piece. Piece is going to be each one of these individual pieces of pepperoni which we'll draw. To do this, we'll begin with ctx.beginPath without any existing paths which may be drawn. ctx.arc, draw each one of the circles for the pieces of pepperoni. Then remember, this takes in the x and the y location for the center of the circle. Since what needs to be based on the above locations, what we're going to do is to access our piece. The first index position of zero, and for the y location, it'll be peace and then the index number of one. Pass this in. Piece, access the index number of zero, the y location is this peace and the index number of one, size of 10. Let's create a circle it as zero and then math.Pi multiplied by 2. Let's give it a color with ctx.fillStyle. Just before we draw this, which is equal to a string, I want to go for the hex value of BD 3611. Then finally, we'll draw this with ctx.fill give this our solid background color. Let's give this a try. Jump into the browser. We need to start our game and select any one of our orders. Also, pizza, we'll roll the dough, add the source, the cheese. We know this is working, next the pepperoni. There's all of our circles which are all based of our array, which we created inside of here. Good. Now down to the ham and you can also give us a go if you want to yourself, you feel confident doing so. This is going to be based off a similar approach to above. First, we need to create our ham positions, which is an array which also contains subarrays, contain now x and y locations. Let's first create these and store them inside of a constant called hamPositions, our main array. Then create our random locations. The first one, the second one of 108, 74, number 3, 147, 47, 130, 124. Again, you can make these completely random and change these if you want to, 125, 160. Make sure that these all stay within the pizza Canvas area, 159, 145, 197, 82, 202, 132, 158, and 90. We're almost there now let's keep going with the final two, we'll do 90, 140 and the last one of 105 and 135. Just like above, we'll loop through these with a forEach loop. We'll select our ham positions called a forEach loop on the array, which takes in a function each piece. But this time, rather than creating circles using the arc method, I'm going to use the fillRect method to draw these as a rectangle. First, we'll set a color with ctx.fillStyle, and set this equal to a string, which is f58c8c. Next, ctx.fillRect. Draw a solid rectangle on the Canvas. Just like above, this is going to take in the x and y positions, which we can access just like this with our array positions x. This is the piece and the index number of zero, which corresponds to each one of these first array values. Then the second array value of piece what's in the index number of one. Remember with rectangles, this is the x and y location for the top left corner of the rectangle or the square, we'll also need to set the size, which we want to set to eight pixels wide, 32 pixels tall. Let's try this out before we go any further. This is for the ham. Click on this and we have lots of pink ham pieces now on pizza. You can play around with the positions if you want to make it look a little bit better. But I'm going to move on to the next one, which is pineapple. To save little time, a lot of this is going to be similar to our ham position so let's copy all of this section, including the for-loop. Paste this just below our pineapple case. Of course, it's going to be the pineapple positions. Change it for the loop. Make play around with these values afterwards if you want to. For the fillStyle, we'll change the color of these to be yellow color of ebe534, make them a little bit different in terms of size, 12 and 18. Create the cells inside the browser start. Our pizza. The pineapple also works too. Just like mentioned, you may need to change its position so we don't have any overlaps. One last thing before we wrap up this video is we're also going to make sure that the pieces of pineapple and the ham a placed on the pizza at different angles. Currently, it looks a bit boring because everything is facing the same direction. Let's mix up this angle a little for each one of these pieces. We can do this with rotate. That starts in the ham section. Just before we draw this with fillRect. We can access rotate, which is also available on the context. This rotation value is in radians, not degrees. A way to convert this to a degree is just like this. We can pass in our initial value. If we wanted this to be rotated by a small value such as five degrees, we can convert this to radians by multiplying this by math.PI divided by 180. This makes it a lot simpler to work with degrees if it's a lot easier to wrap around this inside your head. But we don't want to keep this hard-coded value of five. The whole point of adding this rotate for each one of these pieces is to make it a slightly different value for each one. We can do adding in Math.random, which will place in a slightly different value for each one of our positions and to make it a slightly larger angle, because remember Math.random is only between 0 and 1. We can multiply this by 2. That's also copy this rotate method, and we can reuse this inside of the pineapple. Just before we use fillRect, let's try this out, refresh and starts up again. The pizza sauce, the cheese, pepperoni, next to ham. If you take a close look, these pieces are slightly out of alignment. Also with the pineapple too, but with a pineapple, as you can see, we have a small issue. This is when we use multiple ingredients with rotation values. This happens because of the rotation at transform. When we rotate, the Canvas will rotate from the canvas origin, which is 0,0, all the top-left. If we add multiple rotations, each one adds on to the previous one, which we have set. We set one for the ham, and then we add to this by adding the rotation for the pineapple. We can fix this by resetting the origin for each new ingredients using something called set transform. For this, inside of our function, I'll make pizza function. Just before the switch statements. We want to call this ctx.set transform, which is going to take in six values. The six values will be 1, 0, 0, 1, 0, 0. These six different values can be a little confusing, especially as they are not particularly grouped together. We can see the first value of one and the fourth value is also one. Both of these relate to the scaling, which can make an item larger or smaller. The first one is the horizontal scaling, and the fourth one is a vertical scaling. We don't want any of these values to be increased or decreased so we keep these at one, which is the original size. The second of third value both relate to the skewing. We don't want to skew any one of our pieces either. We're keeping these as zero, which means nothing to be set. The things that we are interested in is these final two. These final two we set in the horizontal and the vertical translation to be back to zero. Each time we select a new ingredients, the rotation transform, which will look before the reset back to zero, meaning we don't get a buildup of these rotation values. Let's try this with the transform now in place. Select an order. Now what we're looking for is both the ham and the pineapple pieces to be back in the original locations. This is all working fine now. As mentioned, you can create more of these cases for different ingredients if you prefer or if you'd like some extra practice. The next, when you are ready, I will see you in the upcoming video where we'll clear out this Canvas once the pizza has been completed. 44. Clearing The Canvas: When we're finished making the pizza, adding the toppings, and then finally add it to the oven, we need to clear the existing Canvas ready to make the next one. As you may have guessed, we create a function which is going to cover this, and we'll do this at the bottom of our script. Create a new function inside of here to cover this called clearCanvas. The first task I'm going to do it inside this function if we go into the Start here and we'll select one of our orders. Remember, when we'll make each one of these pizzas and we click on the ingredients, it then renders the button disabled. What we'll do is we'll select all of these buttons to begin. We'll loop over these buttons and then we'll remove this disabled attribute. The first one is to setup a constant called steps. This is going to loop over all of our buttons with the class name of ingredients. Document.getElementsByClassName. The class name attached to each one of these buttons is ingredients. A little bit more space for this and if you remember from the early videos when we use getElementsByClassName, rather than returning back in array, this will return back at HTML collection. We have HTML collections. We can't use any of the array methods such as for each. What we're going to do is to grab our steps and then we'll convert this to an array, which will mean we can use our forEach to loop over each one of these. We'll do this with Array.from. This will create a new array from our steps. Place this in. Now we have an array, we can use array methods just like forEach, pass in our function. We'll have access to each one of the elements. From these, elements, they can remove attribute passing in the string of disabled. This now it should loop over all of our ingredients and remove the disabled attribute so that are available for selection on the next pizza. Next, as we looked at in the previous video, we sometimes have an issue where we have any rotation values for the ham and pineapple. What we're going to do is to grab or set transform at the top of the switch statement, which is just here. The current values inside of here will reset our transform if any existing rotations are taking place. The final step is to clear anything which is currently on the Canvas and we've used this in the past with ctx.clearRect. We begin at the top left of our Canvas, which is zero, zero and to clear the full size of the Canvas, we can access our variables with canvas.width and also canvas.height. That's it. That's our function now complete. The last thing to do is to call this function from addToOven. We'll select this and take a look for the function called addToOven. Just under displayOvenItems, paste this into our if statements. While here there's also one quick step we can introduce, which is to grab our variable which is completedSteps. Reset this to be an empty array. Let's give this a try. Refresh the browser and it starts up again. Select an order. Currently on ham and pineapple, so we roll the dough, add the sauce, cheese, ham, and pineapple. Add this to the oven and now our Canvas is being cleared and all of the ingredients is still available for selection on our next pizza. I'll try one more, the pepperoni, add the ingredients, add this to the oven, and this all works as expected. This is now it for our work on the Canvas and you can play around with things, you can extend things, and you can even add the extra ingredients if you want to. Now let's now move on to the next section where we'll finish off this project. 45. Wasting Pizzas: This new section is going to involve finishing off our project. One of the things we need to take care of is to check the chef has completed all the required steps before adding the pizza to the oven. So i.e. if the pizza is wrong, it will be wasted. That is what we're going to cover now. Later on, we will also display some stats to the user, so we can keep track of these wasted pizzas inside a variable. Let's jump up to the top of our index.js. Scroll down to our variables. Using the let keyword, create a new variable called wastedPizzas, and we'll keep track of how many of these we've got wrong. Then it go back to the bottom of our script, and we'll create a new function to handle this. Set this up, call the wastedPizza. Before we forget, we'll grab our wastedPizzas variable from the top and we'll increase this and use this with the stats later on. Next, we'll clear any steps ready for the next pizza. CompletedSteps, reset this to be an empty array. Then finally, we'll call clearCanvas. This was the function which was set up in the previous video, which is going to reset the canvas and also remove the disabled attribute. Over to the index page. Inside the main kitchen area, we also have a button which we can link this up to. We'll add an EventListener to this element which has gone to call our new function. Below our function documents.querySelector. This button. If we just take a look, this had the ID of waste. Add an EventListener, where we'll listen out for the click event, which is going to call our above function. Let's try this out, save and go back to our game and start over. Select an order. We'll do this wrong, we'll just click on these in the wrong order. Click waste. Now a canvas is now being reset and we see we don't have this item inside of the oven. This now sets us up for the upcoming video, where we'll check if the chef has taken the correct steps to make this pizza. If not, this function will again be called, but this time automatically. 46. Checking Steps: This wasted pizza function which we just created will also be useful once again, because we're now going to check that the chef has taken the correct steps, or i.e., added the correct ingredients onto the pizza before adding this to the oven. If they got this wrong, it'll be then again, a wasted pizza. Just to say this, if we go into our game, select any one of our pizzas. Currently before we add any of the toppings, we can click on the oven and add this without the correct ingredients. We can also keep going and add in more of these too. To check the ingredients, we can create a new function. I'm going to do this just after we add this to the oven. Take a look at our function called add to oven, which is a little bit further up. It's been awhile since we've seen this one. This is add to oven. Just after this, we'll create our new function, which is the steps completed. Inside here, we also need to take in the pizza name, which we are currently comparing against. We can check if we have the steps correct. So passing the pizza name, which we'll add in when we call this function. This function will return back either a true or false Boolean depending on if these steps are correct or not. It's true or false value will determine if we can add the pizza to the oven and we'll call this from our add to oven function. Jump inside of the if statement where we check if we have a pizza name, create a constant to store back the returned value from our function which we'll look at in just a minute. We'll call this can add to oven. Remember, this will be either a true or false value, and this will be equal to our function called steps completed. Remember this also needs to take in at the pizza name, which we have stored above in this variable. Just below this, we then create in our pizza object to go inside the oven. Now we're pushing this to the oven array. But just before we do this, we only want to make sure this happens if the can add to oven variable is true. What we'll do is we'll cut out all of this information from our object all the way down to completed steps. Pass in an if statement to check if can add the oven is equal to true. If it is, paste this back in. Our pizza is now able to be added to the oven. Let's do a quick test and check this works. We'll go into our new function, and for now, we'll simply return the value if true. We should be able to add any of the current pizzas to the oven. Let's try this. Click the oven, and it's works. But now if we stop the game and return false, hopefully should now block all pizzas from being pushed to the oven. I'll select one, and this now blocks all pizza from going into this section. This means we can now add some real conditions to check against inside of here. To do this, we need to grab the steps from all pizzas array. To begin, we need to actually select our pizza objects. Here we'd been passed at the pizza name and if we take a look for our pizzas array up at the top. We're going to use this name to find our particular pizza and then return back the full object so we can access these required steps. Let's go down and do this now. We can move the return statements, access our full pizzas array, and then use the JavaScript find method to search via this pizza name. To do this, we'll run a function for each one of the items inside of our array and store this inside of a variable called pizza. This find method is going to return back a new value. We want to check if the pizza which we are currently accessing has a name property which is equal to our pizza name, and then it we'll store this returned value inside of a constant called pizza objects. The next thing to do is to grab the steps from this object, and again store this inside of a variable or constant. This one is called the steps required, and we'll set this equal to our above pizza object. Filter this down to only save the required steps. Now if we go back up to our pizza object at the very top of the script, this is the required steps property which we just accessed. This is an array of all of the values. We now have all of these values which it takes to build a pizza, and also if you remember from earlier, scroll down to our variables. We also have a variable called completed steps, which is added to as a chef clicks on each one of the ingredients. We now need to compare these two arrays and check that all of the included steps have been taken care of. Also, if we think about this for a pizza to be ready to go into the oven, not only did the completed steps need to be correct, but they also need to be in the same order too. For example, if I have the dough, the cheese, and the sauce in that particular order, it technically would match a margarita. But we don't want the source to be on top of the cheese or the dough to be added last. We can check this using a JavaScript array method called every. Back down to our function, what I'm going to do is to type out this function and then we can talk about what is going on just afterwards. We can access our steps required, which is the array of all of the steps required to create a pizza and then call this method which we just mentioned, which was every. This will run a function for each one of our array values. Passing in as arguments, the element, the index, and then return back a value, which is if the element is equal to the completed steps as in the index. Also finally, we'll just store this returned value inside of a constant called check steps. Just to explain what was going on here, we're going to loop through all of the required steps, and then we'll store this inside of the element value. For example, on the very first required step, which is generally role dough, this would be the value of this element. The index number would of course be zero. Then below we check again for the very first one if this roll dough value is equal to the first value in completed steps. If this pizza has been created, both of these value should be equal to roll dough. On the second loop, this would generally be equal to sauce. Then we check if the source is the second value and so on. Every method will return true if all of them are a match or false if a single one or more fail. This is the main test to check if the pizza is correct before going into the oven. If we wanted to, we could simply use this as our one and only check but if we use this, the chef doesn't know exactly which ingredients has caused the issue. He won't know if he used too many ingredients, not enough ingredients or the wrong ones. To help with this, I'm going to set up multiple conditions so we can give different error messages. This will pass in some if statements to perform some checks. But the first one, we'll check if too many ingredients have been added. We want to know if the length of the completed steps is greater than the length of the steps required. If completed steps, the length is greater than the steps required. If it is for now we'll just place in a console log and we'll say too many. Copy this, paste this in below, and changes this to the less than symbol. We can check if not enough ingredients have been used. If this happens will say not enough inside the console log. The third one we'll check if both of these values are equal, so just make sure this is spelled correctly. We'll check if the completed steps is equal to the required steps. We'll also check if the ingredients are incorrect. We can do this with our checkSteps variable and checking if the value is equal to false by adding an exclamation. Basically we've taken the correct amount of steps but the ingredients are incorrect, but this will log to the console the value of wrong ingredients. Let's check this out over in the console. Open up the developer tools. We'll start up again. Select one of our pizzas and let's go for pepperoni which is a simple one. We need to roll the dough with pizza sauce. Hopefully this one will add too many ingredients, will click on too many options. Try to add to the oven, I see too many, refresh. Let's do this once more, margarita. We'll only click on one of these ingredients. At the oven this is not enough ingredients, and then the third and final one we'll check if we've included the wrong ingredients with the right amount of steps. Let's test this. We know that the pepperoni has the roll dough, it has the sauce, the cheese, and pepperoni, so we need to take four steps but make sure that these are incorrect. Pepperoni, I will add some ham onto this. Make sure we are at four steps. Click on the Oven and we can see we've used the wrong ingredients. Good. We have our messages and these also now need to be shown to the user, and we can do this if we go over to our index.html. Let's take a look. For our Message area we have this surrounding div and our messages for the chef, and then this p with the id of message. We could write these messages directly into each one of our IF statements and I'll put these on the screen but instead let's create a standalone function to handle these since we will be repeating these multiple times. Let's add our function called showErrorMessage. Pass in the message which we want to display. if that's all we'll select our Message area which we've just seen inside of the index page with document.querySelector. Pass in the id of message, set the innerText content equal the message variable. Now once the chef has made a mistake we want this to disappear after a certain amount of time and we can do this with a setTimeout. Pass this in which takes in a function , separated by comma. The second value is going to be the time delay in milliseconds, so let's say two seconds. Open up the function body. All we'll do inside of here is copy this Message area, paste this in. Let's set this to be an empty string. We can now call this function called showErrorMessage and place console logs just above. Paste this in, add in a string. Also you have used too many ingredients. Copy this. The second one you have not used enough ingredients, and the third one you've used the wrong ingredients. Let's try this out. Again, we'll do the same test as before. Select an order, so we'll do too few. You've not used enough ingredients , then we use too many. That's good. Then the last one when we use the wrong ingredients, so pepperoni. I'll add four steps; roll dough, pizza sauce, and peppers, and there we go. The last thing to do is to make sure that these pizzas only add to the oven if the ingredients and the steps are correct. Currently as we looked at earlier this controlled with this IF statement, and this will only add to the oven if this is true. We need to cut this true or false value, return it back from overblow function called stepsCompleted. Currently this function is running and we're doing all of our checks but we're not yet returning a true or false value, so we need to add this at the very bottom. We'll only want this to return true also if the oven capacity has not yet been reached. Earlier we set up variables called oven and also ovenCapacity which we can see just here. I have the oven which is an empty array and also the ovenCapacity too. We set this to only hold six pizzas. We also want to do a check to make sure that we don't have too many pizzas in the oven before we return the value of true. We'll cut this out. Add an IF statement where we'll check if the oven.length is less than the oven capacity which is currently six. If it is we'll then return true, if not we'll return false. We're almost there now but we'll also do need to take care of what happens if we've used the wrong ingredients, because if we mess up a pizza we also want to run our wastedPizza function which we created previously. We can do this inside of our IF statements. If we've used too many ingredients this is a incorrect pizza, run our wastedPizza function, then return out of this. The next step is middle one is to check if we've used not enough ingredients. However, we don't want to run the wastedPizza function because they can still have the chance to add the correct ingredients afterwards. All we do is return out of this. For the last one where I've used the wrong ingredients we again want to run the wastedPizza function, return out of this. This should now leave us ready to give this a try when we created the wastedPizza function down at the bottom in the previous video. Let's take a look for this. This also clears the Canvas too. We know if this function is being run and we'll also know if the return value of true has been triggered because we should see a pizza in the oven, so we'll refresh and try this out. First of all let's select the pepperoni. I'll give this a go for the correct ingredients : the dough, the sauce, the cheese, the pepperoni, and this the oven. This is good. The is [inaudible] now being cleared so we'll try one more, the ham and pineapple. For this one we'll make it incorrect. We'll add the wrong ingredient, so not too many. This all seems to work in because this pizza is not added to the oven yet the canvas at the bottom is still cleared and ready to add a new pizza. 47. Completing Orders: When we've completed all the pizzas on any given order, it would be a good idea to complete the order so we can move on to the next one. This is what we'll focus on in this video. Just before this, I want to fix a small issue. This issue, if we go over to the browser, and Start our game. Click on any one of these orders. The issue is we can click on these ingredients before we've even selected one of our pizzas. Not only does this leave our project feeling a little bit strange, it also means we can't add a pizza to the oven because we check these selected ingredients against the clicked on pizza. To fix this, all we need to do is to check if the current pizza section is set when we click on any ingredients. To do this, take a look for the stepComplete function, so I'm going to do a search. This is the one we need, just here. First, before we check if a step is complete, we can do an if statement at the very top. This is going to check if we have a pizza selected. Where we can do this, if we go to our Index.html into the kitchen area, just here, we can see we have this span with the ID of current pizza. When we select one of the pizzas or order, it's then placed in this section. We can check if it has any contents inside of this elements. We do this by selecting this with document.querySelector. This is an ID, so pass in the hash. The ID was current_pizza. We could check if there is any inner text inside of here, or if it's equal to an empty string. If this is empty, we have an issue, we've not selected a pizza. What we're going to do is to access our function called showErrorMessage, pass it in a string of first, select a pizza you would like to work on, and then, we return out of this, so no code below is run. Let's give it a test. We can go over to the browser, Start our game, and select one of our orders. Now before we select one of our pizzas, we'll try to add in ingredients such as roll dough, and we see our error message just here. The step is no longer marked as complete as we can see by the fact that this button is not disabled. Now onto completing our order. For this, for example, this has three pizzas. Then we want to make all three of these, and then complete our order. Now for this, before we let the player complete it, it would be good to first check that they've actually created enough pizzas to complete the order. Step 1 will be to store somewhere the number of pizzas on each order. There is many ways we could approach this, but I'm going to store it as an attribute when we create the order. Take a look for the function called createListOfPizzas , which is this one just here. Inside of here where we built our particular elements, we have a span with the current pizza quantity. For example, this could be two margheritas or one pepperoni. Now, we can add the quantity of each order line to a variable. Let's create this variable just above, so we can keep track of this. whole total pizzas, and we'll initially set this to be a value of zero. We'll then reset this each time we create our list of pizzas by setting this to be a value of zero. Then, just below this, we can add the current pizza quantity to the existing total pizzas variable. Just to clarify what we're doing here, if we have an order, for example, this first one has three pizzas, this one has three, and this one has four. What we're doing is we're looping over all of the pizzas, and then adding in this quantity to our variable. Then we have this total for the order, which we can reference against in the future. As mentioned before, we are going to use this total pizzas quantity, and add this to our order as an attribute. We can do this when we create the order. We need to take a look for the function called createSingleOrder, which is just below. Just below our pizza list, what we'll do is we'll grab the order wrapper, we'll set attribute, which we've used in the past. The attribute, this is going to be a custom attribute, it's not one of the built-in ones which we already have. Generally, when adding our own custom attributes, we have the data prefix. This is data, total pizzas, and then the value, which is our above variable which we created called total pizzas. What we're basically doing here is each time we create a new order, we're adding a data attribute called data-total-pizzas, with the total number of pizzas on the order. If we save this, we can jump into the developer tools and check this is all working. Refresh, and then Start our game. Now if we select one of our orders, take a look for the class of order wrapper, and you can see each one has this new attribute called data-total-pizzas, and the quantity for each one of these orders. This means we now have the total number of orders we need to create. Earlier, if we take a look at the variables, we also created a variable called pizzas complete for order, which we have here. This is increased each time we add a new pizza to the oven, giving us the two values which will now need to compare. To do this, we also need to create a button to complete the order, which the chef can trigger inside the kitchen. This button will trigger a function, and we can set this in the select current order function. Take a look for this, select current order. I'm going to create a button inside of here, because this is where we set the current order which we're working on. Down to the bottom, just under this last line of code, but still within the if statement, and below this, and we'll create a constant called completeButton. From early, we have the function called buildElement, which will create a new HTML new for us. The first button is the type of element we want to create, which is a button and the value which is the text of complete. Then, we can access this button, add a class name of complete_btn. This button needs to trigger a function so we can add an event listener, so completeButton.addEventlistener. Well, it's now for a click, which is going to trigger a function which we'll create in just a moment called completeOrder. Finally, we'll have our orderDiv, which is this current working on section. We grab this, and then we can add appendChild. Pass it in our Complete button. We'll test this all by adding a simple alert inside of this function. Create the function called completeOrder. Now I alert with the text of complete. Let's jump into the browser and check this works. Refresh and click on the "Start". Select one of our orders. There's our new Complete button which will trigger an alert when clicked on. Good. Now we know this works and it's been triggered, we can remove this alert, and then, we can do our comparison between the total number of pizzas on the order and the number which we have currently created. First, we'll grab our current order, we stored this inside of a constant called currentOrder. I'm going to grab this with document.querySelector. Now, how do we go about selecting the current order which we're working on? Well, if you remember from earlier, when we clicked on the "Start" button, all of the orders inside of the sidebar, if we select one of this class of order_wrapper, and then, when we click on one, it's moved over to the working on section. The working on section also has an ID too. If we scroll up, this is the section, just here. We can grab the order wrapper which is contained inside of this working on section. We can do this by passing it in a CSS selector. The working on section, grabbing our section just here. Then we can grab our section inside, which has this class of order wrapper. We can do this just like with CSS, use the greater than symbol, and with this being a class, we use the.order_wrapper. Select this stored order. Remember inside of this order we added the total number of pizzas for this order, inside of a custom attribute. We can use get attribute, pass it in the attribute name which we gave this, and this was data-total-pizzas. Store this inside of a constant called totalPizzasOnOrder. Then, we can finally do our check below inside of an if statement. We've got the total number of pizzas which we should have, and we also have the variable stored from earlier called pizzas complete for order. We can check if pizzas completed for order is less than the value above called total pizzas on order, if it is, we have an error, so we can pass it in our function called showErrorMessage with the text of "You have not made enough pizzas to complete this order." Then return out of this. Let's give this a try. Save this and Refresh. What we need to do now is to Start our game. For our first-order, this has three pizzas, so click on this. Now if we try to add one to the other, and let's go for the ham and pineapple. We'll create the very first one. Add this to the oven. We only have one, click on "Complete". Now we get the error message inside of here. This now all seems to be working. We can move on to actually removing the order once it's complete. Just below the if statement, we want to grab our current order which we have stored from above, and remove this from the working on section with the remove method. This will actually remove the order from this section, but this will actually only remove the order which includes the title and the pizzas, we still need to take care of removing the button. The way way can grab this button is remember this complete order function is being triggered from our click handler on the button, so we can pass it in the actual, put in information with the event. We can access this with e.target. We stored this inside of a variable called Complete button. Just like above, we can access this variable, and call the method called remove to remove this from the DOM. We're also going to add some stats to this game later on, such as the number of completed orders. We're going to prepare for this by creating a variable of at the top. With the rest of them, we'll say let completed orders to be an initial value of zero. Then go back down to our complete order function where we can increment this by the value of one, so completed orders, plus, plus. Now, we have this order completed, we can also reset this variable called pizzas completed for order. We can reset this to be the value of zero, so we're ready for the next order. Let's finally save this and go over to our game, and we can try this out. Click on "Start". What we're looking for is to create the correct amount of pizzas to complete this order. First, the ham and pineapple will complete this, so we have one, and we also have two pepperonis to create on this. We'll try one more. We should now have three in the oven and three which also associated with this order. Click on "Complete", and this now removes our order from the working on area. 48. Removing Orders: When testing out this game, so far you may have noticed an issue, when we click on the "Start" button, we get the orders coming in, and then when we click on one of the orders to move it into the working on section, when the orders are regenerated, the same order is still placed in the list. We want to remove order 1 since we're working on this. This happens for each one which we click on. To fix this, we could remove this order from the orders array. To help identify which order we've clicked on, we can add an order number attribute to each one. In a similar way, where we go into the createSingleOrder function, remember early we added this custom attribute called data total pizzas. This helped us identify how many total pizzas were on the order, so we could compare this to the amount which we created. In a similar way to this, we're going to also add a new custom attributes with the order number, so we can identify which one we've clicked on. If we take a look above, we already have access to this order ID. It's going to be pretty straight forward to do this. What we're going to do is to duplicate this line to create a new attribute. Copy and paste this one in. We'll create a new attribute. Again, with the custom data prefix, this one is data order number. Passing this order ID. Then before we go any further let's save this and try this in the browser, by opening up the Developer Tools. That's our game. Now if we select one of our orders, this is your orderWrapper. We have the data orderNumber of one, we have the orderNumber of 2, 3, 4, 5, and so on. With this now in place, we can move over to our code and remove this order from the orders array. A good place to do this will be in our function called selectCurrentOrder. Take a look for this. This is a function which is run when we click on each order. Using this constant of orderWrapper, we already have access to the click on order. Inside of the if statement below, we can retrieve the order number attribute from the orderWrapper, and then get to work with removing this. Down at the bottom, we'll start by retrieving this order number, install this inside of a constant called orderNumber. Set this equal to our orderWrapper. Dot getAttribute. [inaudible] customer data orderNumber. Now we can access our orders array. We can use the JavaScript array method called Filter, which can take in a function, and to keep this short, I'm just going to place in an arrow function. In each order, in the order variable. Then we want to check if the particular order ID is not equal to our orderNumber above. This is going to filter out all of our orders and only let through the orders which have not been clicked on. This will give us a new array with all of the values except this one. What we can then do, is set our orders to be equal to this, which will override the original array. Let's go back over to the browser and try this out. Start the game. Select our first order. Now let us regenerate. Now when our orders are now regenerated, we no longer see order 1 in this sidebar. 49. Updating The UI & Stats: During creating this game we've kept track of some numbers, such as the completed pizzas, the wasted pizzas, and also the completed orders too. These are now going to be used to create a stat section at the end of game. This area will appear in place of the method section. So we'll hide this section and replace it when it's no longer needed at the end of the game. The stat section is actually already inside of our index page. If we go into here right at the very top inside of the main section, we have this area where we're going to update all of these three areas with our variables. This will also reflect our start and end game functions and move over all of the areas which are showing and hiding elements into some custom functions. Currently, our stats area is not being displayed because if we go into our style sheet, we set this to be the display type of none. Let's jump into our index page and if we take a look, it'll start off game function just here. This area is responsible for showing and hiding our start and end buttons once the game has started or ended and also if we scroll down, it also adds this message on the start of the game, which is then removed after three seconds. Also the end of game function will then reinstate the Start button and then hide the End button. To re-factor these two functions, just below startup game, we'll move these into a new function called Startup game UI. Then scroll up. We'll cut out our two areas which are showing and hiding the buttons into our UI. Then also our message area with the set timeout for this out. When this is in and then we can call a startup game UI function just above in place of the code, which will cut out. In a similar way just below the end of game, create a new function. This one is end of game UI. Now what we need to do for this one is to copy a cutout both of these lines at the bottom, and these into the new function and then call this in place. Let's try this out, over to the browser and click on the "Startup game". This is now removed and we see the end game. Now if we click on "End", the start button is now displayed. Nothing different, just a re-factor to keep our code a little bit more organized. Now we can also use these two new functions to show and hide the stats area. We'll begin with the startup game UI at the bottom document.querySelector. Grab the original method section which we can hide by accessing the style.display and set this equal to the string of block, duplicate this, and then we can do the opposite with our stats. We want the stats area to be hidden, will change this to be the value of none. We do this because we only want these stats area to appear at the end of the game but we'll do this now by reversing both of these values, instead of the end of game UI, the method area is going to be hidden so we can reveal the stats area by setting this to be the value of block, save this and try this out. Go to the game, we see the method area so we can see exactly what we're doing with each pizza and the game and we now see our stats. As we've seen before, this stats area is just the HTML, so we need to take care of adding our variable values to each one of these spans. Jump into our index.js inside of the end of game UI document.querySelector. The first one of our spans at the idea of completed orders, where we can set the inner text content to be equal to our variable with the same name. Copy and paste this two more times. The middle section was completed pizzas. Again with the matching variable name. The third one was wasted pizzas and wasted pizzas variable. These free variable values also needs to be reset at the start of each game. The start of game UI it's resets all of these values. The first one was the completed orders zero, the completed pizzas zero, and also wasted pizzas 2. Let's try this. We'll need to create some new orders start up the game. Ham and pineapple in the oven, and pepperoni. Also waste some of these pizzas so we have some stats, end the game. Don't see any updates in the stats let's go over to our code and check this out. Where do we update this? We update this in the end of game UI. These three lines. We can see here that the text editor has highlighted an issue with the three dots. We've got complete orders which should be completed, check the variable. Complete all this. This looks like the right one, the result. Order number 1, which is ham and pineapple, add this to oven and then two pepperonis , complete the order. Next one we'll try to waste an order, we'll add some pepperoni and ham, add this to oven, this is being wasted. Now, click on the "End", see one completed order, which is correct. In terms of completed pizzas remember that this variable is only updated when the actual oven has finished cooking. Once the timer, which is set to be 20 seconds, only after this cooking time has finished will this be added as a completed pizza. We wasted one pizza too, so this is good. Almost now done with this video, we do have a couple of things to also fix. If we click on the "Start" button, we'll see exactly what this is. We take a look at in the kitchen area, we've got 11 at different ingredients and also the timer is on 271 seconds but if we click on "Start", the time we will continue from there rather than restarting and the ingredients are also doubled up. Let's fix these two issues over in our start of game UI. First, we'll reset our ingredients by selecting the HTML area with query selector. Select the ingredients and reset this by setting the innerHTML to be equal to an empty string. Also will take care of the countdown timer by setting count down time variable to be equal to the game length. Try this out. It's also the game, ham and pineapple, add this to the oven. Now if we end, we start the timer that has been reset. We only see the single set of ingredients. Finally, just to finish off the stats area, I've added in a fade animation to our CSS. If we go into our style sheet, let's take a look for fading. Creating a simple animation to fade in the start area at the end of the game. All we need to do is to add this as a class name to our element. To look the end of game UI, duplicate any of these, grab all starts. This time we'll set the class name to be equal to fading. Good, let's give us one final test inside the browser. Start the game, select an order, complete the first one, pepperoni. Complete a couple of these pizzas to finally onto our stats , end the game. Good. With that in place, I'm now going to call this project done. But it's probably a few things which can be improved and a few little issues which may also need to be solved. But this project is about learning JavaScript. I think it's given us a lot to practice with and a good chance to show how all of these little things which you've been learning during this class, all work together to create something much bigger. 50. Introduction To Scope: An important but often confusing part of JavaScript is scope. Scope at most basic is a way to place variables into groups. Each group allows a certain amount of access. This means we can keep some control over what has access to our variables. This makes sense because variables hold all of our pieces of important data. Why would we want them to be changed to accessed when they don't need to be. Here we see a simple example. We declare a variable called score. We then have a function to update the score, log it to the console. All is completely fine here. But what about this though, we decide to add a bonus of 10 points to the score. This variable is created inside of the function and then log to the console. Again, no problems here. The console will show a value of 11. The problems begin when we try to access this bonus variable outside of the function. This would cause an error with a message along the lines of bonus is not defined. We know it is defined because we see it's not accessible because of scope. This goes back to these groups variables are placed into. Since the bonus variable is created inside of the function unlike the score. Accessing this is restricted to all function. But as we know with JavaScript, that's never just it. There are also a few other things we need to understand. For the first time in a long time, we can jump into a new section, and this is number 9 and then jump into the first lesson, which is introduction to scope, which has an index.html. To control the level of access to a variable it depends on a couple of factors. As we've just seen, the location in our program where we declare the variable and also the type of variable which we create too. We can create variables with var, let, and const and these also have an effect on scope too. This is the same example which we just looked at, where we declare a score using the var keyword outside of the function. Then inside of the function we update this variable. We add a bonus and then log this to the console. Let's jump into the console. We can confirm what we've just seen. Open us up and we expect the value of 11. This works because the score variable is declared at the top level of our program and this doesn't mean it needs to be physically placed at the top, just like it is here. It just means it's not nested or declared inside of something else, such as a function. This means it's in the global scope and it's globally accessible. If we try to access the bonus variable outside of the function of where it was declared. We haven't declared inside of here. Let's see what happens down at the bottom. Placement console log, a variable of bonus, which then returns back an error of bonus is not defined. This bonus variable is restricted to only being accessed inside of this function. Because this function also has its own scope. This can be useful for variables when no, we don't need to use elsewhere. It gives us the safety of knowing other sections of our code cannot modify these values. This function scope also means we could create multiple variables with the same names, but inside of different function and if we need it to do this, they would be completely independent. We can also see this access level inside of the browser's console too. If we first remove this console log refresh to clear this browser. Then if we type the word score inside of here and enter, this returns back the value of one. This is correct because we have the initial value of one and then our function runs and increases this to be the value of one. This all works because this variable is global. But what we try to access our bonus which is scoped to this function. Let's try this out. Enter and we see the same error message which we had from the console log. Along with these functions, these global variables are also available in other blocks statements too, such as for loops and if statements. Let's try an if statement just below our function call. If score, place in a console log with the value of score and this should work as expected. This also applies to other block statements too. Block statements are basically sections wrapped in curly braces so we have the function which we have here. I have the if statements, which also has these curly braces, but also things like for loops and while loops too. Recap. JavaScript has the concept of scope to allow us to set how much access we have to a variable like this example, score is declared in the outermost section of our code, meaning it's in the global scope. Global variables like this can be accessed anywhere, including inside of the code blocks wrapped in curly braces i.e functions and if statements. The opposite is true though when we declare a variable inside of a function, this has function scope, and will not be available outside of this block. Therefore, protecting the variable from being updated or removed from elsewhere. 51. Nesting Scope: So far we see that scope only appears to work one way, from outside to inside. Variables declared at the top, such as this global level variable, are available inside of other functions or blocks such as this function here. We can carry on by nesting other statements inside of others, and the scope continues in the same way. Access is passed from the top and down to each level, yet new variables declared inside of new blocks are still restricted. You're effectively not passed back up to any higher levels. When we seeing this in the previous video where we try to access this bonus variable outside of this function and in the global scope. Scope nesting is referred to as lexical scope in JavaScript and many other languages. Let's take a look at what this looks like in action. To begin, we have the same setup as previously. First, let's change this console log, include the text of inside function. We do this so it's a little bit more clear because we now going to be extending this code, then it's still inside of this function we can nest an additional block, such as an if statement. An if statement, where we can check if bonus is true, and if it is, based on a new console log with the text of inside if statements. Then we can append onto the end the variable of bonus. Now we are inside a nested block statement. We try to access our bonus variable from the level above, so what do you think will happen? Well, let's try this out. Make sure you were inside of the nesting scope section and this is open in the browser. Refresh. We can see as expected, the inside function code will run because there's nothing to stop this. Then one level down inside of the if statement, not only does the console log run, but we also have access to this bonus variable. This means that nested statement blocks can access variables from an outer or a higher level of scope. But what about the other way around? But we can try this out by adding a new variable inside of our most deeply nested statements, so var bonus2, any number is fine for this test and we can access this in the higher level, which is this inside function, write add the value of bonus2, save and refresh, and now we can see we get the value of undefined. Meaning we can clearly see this doesn't work the other way around. We get undefined so JavaScript is aware that this variable exists, but it's assigned an undefined value. As a quick side note, if bonus2 was declared with let or the const keywords, it would throw an error rather than having an undefined value. But more on this one soon. The nesting can also continue as deep as you want to go. Let's try adding a new block statement, such as a while loop. This again, also has its own curly braces to enclose the code and create a new inner scope. First, let's remove the bonus2 which you no longer need. We can remove this from the log, and then inside of our most deeply nested section, we can go one further. Creates a new variable called numbers which you're going to loop over and set this to be an array of any values inside of here. While loop we also need an initial value which we can store in i. Set this to zero. We can keep running this while loop, while i is less than the length of our array, which we can access with numbers, the land inside of our code block or our scope section. Placing a new console log with numbers i, which will print out each one of these numbers individually, so don't get stuck in an infinite loop. We can increment the value of i each time. Let's test this out. Refresh. As it will fall console logs from just here. Again, from this most deeply nested section, we still accessing our variable from a higher level, and we can go up even further and test our bonus variable and try this out inside of our deeply nested section. Paste this in, and there's our value of 10. Also going off the earlier example, you can probably tell what's going to happen if we tried to do things the other way round. If you create a new variable inside of this while loop, so jump inside of here. But the log with the new variable of bonus3, which is equal to any value, and then we can try to access this at the top level of our function, so add this inside of our console log bonus3, refresh. There we see the value of undefined. This is how we can use scope in nested block sections. We've also seen some examples about how scope is only accessible from one way. Nested sections, such as our while loop, in access any variable from a high scope, but it doesn't work the other way around. 52. Block & Function Scope: Jump into the next file which is the block and function scope. We don't get too confused about what we're now going to look at. I've kept the same function example as previously. With this example here, we have multiple nested variables inside of this function at different levels. Functions behave differently to other statement blocks. Going forward each time I mention blocks, I'm referring to the code surrounded in curly braces, such as these if statements and also our loops. With a function like this, we cannot access the variables nested inside from outside. If we try to place a console log just after our function call access our bonus3. You see bonus3 is not defined and also the same for things at other levels such as the regular bonus. We also have the same issue but it doesn't matter if the variables at the top level of a function are nested inside of other blocks. Even if we declare these variables using let or const it will also be the same. [inaudible] var from let the same results and also the same for const. Changes back to var. This is how a function behaves. It has its own scope and we know exactly where we're at with the variables declared inside. But it's not straightforward with other blocks. If we change this from a function to any of the block, such as an if statement, let's see what happens. Move the function keyword and we can say if the score is equal to 0, remember score is declared in the global scope. We still have the console.log for the bonus at the bottom. Now if we try to refresh, we also need to remove our function call. This bonus variable is now available. But what about a deeply nested variable such as bonus3? Let's try this. Refresh and this one also works too. We can see here the blocks behave differently to functions regarding scope. This happens because block statements don't have their own scope. Well, that's not strictly true because it's true for this example which we see here. But as a JavaScript developer, we have multiple choices depending on how we declare our variables. Variables declared with the var keyword, which we've deliberately used so far, will always behave like this. But using const or let inside of these blocks will remove access from the outside and sculpt these to their current block. If we wanted to make sure this bonus variable was only available inside of this block and not from outside which we have here, we need to make sure we declare this variable using the const or the let keyword. Now let's try the bonus. We no longer have access and also, the same for const. Just as a recap when we declared variables inside of functions, we didn't have this choice of whether we wanted to restrict the access to inside of the function block or make sure it's accessible from outside. But when we use other blocks, such as an if statement or a loop, these blocks give us the choice of whether we want to use scope in or not. 53. Hoisting: Earlier in the course, I briefly mentioned a term called hoisting, and promised to come back to it. This is what we're going to cover now. We've already seen some examples of hosting already. Let's take a few examples first to see what is happening. Title files in this hoisting section contains some examples and the first one maybe familiar. This was an example we used earlier in the function section, and up at the top, we have two arrays. We have the bread and also the brownies. Then we have a function setup in two different styles. We have the function declaration and also the function expression. Both of these do the same thing that you're checking if an ingredient is present in the selected array. Why am I showing you this same example over again? Well, notice here how we're calling the function in the console log up at the top before the function has been created. We call it check. Since our code is read from top to bottom, we get into the checkAllergies function call before it's even been created, whether that's in the declaration or the expression version. Let's go over to the browser and see what happens with this console log. Let's see if we get back a returned value from this. This works with the function declaration, but what about the other way round? We comment out declaration and reinstate the expression, refresh and this returns back an error saying we cannot access our function before initialization. Below this, we have Example 2, which is a really simplified version of the issue. We're creating a console log and login the value of the variable before it's been created. We've seen inside the console before that this works. We just remove this with the error refresh. We can see this is working perfectly fine. This works even though we access our name variable before it's been declared and it gets even more weird if we try to reassign a name value before it's declared. Over the top, just above our console log. What we're going to do is to reassign or update this variable with a new value before it's even being created. This also works. We'll see the new updated value in the console. Although these examples are varied, they are all showing a fundamental thing. We can often access variables before they're even declared. This leads us to a term called hoisting. Just quickly before we jump into this, I want to show you something else, which is a variance of the last example. What about at the very bottom if you had a console log passing in the value of role? We then declare this variable without initializing it with a value and then we'll give this a value at the very end. Let's test this out. Save and refresh. You can see this slightly modified version will return back the value of undefined. Looking at these two examples, it may seem pretty strange because we're looking at how we can access variables before they are declared and also since both examples are pretty similar. Hoisting is often described as the process of JavaScript, taking our variables and function declarations and moving them to the top of the program or to the top of their scope, meaning they are declared and ready to access at anytime during our code. This would explain a lot of what we've just seen. None of the code physically gets moved around or moved to the top of our program. It's the process of our variables and function declarations being placed in memory at compile time. The human readable code which you write, such as JavaScript, can be read by a computer. It first needs to be converted or compiled behind the scenes into a set of instructions which computers can understand. It's during this compile phase, our code is first read or passed. Our variables and function declarations are then stored in memory. Just to clarify, during this compile phase when this program is first passed, variables like this one are first stored into memory, which is why we can access them before we appear to have even created them. There's no hidden magic behind the scenes, no moving around our code to the top of the program. It just simply our code being read and a reference to all variables and functions stored in memory. This explains a few things from our examples. First, if we take a look at this function example at the top. The first example, the function declaration. Function declarations are hoisted. This is why we can call this function before it's even declared, which we're seeing with our console log. However, function expressions are not hoisted, and this is why we've seen an error in the console. For Example 2, the very first one. Since this variable name of Chris is hoisted, this is why we can access it before it appears to have even been created, although this was different for the second version, which returns back undefined. Why do you think there's a difference between these two variables? Well, an important part to understand is what exactly is stored. To better understand this, let's take a quick step back to variable basics. Earlier, we looked at some of these variable related keywords and a declaration is when we declare a variable, which you want to use and then give it a name. Once we then pass it an actual value, this is referred to as initialization. You have declaration and initialization. Back to this example for our role variable. Here we've declared an empty variable and then after this, we have initialized it with the value of dev. At the early compile phase, only the empty variable declaration is hoisted and stored into memory. However, though the following line where we initialize it, this value of dev ignored at this stage. At this stage, it's assigned the value of undefined. This is why we see undefined in the console. However, with the previous examples since we do initialize this with a value of Chris, at the compile phase, the variable will be assigned this value rather than undefined. Also to make things even more confusing, we need to remember here that we're using the var keyword for both of these examples. It's behavior is also different with the let or const keyword. If we change our role down to the bottom to be let, let's see what happens inside of here. We login the value of role, refresh and now rather than the value of undefined being assigned to this variable, we'll now get an error inside the console. This error says we cannot access our role before initialization. This is because when we're using the const or let keyword, it first needs to be declared with a value before we can access it. If we don't first assign it a value, it still will be given a value of undefined behind the scenes, but we still must declare it before we try to access it in our code. This can be a tricky subject to understand especially in the beginning, because hoisting applies to all three of these keywords, it applies to let, var and const. However, var does things a little bit differently like we've just seen. But even if you don't fully understand what was going on at this stage, having a basic understanding that variables are hoisted can save you a lot of trouble in the future if you run into a similar error. 54. Temporal Dead Zone: The temporal dead zone is something which sounds more difficult than it actually is. Most of the concepts surrounding it has been covered in previous videos. Looking at the code in the script section down at the bottom, we have a console log and a variable. We know that a variable created like this with the var keyword will find access before it's been declared. This is because the variable is hoisted to the top of its scope. We can see this by accessing this first and I'll put this inside the console so everything works completely fine. But as we also discovered, if we use the newer let or const keywords, the behavior is different. Another way to look at this would be maybe to initialize a variable before we use it. If we remove the value and then initialize this about the top, name equals Chris. Let's see what happens inside of here. We still have an error since we are trying to access our name too early before it's even been initialized. But what about if we switched around lines one and three? Well, if we place one at the very bottom and then move the let keyword to the very top, this instead returns back the value of undefined. This is also touched upon in the previous video. If we don't assign a value to a variable using the let keyword before we use it, instead, it will be initialized with the value of undefined. Const, let, and var all get a value of undefined if we don't set the initial value before we try to access the variable. The difference is var can be accessed before it's even been declared, just like we've seen in the previous video. How does this all relate to the temporal dead zone? Well, it's simply name given to something we've already seen when using the const and let keywords. It's the name for a period of time from when we enter any given scope, right up to when a variable is initialized or accessible. A variable may exist, but it's not yet initialized. If this happens, it's said to be in the temporal dead zone and we cannot access it or use it how we want to. If this all sounds a little bit confusing, let's simplify an example to try and give you a better understanding. What we're going to do is we'll remove our top line given the console log and we'll say let name equal to be a value. If we try this out, we know this won't work as we've seen in previous examples. This is because from the beginning of the current scope, we`re entering the temporal dead zone. Let's add a comment, temporal dead zone begins. This is all at the top level of our script, so it's in the same scope. It's not nested in an inner scope such as a function or an if statement. Then when our variable is initialized on line 14, the current temporal dead zone ends and the variable is now accessible. Its beginning and ending zone also happens to any other scope too. For example, if this was in a certain block, such as a function or an if statement surrounded in the curly braces, the same would also apply. Looking at this example, it may appear that the code order is the determining factor, since the variable declaration happens after we try to access it in the console log. However though, this is not the case. As mentioned earlier, the temporal dead zone is a period of time from when we enter any given scope, right up to when a variable is initialized. It's the time which is important and not the order of the code since the word temporal actually relates to time. We can see this if we wrap this log into a function. Create a function about the top. Let's say get name. With this console log up inside a function and then call our function. However though, we may expect this to cause an error, just like we've seen previously. Looking at the code order, the console log still happens before we declare our variable. It's understandable that you may be expecting an error. However though, this is not the case because the function is actually called outside of the temporal dead zone. The temporal dead zone is not the code order, it's the time it takes to actually make this variable accessible. There are some complicated things to grasp here and also in the past few videos. I don't expect you to fully get everything on the first try, but I do think it's important to know that these things exist because one day you may run into an issue because of them and it may just trigger you to think about these concepts and how they could be affecting your code. How do we make our lives easier and minimize errors? Well, a simple way could be to put const and let variables at the beginning of their required scope, whether that's at the top of an if statement, the top of a function, or even at the top of our scripts. That way, they will always be ready to use when needed. 55. Closures: When we create functions, they don't always need to be stand-alone functions. They can instead be nested to in the starter project. In this closure section, you can see inside of here we have an empty script area. Now we're going to create a simple function to demonstrate the effect of closures. Jump into the script section and create a regular function inside here. I will name this one the outer inside with a variable. We'll say outer value. I set this to a string of outer. Now we can nest an additional function inside of here. I'll just blow our variable creates a new function. This time with the name of inner. We'll do what we did just above we'll create a new variable. This one can be in a value equal to the string of inner. Then inside of this inner function we'll create two console logs. The first one is going to be for the value of inner value, which is contained inside of this same function. We'll duplicate this and placing our outer value. We know from earlier videos that when working with scope and when we nest scope inside of functions or brackets like this, we can still access variables created in outer levels, such as this one here. Basically, an inner scope can access variables from an outer scope. For this inner function to actually run and place our console logs inside the browser. We need to call this inside of here, so called our inner function makes you this is nested inside of the outer function. Then finally we'll call our main outer function, we'll also do this inside of a console log. Make sure you're placing the brackets. Then test this out by jumping into it the console. We see inner, we see outer, which is our two console logs. Then the third one down at the bottom is the value of our function which is undefined. We can ignore this undefined value at the moment because we have not returned anything back from this function. But we now know this is working since we have our two console logs meanwhile we can access both variables from inside of this inner function. We can first access the inner value because it's local to this function. We can also access the outer value because of the scope chain. Scope or lexical scope, which you mentioned, allows this inner function to access our two variables. What about this inner function was pulled out of this current setting. I'm not talking about physically moving the inner function elsewhere. But instead, what about if we stored it into a variable and made use of it elsewhere? Well, to be able to do this, instead of calling the inner function at the very bottom, we instead return it, so we'll remove this, return the value of inner. The important part to understand here is we're returning the actual inner function. When we call this outer function. We can see this inside the console. We still log in this and also running this. If we refresh this, we'll now see this inner function inside the console. Bear with me here on this one. What we're doing here at this stage is we call it an outer, which returns the inner function. This inner function is effectively a stand-alone piece of information. It has no reference to this outer function or any content inside. Let's grab this inner value, which we can see inside the console log. Install this inside of a constant called interact. Now instead of directly, I'll put in the outer function. We can place in our constant refresh and we can still see we have access to this inner function. All we're doing here is creating a variable which stores a reference to this returned function. This variable can now be used elsewhere. Now what we have is a function reference independence of the original outer function. This now leaves us with a key question. This inner function which we have stored in a constant, access this variable from outside. Well, we can find out by actually running this function by placing the brackets just after this constant. Say this, remember we're still trying to access its outer value. Refresh, and we still see our two console logs. Meaning yes, we can still access these outer variables. This may seem pretty strange. We are accessing variables which seem to make no sense with what we've already learned about scope. This all relates to something called closures. A function, just like our inner function here, we'll also remember what variables it has access to. In our case, it's this outer value. This is what's called a closure. Closure is putting a fence around everything we have access to. Remember all of these variables wherever this function may be called in the future. This can be useful now because instead of needing to create an outer value as a global variable, we can instead restrict this access to inside this function and still allow any nested inner functions to use it. Also, note that this term of closures can only happen inside of functions. This is still not clear. Let's take a look at another example using the player score, which needs to be updated. We'll just comment out all of this and at the bottom. Create a new variable. Let's scroll to be equal to 0. Then create a new function called update score. Then inside here, what we'll do is re-assign our score with the value of the current score plus 10. Log this to the console. At the bottom call our function. Let's test this out. This should be a value of 10 since we have our original score of 0. We then call our function which adds 10 to the original score and then prints out the new value. Also, if we update this multiple times by calling our function more than once, they should also work too. This is all fine, it works as we wanted to, but score which we have outside of a function is classed as a global variable. It can also be updated from other areas too. Instead, it will be better to have more control over this variable and only update it inside the functions created for this purpose. You may think, let's move this variable into the function. We can drag this down. This technique creates a function scope and his variable cannot be accessed from outside. This solves one of our problems, but it also creates another. Let's see this inside the browser, refresh. We get back the value of 10 free times because the variable resets back to zero at the beginning of each function call. Also if this was a real game, we may also want access to the score variable outside of this function. Maybe do something like display on the screen to the user. To help with this, we can make use of a closure to nest inside a function to update the score variable. We have the update score outer wrapper. Then we can create a new nested in a function called increase with our score variable inside and also the console log which are the inner function, just as before. Also, store this function into a new variable. The first one, we'll say const, new score is equal to this returned value. We could still call this function multiple times if you wanted to. But this time we need to reference this new score, so it changes. Also leaving in the brackets just afterwards so we actually run this function. Then try this by refreshing. Now, this has increased by the value of 10 each time we call our function. This now solves the problems which we had before with the original update score function. Before we made these changes, we reset the score variable back to zero. This meant that as we've seen before, each time we call this function, the result was always the value of 10 and it wasn't adding this to each one of the calls. Closures will solve this by remembering the score variable in memory each time it's called. A score variable also now has narrower scope so we cannot be updated accidentally elsewhere like we could if it was a global variable. Yet if we still didn't need to access this score variable from outside of this function. We can return back a value and store this inside of a new variable. Meaning we could still access this score from inside of the closure and display it to the end-user. 56. A Little Bit Of Background: This new section comes with quite a few buzzwords such as: callbacks, asynchronous, synchronous, and also some concepts which may be difficult to understand without knowing a little bit of background as to why we use them. This video is going to try to explain these in simple terms and what exactly each one does. Starting with synchronous code. Each line of code is a bit like a task, and each one is completed in order. Line 1 will be read, wait for this to be processed, and then move on to line 2. We'll also wait for this to finish before then moving on to the third line. On a tiny program like this it doesn't really matter because operations are quick and easy to process, and you wouldn't notice any waiting time between each one. But in extreme cases if one line never finished processing or took a long time, then we will be stuck. On the browser we can see some simple examples of this, so jump into this new section which is number 10, Asynch-JavaScript. In a little bit of background section we have two examples, but now we'll focus on example 1 which is uncommented out and also the HTML up at the top. We have the button and the level 3 heading. Ignore the image for now, this is related to the second example. All we do here is grab both of these first two elements. We query selector, we select our button. Add an EventListener which will listen out for the click and this function will trigger an alert, and then just afterwards we'll grab our heading and set the innerText content effectively given us two stages to this function. Alerts can be good for example like this because they block the execution of the code until we close it down. Now if we open this up inside the browser; copy the path to this, paste this in, and refresh, we see our button which will now listen out for the click. I'll click on this, we'll then see the pop-up which is the very first line of our function, and then if we click on this button it closes down. The next line of the function is then called which will set the innerText of the heading, so we have a clear order of things running. We have the alert, and then once this finishes it moves down to setting the text. With this example, each line will not run into the previous one as completed. This is how synchronous code works. One of the issues here with synchronous code is that a single line of code can block the rest of the program from running, and this can be avoided by using asynchronous code. The code is still read in order line by line, however an operation doesn't have to complete before moving on to the next line. Effectively, all of the code is run and then set off one by one. We need to handle what to do when each task is completed and this is the key part here, and then in what to do if the code comes back a success or if there's an error. Looking at our second example, let's just uncomment out this section. Here we have something called fetch. This is the Fetch API, and remember from earlier we have certain web APIs such as Canvas. This Fetch API allows us to fetch things across a network which could be another website, a database, a server, or an external API which someone else has created and the important thing here is the fetch call is asynchronous. It will run and then allow the rest of the code below to run too before it completes or it gets any data back. The main idea here is we get data from somewhere else over than inside of our own application. This example selects an image from Wikipedia and then stores the return value into a variable. Let's begin by logging the return value of this variable to the console. Just uncomment out this first example, and then place in a console log with the value of the variable which is imageSource of the browser. Jump into the console and we'll see something called a Promise. We get back a Promise and it's got the result in brackets of pending, so what do you think this could be all about? Well, we will look up Promises in more detail soon, but it goes back to the important point which I mentioned before. When using asynchronous code or async for short, we need to handle what happens if the code comes back a success or if there was an error, and a Promise can handle this for us. When we first asked for this image from Wikimedia, we don't know at this time if the Wikimedia site is down, running slow, or if there is a connection problem between us and their server. This console log below was immediately called after our fetch, so it was run before the image even came back. This is why we get the result of pending because we never had an image to actually log to the console. As another example if this is pending and we don't have an image, what about if we try to maybe delay the console log by three seconds? Well, let's cut this out. We can place in a timeout which will trigger a function, and let's say three seconds. Inside the function place another console log from before, refresh, and you can see after three seconds, our promise is now fulfilled. We have a response, so waiting three seconds this gives us the time to get back the information or the image which we need. Instead, if this was synchronous code, the rest of the code would need to wait on this image to come back for three seconds even if we didn't need to use it. Or alternatively, if we never handled it like this, the line which immediately follows our fetch call may try to access our image which you don't have back, and therefore causing an error. With this in mind, we'll look at promises and other ways to handle a response in the upcoming videos. 57. Callback Functions: This video is going to introduce you to something called a callback function. A callback is just the name given to a function which is called after something has happened. The anomaly used as a next step to take once something has completed. From what we've previously covered, we know that async code can take some time to complete. This could be getting data from a database, or even saving to a database as an example. Let's see how this can affect our code. The code in this example begins with an empty, unordered list. Now, our script has an empty users array. A typical app which has users would probably have a function to make a call to our database and update this user's array with the result. We have a function to simulate this and add two new users. All we're doing inside of this function is to access our users array and placing it to user objects. Then once we have our users back from our database, which we assimilate in here, what we'll probably want to do next is to create a new function which grabs all of our users loops over each one and then it displays them in the browser. Let's take a look at how to do this. We will create a function, let's say listUsers. Under listUsers is first going to access a users array, we'll loop through with forEach, which will run a function for each one of our array values or passing the variable name of user. Then run that before we have this empty unordered list, we can create a new list item for each one of our users. Const elements is equal to document.createElement, create a new list item, and then add the text content inside, which is the username. Documents.createTextNode where we can make use of our user variable and access the name property. As ever, we need to create our three-part process, which is to create the elements, to create the contents, and then at the third part is to merge these together. To grab the parent elements, we call appendChild, add in the name, and then finally, add this element to our unordered list. First grab our unordered list with document.querySelector, add it in our unordered list and then appendChild, which is our elements. This is it for our list user function. We can call this below and check this all works in the browser even the names of our two array values. This works completely fine. We don't have any issues with functional data because we know it's in this same file. But realistically, what we'll probably do is to get our users back from a database, and this database call would be asynchronous and may take some time. If all this went well, the time delay will be small, but still a delay nevertheless. To simulate this delay, we could also add a setTimeout to our both function. I'll grab our users, let's cut this out, place in a setTimeout call, and then a function. I would just add one second delay to this. Open up the function body and paste in our user array, and now let's see what happens inside the browser. Refresh, and even after one second, we don't see our users inside the browser. Now, user have been listed since we are immediately Lupin of the users down at the bottom because our function is being called immediately. This is effectively happening before the one second delay from our timeout, meaning that when we try to access our users, it doesn't have any values. This is a common thing to have to deal with, when working with data stored externally, we basically ask for the data which we need, but we need to also make sure the data is returned and available before we can safely access it. It needs to be in order so things don't break. Even though we're calling the functions in the correct order, so we're created our users and then we're listing our users, the time delay is causing the issue. We can also confirm this with some console logs. First of all, if we place in one just after where we create our users, place in the first one and we'll say this is the getusersFromDatabase function, and then also placed one it inside of our list user function with the text of list users. If we didn't have this time delay running from the top to the bottom, you would expect to see the first console log, followed by this one just here. But if we save and refresh, the opposite happens, we see the list of users cold before getusersFromDatabase, and we know this is the wrong way round for what we need to do. It would be nice if this list user function was only called once the code in a timeout was deemed to be a success, and we can do this by introducing a callback function. To do this we'd move the list uses function call, pull this out, and then passing in the callback function into getusersFromDatabase. This callback function will be then taken in as a parameter from create our function. Like any other parameter, this name is up towards. It doesn't have to be callback, we'll place this in it just so it's clear what we're doing. Now, we can call this callback function at the end of setTimeout. Just after our console log we'll call this as a function and then we can go back to the console and see which order these appear. Refresh, and we get an error inside of here. We say callback is not a function. Callback. This just needs to not have the function calls since we're just passing a reference to this function. Now, refresh. Things appear to be running in the correct order. We get back our users from the database, we then list now users can also see these reinstated back in the browser. This solution is asynchronous callback. Remember, from the last video that synchronous refers to the code which runs in order and one operation needs to finish before moving onto the next. Using this example that we've just done, once the users have successfully came back from the database, which we simulate with our setTimeout, we can then use our coal back the list users function, and this way if things are kept in the correct order. We can also pass in additional arguments to this function too. Let's say we wanted to only get the users which had the role of admin, we can pass this in except the parameter. Now, when we call our function as passing the role of admin, so this is completely fine. We can pass in as many arguments as one, two to the function. We must ensure that the callback is always last. This method of passing in functions as function parameters is nothing new. We can see this if we go back to a previous file. Let's open up the sidebar, jump into the previous one, and inside the first example where we added an event listener. We first listen of to click, then as the last parameter which triggered a function. Here we pass it in a callback function which we want to run once something has been clicked on, and also consider a array methods too which we've looked at something like for each, which we have in this current example. Each element inside of our array, we then run a function inside which is also a callback, meaning this technique is nothing new. When we talk about callbacks, these are generally a more older traditional way of doing things. We'll look at more modern ways next. But callbacks are really important to be aware of, since there's still plenty of them around and still in use today. Callbacks too get a bit hate in the JavaScript world and not because they don't work. It's more because how things can easily get messy. This example that we just use is not too bad. Because all we have is a single function, which then calls back a second function. But the problem lies when we have a callback, which calls another callback function, which calls another callback function, and so on. Even looking at this example, the list of users function may also need its own callback too. Then that callback may also need its own callback and then we're stuck in a long chain. We can compare this thing to our own lives too. We have an order of tasks which you want to complete in a certain order. Say we want to drive the car. But before we can actually drive the car, we need to walk to the car, before we walk to the car, we have to find the keys, before that, we have to get dressed and so on. This is a series of tasks which rely on the previous one to be first completed. This is comparable to the callback functions being called once the previous code is successful. It's this multiple callbacks which can result in one big mess. To see an example of this, we've create some small demonstration functions. Let's comment out everything from above. Now, create some new functions. The first one is getOutOfBed, placed in the console.log, says out of bed, and then duplicate this three more times, giving us four functions. The second one is to find our keys and just console.log. The next one is walk to car, and the last one is to drive the car. Will say yey, since our task is complete. Using what we know from our previous callback demonstration, each one of these functions needs to be passed to the next function as a callback. Then call this inside of each function. The first one getOutOfBed. This is going to take in a callback, which will run at the very bottom, passes into the second one too, call our function. We don't need to add this to our last function since it's not going to be calling any further functions, since this is our end result. It's actually triggered this chain of calling all of these functions, we're going to create one more function to call all of these. Create a new function called completeTasks. We can call this function, which is completeTask passing in the first function which you want to call back. Our first one in our order is getOutOfBed. What we're going to do now may look pretty complex, but it's basically the same setup as before. We'd get users from database. Only this time there is more than one function in the chain, which we'll callback, and then inside of the completeTask function, we can then nest each one of our functions to call inside. The first one is get out of bed. Pass in a function. Let's go over to the console and see what happens. If we refresh, we see the text of out of bed inside the console and if we take a look up, this is the console log at the very top. The next party is going to be key to understanding all of this. What we'll be doing here is we're creating our first function called completeTask. This is then called on our first step, which is get out of bed, then we pass a function inside. This function is accepted as the callback, and this function is then called at the end of this function. Basically once this function has finished, it will then call our second function, which is nested inside. This next section, which we're going to call can be our next stage, which is findkeys. Let call this function, findkeys also needs to take in a callback function , so pass this in. This should now run our second console.log. Got a spelling mistake, so we'll just change this, findkeys. Now we have our second console.log, so will run in this section just here and then it's going to run this next function is next function is nested inside. Passing our next stage, which is walk to car. Walk to car also takes in a callback function. We'll save and refresh, send prints out the text of walking. It will then run our next function, which is inside. The final stage, is to drive the car. This is the very last stage, so it doesn't take in a callback function. We can simply call this as a regular function. Refresh. This code is run alongside all of our other functions. If you want to, we could also pass in additional steps or additional code into each one of these functions too. Just to clarify, all we're doing here is creating a main function which is run, and then it's function is then calling additional functions inside. Each one of these functions, we'll wait for the code to complete inside before calling back the next one. If this is starting to look a bit messy, well, it probably is, because it is a mess, and that's why some alternative ways of dealing with this are being created. But just because there's new ways, it doesn't necessarily mean this is still not relevant. Callbacks is still an important part of JavaScript, both currently and you will also see this around in legacy code too. You will probably hear this kind of thing also called Callback ****, the Pyramid of Doom, Nested callbacks. Also plenty more names too. All of these names point to the same complexity of nested callbacks just like this. In upcoming videos, you will discover some alternative ways of handling this, including using callbacks asynchronously with promises. 58. Promises: We know now that making an asynchronous request can take some time, maybe just a few milliseconds, or maybe a few seconds, minutes, or never even complete at all. Often when we're talking about this thing, it refers to fetching something from somewhere else, such as a server, some kind of datastore, an API, or an external website. A promise is great for handling this outcome. Promise is an object and this object represents the result of an async task. The result could be a failure, we may not get back from the server what we asked for, or it may take a little time. Promises hold onto this task and promise to tell you in the future when it knows the outcome. We've already seen promises and some of the outcomes already. A few videos ago, we looked at a simple example of fetching an image from Wikimedia. I'm going to use the Fetch API. Fetch is an async operation, and we're seeing a promise returned back in the console. When we tried to access the promise too early before it finished grabbing the image, the results were seen as pending. We then added a small time delay with a set timeout, which was altered in the promise being fulfilled. These are two of the three available states with promises. Pending is the initial state when we don't yet know if the task will complete or not, then fulfilled when the task was deemed a success, such as when the data has came back and it's now ready to use. We also have a state called rejected when the task has failed. We don't have the data we requested, and we need to do something about it. You may also hear the word settled with promises. Settled is when we know the fate of the task, meaning it's either fulfilled or rejected. We don't need to know anything about the pending state since we can't tell what direction it will go with the result. But we do need to handle a success or a failure. Over to the starter files, which is the promises section. Here, we have another example using this Fetch API. This is fetching data from an external API, and this is just an external URL. This URL is going to select a random dog image. We can copy this, and paste this inside the browser. We can see we have a result in a format called JSON, which stands for JavaScript Object Notation. It's a syntax for exchanging data over the web. It looks like a JavaScript object, but it's actually language independent, meaning it can be created and passed by other languages too. We can see we have a message, which contains a URL for a particular dog image, and the code of success. We can copy this image and paste this link in, which then gives us access to the particular image. I've installed the browser extension to make this look a little bit prettier. Yours may look a little harder to read, but the data should still be exactly the same. Back over to the editor. As we know, the fetch call is asynchronous, so we can handle the outcome of fetching this image with the promise. First, we can handle the fulfilled state, which is a success, and we do this by chaining onto the end of the fetch call. We can remove the semicolon, chain onto the end.then. Then is a method which we can chain onto a promise. Remember, when we use the Fetch API, this will return back a promise as the response, meaning we have access to the then method. Pass in a function. With this being a asynchronous callback, we'll only run the code inside of here. Wants to know the task was completed successfully. Of course, we probably want to access the data we get back from the fetch call. This can be passed to our function, so passing any variable names such as response. Then we could log this to the console and check if this works. I'll save into the browser and open up the console. There's a response. This successful promise returns a response object which contains details of what we get back from the server or from the API. This object contains things like the status code. In our case, it's 200, which means it's all good. Down to the URL low, we see the actual URL which we requested in the fetch call rather than the URL of the image which we get back. The reason we don't see this is because all the data which we get back is stored in this body section. If we open this up, we still don't see the URL of the actual image. Instead, we see a readable stream. This goes back to the JSON format mentioned before. To read this JSON format which is stored in the body section, we have a JSON method which we can use. Inside the console log, we can add onto the end the JSON method. Then let's try this one out. Save and refresh. We're back to a promise which has the current state of pending, meaning the task has not yet completed. This is because the JSON method also returns a promise too which we again need to handle. There is a couple of ways we can do this. First, we can remove the console log wrapper and leave response.JSON. Since this JSON method also returns back a promise, we can also chain on the then method. Pass this in, which again it runs a function. Also this function, it takes in the data from the response, so passes into a data variable. Then we can log this data to the console. Let's try this, save and refresh. Now, we've successfully passed our JSON content, which is stored in the body section. This returns back the actual image of the dog, which is stored in the message, and also success as the status code. This is the same response which we've seen when we pasted this into the browser earlier on. Everything here returns a promise, the fetch call returns a promise, and also the JSON returns a promise. But another way of doing this, which I personally prefer, but it's completely up to you, is to not nested then calls like this. If possible, my preference is to keep them all at the top level for readability. To do this, we need to cut out the nested then method which we've just added in. We'll leave it in response.json inside of here, and we'll cut out the second to last set of brackets all the way up to just after response.json. Cut this out. Now, the function should just left with response.json. Make sure the semicolon is removed from the end, and we can paste this onto the end, giving us two then methods in a row. However, though, if we go over to the browser and refresh, we see the message of undefined. This is because we are trying to access the data from our previous method. But first, to do this, we need to return this back. This all works just as before. We can also chain on as many of these then methods as 1, 2, and each one will wait on the previous result finishing before running the code inside. We'll keep full control over our async task and the order in which the code is run. We can also filter this down just like any other object. We could access the message, which is the URL of the image which you need. We can click on this and open this up inside the browser. We can also make use of this image URL and pass it to an image element. First, add an empty image element just above our script, and then in the second then method when we know we have access to this URL, we can remove this console log, select our image elements with document.query selector, and then set the source attribute to be equal to data.message. Let's save this and refresh the browser. Each time we refresh, we'll get different random image back from our API. This is the fulfilled state handled. But what about if there's a problem and we get back a rejected state? This will happen if there is an error fetching the data or completing the task which we asked for. This we chain onto the end a catch method. Here, we are chaining the event method , remove the semicolon, and then chain onto the end of the catch method which we'll run if there's an error, we pass that error to this callback function. A lot function with the error based on a console log. Let's start with a string of there was an error. We can also add onto the end the error message too. If we test this and refresh, we don't going to see anything inside the console because the image is being returned back successfully. To actually test this, we need to jump into the developer tools and go into the network tab. I'll select this, and to do this, we can actually turn off our network. Let's make this a little bit bigger. Chrome has this drop-down which you can see here. We currently not using any throttling, but we can also switch this to a slow connection or even offline. If we do this and jump into the console and refresh, switching off this network means when now don't get the image which we want. The promise should now throw an error. With all of this, the final thing which we're going to look at is the finally method. The finally method will run regardless of if the promise was fulfilled or if it was rejected. This can also be chained onto the end too. Like with all of the above methods, we also need to remove the semicolon as in the finally method, which again it runs a callback function. Place in a console log with the text of, I will always run. With the network still turned off, we can refresh and see this message. Let's turn the network back on, refresh, jump into the console, and we still see this console log even when the promise was a success. The finally method is useful to follow up with some code which we need to run after the promise has settled. Alternative would be to place this code into both the then also the catch sections. But this would result in duplicated code. This is promises and how it can be really useful with async JavaScript. This whole thing is possible because the fetch method initially returns a promise to kick off this whole chain. But what about things that don't return a promise? Well, next, we'll take a look at how we can handle this. 59. The Promise Constructor: In the previous example, we could begin to use promises because the Fetch API returns a promise. But what about functions which don't return a promise? To kick things off, let's write a simple custom function, and this is going to run and set some data after a time-out. I will jump into the promise constructor file, which is currently empty inside the script to create a variable at the top called data. Set this to an empty object. Create function called getData. Then inside pass in our setTimeout, which is going to take in a function. As a function Then just after this, we'll run this after 2,000 milliseconds time delay. After two seconds, all we want to deal with this function is to set our data object to have a value. We'll reassign this to be a new object where we'll pass in a name property equal to a string. This will call getData to actually run our function. Then at the very end we'll log the value of data, we can see what we get back. Parsing our data. We can also go for the name too. Into the browser, open up the file and jump into the console. The console see the value of undefined. This is probably unsurprising because we access the data object inside the console log before we've even set the name property, for the data takes two seconds to be set. This is a bit a simulated request to a database, free to handle what happens between requesting the data and getting it back. No promises are good for this, but this function doesn't return a promise by default. For this, we can create our own using the promise constructor. Constructors is something which we've already looked at with the new operator in the past. We've looked at things like new array. We've looked at new object and also new function. These all create a new instance of an object. Remember the promises are also objects too. We can also use this new operator to create a new promise ourselves. First comment out our example for now, which is everything except the data variable. Remove this. Then we can begin to construct our new promise below. Just with the examples we've seen before, we'll use the new keyword to create a new promise and this constructor takes in a new function which is going to run. This function takes in two optional parameters, a function to run if the promise resolves on one, if the promise has been rejected. These are names of our choice, but resolve and reject are pretty descriptive. What it's been our own custom promise, we set exactly when and where we want these resolve and reject functions to run. The first step is to store our promise inside of a variable. We'll just call this promise. I can call this in just a moment. But I will simply call resolve to resolve this promise. Then afterwards we can make use of this promise variable which is below the coldly, then catch and finally methods which we looked at previously. We can access promise.then, and this method is exactly the same as we looked at in the previous video, which takes in a function which is going to run, the code was a success. With this in mind, we'll place in a console log with the text of success. Allow this and make sure no semicolon is on the end. We'll also chain onto the end of the promise. The catch method, which will also take in a function. Remember the catch method will also be pass the error, which we can place inside a console log. Let's go over to the console now and see which one of these has been logged. We see the value of success, which is unsurprisingly because we've resolved this promise, meaning it's been successful. This result function can also take in a fulfillment value which you want to pass on. Let's say a string of success. Then this success message will also be passed down the chain if this has been successful. The successful section is the then section. We can pass this into our function. We can store this inside a variable such as response and then we can log this to the console. Refresh, and there we go. This is handy if you need to pass some custom data or message to the result section. But going back to the earlier example of fetching some data which we had above, this would be a better example than just simply sending a message. What we're going to do is to copy and paste this timeout section from inside the function. Then we can paste this just above the results section and uncomment out all three lines. We can then move up the results section to be inside of the timeout. It will also set the data and then resolve this promise. This means that the promise should now only be resolved after the data has been set. We can test this by login to the console. Jump into the then section, if this has been successful with a new console log the value of our data. Refresh. Give this two seconds. See the message of success, and our object has been updated with our string. This is how we can handle a success with a promise. But what about rejecting? Well, since this is our promise, we can make it do whatever we want to. This example, what about successfully resolving is the name of Chris has been set. I'm rejecting if the data object is empty. We can jump into our timeout just below where we set our data. We can place an if statement. We can check if Object.keys has in our data object. We can check if the length of this is greater than zero. The name being the key property here, we're checking if the length of this object is greater than zero. If it is, this means this has been set where we can pass in the resolve function. A success message. If not, just after the if statement will pass in reject, which will have passed into our function with the message of rejected. Let's try this. We'll have a data property sets, so we should expect the value of success. Gives this two seconds. This has been a success. If we want to check the rejected state, we can check if Object.keys is equal to length of zero, which results in a rejected promise. There is a bit going on here, but the idea is pretty simple. If a function by default doesn't return a promise, we can create our own. This can resolve or reject at any point we feel it should, giving us total control of the behavior of our function. 60. Handling Multiple Promises: Once we understand how promises work, handling an AsyncTask becomes a lot easier. But what about if we have more than one AsyncTask running at the same time, this can cause various issues. Do we wait on the first task to complete before moving onto the next one? As an example, if we had 10 AsyncTask running at the same time, if we waited on each one finishing before moving on to the next, the delay from each could really add up. Also, as an example, what if task number 10 relied on the value of task number 3, but task 10 finished first. Well, to help with some of these problems, we have access to some useful promise methods. We've covered some methods so far, including then, catch, and finally, and these upcoming methods are going to deal with multiple promises, starting with a method called ALL. The ALL method loops over multiple promises and returns one single promise and a single promise results to an array of the result. It's useful for gathering multiple pieces of data and maybe aggregating them into one single result. Let's take a look at how this works in the starter. Have two separate promises stored into variables. Promise number 1. This again is a simple example that we've seen before where we fetch an image from our API. If this has been successful, it then runs a function which will return back the value of the response. Along with this, we'll have promise number 2, which is using the promise constructor that was seen in the previous video. This will resolve after two seconds. I've deliberately kept them simple for this example. But imagine we wanted to know if both of these were a success. Rather than having to check each one individually, well, for this we can make use of promise.all. At the bottom, access promise, capital P. The ALL method. We're going to pass in an array containing both of these variables, so promise 1, promise 2. This promise.all method will take in any iterable value such as an array. We've looked at looping over arrays plenty during this class. Also, this ALL method will return a promise too, meaning we can chain onto the end various methods such as then and catch. We'll do exactly the same as we've done previously. We'll chain on then, which takes in a function. This function can also take in the results. We'll log this to the console. Afterwards, if there was an error, we can also chain in.catch onto the end as as an ALL function which takes in the error, place in log. Then let's give this a go. Over to the browser, make sure the current page is open. Refresh. After two seconds we get back, return, and an array with two results. The first one is our random image, which is stored inside this object. If we open this up, we can see that this one has been a success. The second one though, after the timeout, is shown as undefined, since the promise does not actually return anything. If we want to, we could pass a third parameter to setTimeout. Let's jump in and do this. Separate by comma. We'll pass in a simple string as a result, which is an optional parameter to pass to the function which we're calling, which is resolved. Now, after a refresh, we should see this value inside the console. We can also test a failure and see what happens if one of these promises is rejected. We can do this by instead of resolving, we can pass in, reject, and this one out and then I'll catch section, the console log will run. We see this value of results which we'll pass in here. But one thing you'll notice is we don't see the random image. Even though we're passing in both of these promises to promise.all, we only see the result of rejected. This is because when using the ALL method, it will only resolve if all of the promises it takes in results successfully or if a single one fails. We're either successfully getting an array containing all of the promises like we've seen before or the first one which is rejected. However though, there may be occurrences when this is not the behavior which we want. We may still want all of the promises to be returned regardless of if there was a failure or not. For this, we can replace all with all settled. All settled is still going to take in an array containing all of the promises. But now, if we save this and refresh, give this two seconds. Rather than seeing the single failure, we see all of our promises inside of the array. The first one was fulfilled. We'll see all value. Then we'll see the second one which has been rejected. We could use these results in any way we wanted to, such as looping over them to handle what to do if there was a failure or a success. For example, we maybe want to know which ones have been rejected so we can call them again. Or even maybe only show a user a certain section if the user request was a success. Something else we have is two methods called any and race. Both of these will only return back one value. First, let's take a look at any which we can use in place of all settled. Save and refresh and we'll see what we get back. This time we don't see the rejection. All we see is our successful image. This is because any method, as it sounds, will resolve as soon as any of the promises passed to it has been fulfilled. Which basically means the first promise, which is a success. This doesn't always mean that it's going to be the first one which is passed in the array. It just means the first one which has completed. The race method however, if we take a look at this, Save and Refresh, this also returns back the same random image, but this will return back the first promise passed to it, which has been settled. Settled could even be fulfilled or rejected. In our case, it's a random image because this one comes back faster because it doesn't have two second time delay. Regardless if the promise passed to it was a success or a failure, the first one back will be the one which you see in the console. To recap, the race method returns the first promise it encounters which resolves or rejects. The any method will also return one promise, but this one has to be fulfilled. They're both very useful to have if any of these situations comes up. 61. Async / Await: With the arrival of ES 2017, came a new way to handle asynchronous code. Often we've looked at previously is redundant, it's all still something which we need to know, particularly for what we're going to look at now, which is something called async/await. Async/await is actually promises behind the scenes, but it was created to look simpler, and be easier to read for developers. It looks simpler because we go back to something more familiar, which is a function. In starts files we'll have an example image where we'll return back a promise which we've seen previously. If you were to instead use a regular function to set this image, we'd do something like this. This probably will create a function called set image, and then inside, we could again make use of our fetch call. Paste this in and store this inside of a constant called response. Then, let's try to do a console log for the response, and as you all know from previous videos, here we're trying to access this async code immediately just below before it's potentially had the chance to come back. To run this, call our set image function, refresh the console, we get back to the pending state. We can see the response, which is our URL, which we originally calling inside of here, rather than our actual image, which we get back. What you may be thinking we could do next is to use response.json. Let's try this out. Store this inside of a constant called image, which is equal to response.json. We can pass this response. Now, look this image, the console. Let's try this again. This time we get an error, saying response.json is not a function, and this happens because the image data is not yet available. We've promises we know we have to chain onto the end of all fetch call, then methods, which then awaits the successful response before running a function. However, though we're not using promises this time, we're going to use async/await. For this, we have two simple steps. To convert our regular function to an async function, all we need to do is to pass the async keyword in front of it. Once you do this with a mark, which line of code we want to await on the data returning before we move down to the next one. Now in case we want to await on the image coming back, and this will effectively pause our function and wait for the data to return before moving it down to the rest of the code. Let's save this and see what happens. If we now refresh the error is now gone. The promise is still independent states, but if we open this up, we can access the data which we need inside this object. We can now see if we copy this image with quotations, we now get back our random dog image and the message of success. The reason why we need to dive into this promise is because we're trying to access our response.json on the line just below. We've still awaited our image to come back, but then we've logged to the console response.json. But remember from previous examples, the json method will also return a promise too. To deal with this, all we need to do is to await our json method to finally finish before we log this to the console. Now if we save this, try this again in the browser, rather than having to jump inside the promise and into the object. Now, directly see the correct information we need inside of the console. We've now returned the URL inside this message property, which we can use to set our image elements. Let's grab this. We can remove the console log access document.queryselector. Wasn't in the image where we can set the image source to be equal to the image.message. There we go. This is how we can use async/await with this regular function style. But there is also different types of functions available too which you've looked at, including function expressions and arrow functions. Just like this. With a function expression. Say let func as the variable name and say this equal to our function, which is simply going to return a string of hey. The arrow function equivalent would look just like this. Here we have our function expression and then we have our arrow function. Async/await can be used in either one of these. The way to mark our function expression as asynchronous is to just like above, passing the async keyword just before the function keyword, and also the same for our arrow function too. We can place this in right at the very beginning, and then we can use the await keyword anywhere inside of the function body. Async/await is a clean and powerful solution to handling async tasks. But we need to be careful to not get too carried away. In this example, we're setting the image on the next line. It makes complete sense to await on the data coming back before we use it. But imagine if we had something like this. If we duplicated this response, and we asked for our two separate image. What we're doing here is we're making two requests for two independent images at the same time. But the problem we currently have is the second image is not going to be called until the first one has returned because we use the await keyword. Now this will cause an unnecessary time delay in the code below. Here, we're trying to access our first image, but we still need to wait on the second image being returned before this line even runs. We use a wave, but we need to wait on the data, which we need to and after. But we still don't want to block the rest of the code from running, if we don't need to. Handling multiple requests like this is something which we'll look at next in more detail. Along with soon looking at error handling too. 62. Handling Multiple Awaits: At the end of the previous video, we discussed the effects of multiple await calls. Here, we have three, have response, responds 2, and response 3, which all make the same fetch call. We know, for example that if the second image needed to wait on the first image data coming back before being run, this was completely fine. However, though if image 2 doesn't rely on the first image, it shouldn't block this code unnecessarily. With multiple requests for async data like this, it brings us back to a previous video, where we looked at how to handle multiple promises. What if we want to know if one fails or if they all fail, how would we then go about handling this? With promises we could use methods such as all and all settled. But with async code, these promises also under the hood. We can still make use of these methods such as all. For example, down at the very bottom inside of our function, we can access promise to all, which takes in an array. We can pass in response, response 2, and also response 3. Let's store this inside a variable or a constant called result, and then log this to the console. An error, so that needs response. This still returns a promise, but remember the all method will resolve into one single promise, if all of the promises it takes in resolves successfully, or if a single one fails. With this in mind, we can also use the await keyword to make sure they all resolve first before moving on to the next line. Pass in await, it is before this. Now we're awaiting all three of these promises to now complete. This means we can now remove the await keyword before each one of these free independent calls. Let's try this out, refresh. We now get an array with all three separate responses. We can go into each one of these. But one of the problems which we still have is, if we look at the URL, this is the image URL which we are requesting inside a fetch, not the actual JPEG image, which is coming back from the API. If you remember, to access this actual image which we need, this is contained inside of the body, and to read the contents of the body, we again need to make use of the JSON method. The JSON method will read the contents of this and turn it into a JavaScript object which we can read. As we can see we've got an array with three separate values. What we can do, is we could remove our console log and loop over all three of these values with the forEach method, so results. For each function, store this inside of value. Now we can log this value to the console and call the JSON method for each one of these values. This now gives us back our three separate promises. But if we open this up, we see a familiar object which we need to dive into to get our actual image back. This happens because as we've seen previously, the JSON method will also return a promise. To wait on this data coming back before we access this, we can use the await keyword, and because the await keyword can only be used inside of a function, we can mark this as async. Reload. Which then gives us back our three images, which we need. This all method now means we can do something after all promises have been successful, or if a single one fails. Speaking of failure, the subject of the next video is looking at how we can handle errors using async await. 63. Error Handling: This video is going to show you some ways to handle errors in your async code. Code is great when all things go well, but when things don't, we need to handle what to do. Some of the promise methods we've looked at give us some error handling. For example, the all method fails if one promise fails, so we have some options there, but we also need to handle all other situations too, either a general error handler, or handling each specific request. In the starter project, in the error handling file, we have an empty image element at the top and also a single function. Nothing new here for this function, this is just grabbing an image URL using the Fetch API. We wait on the data coming back, which is stored in response. We then extract this data via JSON method, and then return the image property which contains the URL. Just before, we use this function, let's take a look at another simple example. Just below, let's create a new function with any name, and all this is going to do is to return any simple string. After this, we'll console log the return value, we call our function, opens up in the browser, and there's our return message. Nothing unexpected here, but if we mark this function as async, so just before the function word, mark this as asynchronous, and this time we get back a promise. We're just going to leave this function there, but just bear this in mind for a moment. As soon as we mark a function as async, it will then return a promise. We know we've got a function to grab the image URL, so let's create a second function which is actually going to set the image URL through this image element. This can also be async, call this setImage. Then inside, all we're going to do is going to grab our image elements with document.query selector and set the source to be equal to the return value of the above function. I start with image element, and set the source equal to our above function, which is getImageURL. We need to call this. The getImageUrl function is async, so we need to await on this promise being returned before we can actually use it. We're going to wait this function returned value. This is all enabled since we've marked his function as async. Let's call this just below, setImage. Earlier when handling errors using promises, we simply chained on a catch section to the promise. This setImage function is also asynchronous too, which also returns a promise just like we've seen before with the simple example, meaning we could chain onto the end, then all the catch block which is going to run next. We can chain this on the end, making sure there's no semicolon, add catch. Catch will run a function which takes in the error message and place it in a console log the message of "noooo" and also a second one with this error. Now, let's see what happens if we try to call this function. Do we get back the error we'd catch or do we set the image. This particular call was a success, so we see the image returned back. To test out the catch block, we need to switch off the network like we've done previously, so jump into the Network tab. Under here, we're going to set the presets to be offline, now we can refresh, we don't see the image. Jump into the console. Our first console log and our second console log have failed to fetch. We see this works fine and we're mixing the syntax of async await with promises. If we wanted to just stick with the promise syntax or move the error handling into the function itself, we could use something called try and catch. Try and catch, as it sounds, will try to do something, and if it works, that's all great, if not, we catch the error and handle it in any way which you want to. Let's remove the catch section from setImage, and then inside of our setImage function, we create a try-block and below a catch block, which is also going to take in the error message. This is reasonably simple, all we need to do is to move our code which you want to run inside of the try block, so cut this out, paste this into the try section, and then inside the catch area, we can place in the same console logs, so a string and also a second console log with the error message which is passed to this function. Let's save this and try this out. Bear in mind, my network is still disabled, so if we try again, we don't see the image, you will see our two error messages inside the console. Let's try to switch this back on, return the network, the image is now returned, and we don't see any of these console logs running inside of here. This try and catch section is running synchronously, so we'll run the very first section which is try. If this all works, that's completely fine, but if it fails, it will then move down to the next catch block and run the code contained inside of there. On top of this, we also have a finally section 2. This works just like when we chained finally onto the end of a promise. Finally will always run regardless if the promise was fulfilled or rejected. At the bottom, pass in finally, and we'll just place in a simple console log. Let's try this, refresh and we see the console log with the text of always runs. Just as a quick side note, the catch or the finally block need to be present. It must have at least one of these in place, or just like this example, we can use both. This is fine for general error catching, but what about if we wanted to know which part of the try code failed? At the moment, this is pretty simple because we only have one line of code. But what about if this try section did more than this? For this, we could chain a catch block directly onto the async task and to see an example, I'm just going to copy this full function, comment this out for reference, then paste it in below. We can remove all of the error handling which we just added, which includes the catch, the finally, and also the try-block leaving our simple async function. With this, we can then remove the semicolon, we can then chain catch onto the end, inside of catch, we could pass a function directly inside, or if we wanted to reuse this function, we could make a separate function inside of our code. Let's create a function just above called handle error. We'll just grab our two error messages, paste these in. The error will also take in the error message, then we can call this inside of catch. This gives us a separate reusable function, which we can then chain onto the end of multiple promises. Let's try this out. We should now see our two error messages. If there's a failure. If not, we see the image, this works fine. Let's try and turn the network off once more, go to the console, there's our error messages inside of here. Of course, a console log wouldn't be enough in a real-world application, we would maybe want to hide the image if there was an error or even add a place holder image in place. But the key here is to do something rather than just see the website or the application breakdown. Handling errors is a big part of async JavaScript, and we see some common patterns here which you can use in your projects, which will really improve the functionality and user experience. 64. Leaving So Soon: This first project which we find in the last section of this class, is called Leaving So Soon, and it contains some starter code so we're going to focus on the JavaScript. This project is what is called a exit intent pop-up. An exit intent pop-up is basically a way of grabbing the user's attention if they try to leave your site. We have some simple HTML, have our title, and then we've got this pop-up section inside of a div. If we go over to the project and refresh, all we currently see is this title. The idea is we have a simple website like this and you may have seen these types of websites when browsing online. If you try to move the mouse up to the top, and try and close down the browser, or to even search or navigate away from the site, you may often see a pop-up appear. This pop-up could contain information. It can contain a voucher code, or just generally anything to keep the user on your site. We don't see this pop-up section because if we take look at this div, it's got the ID of exit pop-up. Inside of our style sheets, if we take a look for this section, the display type is currently set to none. If we change this to be flex and refresh, the background will fade out because of the CSS animation, which we have just at the bottom. Our pop-up now appears with all of the text inside. The contents inside of these websites or inside of this pop-up is irrelevant. The idea is we want to toggle this display setting once a user's mouse leaves the top of the browser. For now, let's go back into our style sheet, and I'll hide this by default. Then, we get to work inside of our script, which is already linked down at the bottom. Let's open this up. If you think about what we want to do here, there's not a lot of tasks which we need to run. Let's start by creating a function which is going to run when the mouse has left the window area. Once the pop-up is actually displaying inside the browser, we also need a way to click on an X in the corner and close this down to. Create a second function called closePopup. We'll start with our first function, which is leftWindow and for this, we need to listen out for a mouse event. We're going to select the document which is our full webpage, and then listen out for when the mouse leaves with the mouse out event. Let's grab our documents. We can add an event listener. Events. We want to listen out for is mouse out, which is then going to trigger our above function. Remember, with events this also takes in the event information which we can access inside of a variable. Let's begin by logging this into the console. Log the event information into the console, refresh, and we can see if we move the mouse outside the documents area, this mouse event is now fired. This will also work if you go for the other side, and also the very top two. Jump into here. The mouse coordinates which we're interested in is this clientX and the clientY. This is a pixel value which will tell us the mouse location once this event was fired. Just like when we looked at the Canvas early on, X is the left or right direction, and the Y is top to bottom. Since we're trying to watch out for the mouse, leaving the top of the browser to close this window, we're going to be interested in the clientY direction. We can filter this down, e.clientY. Let's reload. Now, if we go to the top, we can see as soon as we pass the top of the browser area, we then begin to get a negative number, meaning the very top here is the value of zero. We need to listen out for maybe a 20-pixel area, which will display all pop up as soon as the user moves the mouse up to the top area of the browser. We can remove the console log. Place in an if statement. We can say if e.clientY is less than any value of your choice, I'm going to go for 20. As we've seen inside of these style sheets, we can grab our elements with the ID of exit-popup and toggle the display type. Grab this with the document.querySelector. I send the ID of exit-popup. Set the style property of display to be equal to flex. Let's try this out. Refresh and now move to the top, and this one will trigger our pop-up. You may think this is all working fine and this is all we need to do. We also need to take some steps so that we don't irritate the user. Need to activate this cross so it toggles our closePopup function. But probably only want to run this code to activate the pop-up after a certain amount of time, and we also want to make sure this is only triggered once on the user's visit. To make sure this is only triggered once, we'll do the reverse, and we'll remove the event listener from the documents. From early videos, we know that we need to copy the same information from addEventListener. We can't test this out just yet because we also need to be able to close the window down before we can reactivate it. We'll do that now we'll go into the closePopup area, and then do the opposite by setting the display type to be equal to none. To activate this function, we need to listen out for a click on our cross. Inside the index page, the span contains the cross area. Let's grab this inside of our script, under the bottom, document.querySelector. We'll select our span. Store this inside of a constant called closeBtn. Grab the elements, add an event listener. We want to listen out for the click events, which will run our above function. Let's try this out. Move to the top to activate the pop-up. Click on the cross. We can also see if we move to the top of the browser, our pop-up isn't reactivated because we removed the event listener. All good, this is working pretty well. But one quick addition we'll make, is to make sure that the pop-up isn't activated as soon as the user visits the site. If there are, for example, typed in something at the top and then moved straight away, you don't want the pop-up to appear immediately. What we'll do is we'll place a setTimeout to only activate this function after a certain time delay. Call a setTimeout. Pass in a function where we can move our mouse out event, which triggers our function. Will only call this after a time delay of three seconds. Try this out so we can move our mouse up for the first three seconds. Then, after three seconds, our function is active. Pretty simple project, and we can do quite a lot with a small amount of JavaScript code. It's something which you may find useful when building websites in the future. As will be our next project, which will be an image carousel, which we'll build completely from scratch. 65. Image Carousel- Setting The Images: In our next project, we're going to build in a image carousel. This is going to be the end result, and it's completely built with JavaScript. What we'll have is a main large image at the very top. We can cycle through the bottom images to replace this using the left and right arrows. Also, we can skip to any one of these images by clicking on them, and placing these up to the top section. This is going to put together a lot of the skills that you've learned and also better see how things work in practice with a real-world app. Let's start this over in the starter files. If we jump into the next section, which is the image carousel, we have some starter code. We've got a very simple index page, we'll be injecting all the contents by JavaScript. All we've got is an empty div with the id of carousel. We'll place in all image contents, and then we'll link to our script. The script is inside the carousel folder, which contains our images, our style sheets, and also the JavaScript to make this work. Provided with this course is five different images which you can replace and also some basic CSS. We've just got some basic styling. For example, we set the main carousel to be a certain width and also place it into the center with margin 0 auto. We've got some hover effects. Other than that, some general styling along with the small and the large class we have here. We'll be adding these smaller than large class to each one of these images so they fit nicely on the screen. Let's start. We jump into our empty carousel.js. We'll begin by grabbing this carousel div section and also create an array with all of the images. Jump into the carousel.js. We'll start by creating an array of our images. Each one of these is going to be a string which points to the URL inside the images folder. If you have used your own images, remember to change the names inside of here to match the ones which you've placed inside. The first one, this is in the carousel folder, and the file path is images/beach.jpg. Let's duplicate this to give us five different images. The second one was elephants. We've got grass. We've got lake, and the final one is town. Next, we'll grab a reference to our carousel. We'll store this inside of a constant called wrapper is equal to document.query selector, plus in the id of carousel. The next step, we're going to create a function which is going to grab all these images, will loop over these and place these onto the screen. So create a function below called setImages. The first step inside of this function is to grab our wrapper, and we'll clear out any existing contents. This is so we can repeat the process of setting our images, but sometimes they'll be in a different order. We'll clear out any extra images by grabbing our wrapper and setting the inner HTML to be an empty string. Before I forget, we'll call our function from below, and then it grab our images and create a for each loop to loop over each one of these, images.forEach, plus inner function. We'll create a reference to each one of these and we'll call it image source, imageSrc. Open up the function body, and then inside here, we're going to create a new image element, store this inside a variable called elements, documents.createElement. Write an image element. Then we need to set the image element source to be equal to this variable. Grab our element, set the source attribute to be equal to our image source. We can then grab our wrapper, which we stored inside this constant, then we can add to this new element, wrapper.appenChild, plus in our newly constructed element. Let's go over to the browser and see what we have. We've got our five different images from this loop, but if we take a look at the final version, we don't just want five random images placed inside the container. What we want to do is to make the first image large and then create a separate section down at the bottom with the remaining small images. To do this, we'll create a wrapper for all the small images down the bottom, and then it will section this off the place a small images inside of here, and the large image at the top. First, let's jump back into our function and create a new wrapper for the four small images at the bottom. Just after where we clear our upper and create a new constant called the smallImageWrapper. This is equal to document.createElement. This can be any element you want to, such as a div or a section, it doesn't matter. Then grab our section, and we'll give this a unique ID of smallImageWrapper. Now what we want to do is loop over all five of our images in the array. The very first one needs to be placed into the wrapper, and then all the four remaining images need to be placed inside of our small image wrapper. The way we can do this is by first selecting our full wrapper and checking if it has any current contents. If it doesn't already have an image element assigned to this wrapper, this means it's a very first image in the array. What we can do inside of our loop is we can place in an if statement, and we can check if our wrapper doesn't have any child nodes. We can say!wrapper.hasChildNodes. The code inside of here will only run if this wrapper is empty and it doesn't contain any additional images inside. This will always be the case if we are looping through and on the first image. If this is the case, we want to set the class. If we look at our style sheets, we want to set this class of large because this has a width of 100 percent. If not, we'll add the class of small, which gives you this smaller size. It's add a class, we can grab our elements.classlist.add, place in the class of large, and also the class of carousel. This class of carousel, if we again go back into the style sheet, will turn the cursor into a pointer when the user hovers over the image. This one should only apply to the very first element inside of our wrapper, else it should apply for the remaining four images. We'll add a class list of small. We'll add all small and also carousel. We still get the hover effect, but this time since we are dealing with the four smaller images, we don't want to add these to the main wrapper. Instead, we want to add them to our small image wrapper which we just created. So let's grab this, open child, placing in our elements. Let's save this and try this out. There we go. There's our large image and the four small images in these separate div. Just as a recap, what we've done here is we've created one large wrapper for all of our section. We've created a function called set images. As soon as this runs, it will clear out any existing contents from the wrapper, which means that when we're loop over our images, if this wrapper is empty, this means it's a very first element in the array, therefore we give it the large class. If not, it's the remaining four images where we add the cluster of small and also place this into a separate div. This is a good first stage for our project. In the upcoming videos, we'll take a look up various other functions such as reordering these images, how to swap the images around, and also how to place in the arrows to go left and right. 66. Image Carousel- Creating The Arrows: We're at the stage now inside of our project where we've got all five images displayed on the screen. We have a large feature image at the top, then of four smaller thumbnails below. We have some improvements to make, we want to be able to click on any of these smaller images and places into the featured section at the top. We also want to be able to rotate these around by adding a small arrow to the left and also to the right. Let's start with this by adding the arrows once the images load. To do this, we can place these into a standalone function and call this. Let me call our images. Right at the bottom of this function, we'll call our function, which we're going to call setArrows. This is the function which we'll create next. Just below this sets up our function which was setArrows. SetArrows doesn't need to take in anything as a parameter, so what we need to do here is we can create some icons using HTML entities and store these as the inner HTML of a span element. What we need is two constants, the first one is the left arrow just equal to document.createElement as in a span. The reason we're using the span is because by default this is an inline element, so we can place these inline with our four images. The left arrow, let's access these constants and set the inner HTML to be equal to our HTML entity and the code for the left arrow is the ‹ Both of these arrows, you need to click on these and reorder all our images. We'll select our constants and add an event listener is now a free click, which is going to trigger a function. We've not yet created this function, but it will be called reOrder and just so we don't throw any errors, we'll create this function above. This doesn't need to have any contents, we'll come back to this. Just underneath our event listener , we'll do pretty much the same, but this time for the right arrow, we'll create the span elements with document. createElement, set the inner HTML, rightArrow.innerHTML. The HTML entity code for the right arrow is &#8250, which is just one up from the left arrow. Add an event listener. This one is also listening out for a click event, which will trigger the same function. Those are our two arrows created with the contents and the event listener. But what we now need to do is to also add both of these to a certain section. If we go back up to our first function which was setImages, we have this smallImageWrapper. This is a div section which contains over four small thumbnails, so we'll add both of these into this section. The way we can do this at the beginning and the end, is to use a JavaScript method called appendChild, which will add this to the end of the div placed on the right. Then for the left arrow, we can use the prepend method, which will add this to the very start of our div. Let's do this at the bottom of our setArrows function. Let's first grab the section, so on the inside of a constant called smallImageWrapper, the document.querySelector, this has the ID of smallImageWrapper. Grab this section. As I've just mentioned, we'll place the right arrow into this contents with appendChild, like we looked up previously. This will add this to the very end of our div section after our images. Place in our right arrow, then let's add our left arrow onto the start, we'll use the prepend method and insert our left arrow. Let's try this. Now after refresh we still don't see our arrows on the screen. Let's take a look in the console and see if this gives us any clues. Inside of here we can see we cannot read properties of null, reading appendChild, so when we try to append a new element to our single image wrapper, we seem to be getting an issue. The reason this happens is because we've got a smallImageWrapper which we are creating up in the top. When we set our images, we've got the main wrapper that contains our full carousel and then, we have our smallImageWrapper, which we are trying to select by this ID inside the loop. But each one of our images, we're creating a new image elements stored in this variable, we add in either the large or the small class, and if it's a small image, we then add in these four small images to this smallIimageWwrapper. But currently, we're not actually adding a smallImageWrapper to the DOM, all we're doing is creating it and we're adding our four elements, but we're not actually placing this inside the DOM. At least then, we're able to select down at the bottom. The only time something is getting added to the DOM is when we add to our wrapper this element. Adding the element directly to our wrapper is completely fine if this is the large image because it's going to go directly inside of the main carousel. However though, instead, when we're dealing with a small image, we want to assign these smallImageWrapper to this section. The way we can do it is by selecting our element and set this equal to our smallImageWrapper. This smallImageWrapper will contain all of our four small images and then we'll add this to our main wrapper. Now if we save this and refresh, we can now open this up, we see our two arrows jump into the elements and if we go into the body, we see our main wrapper with id of carousel. We can open this up. We see our first image with the class of large. Just to clarify, this one gets assigned because as soon as we start looping through all of our images, we check if this section is empty, if it is bigger with the class of large and add this to our wrapper. If not, the four remaining images will get the class small and then add to our smallImageWrapper, which will then be passed to our elements and then we can add these to the DOM, which we can see if we look at this div just here. We can open this up. We have our span element which we just added with prepend, we have our four images and then, the final span which we added with appendChild. 67. Image Carousel - Re-Ordering Images: Previously we set up our left and right arrows and also linked these to a function called re-order. We did this by creating our arrows inside of this function, using our for a click event, which in it triggered our function. What we're going to do now is basically create a new array. This new array is going to be constructed by rearranging the order of all of these images. We'll do this inside of our function by first taking in the event information from the click, and the reason we're doing this is because we need to determine which one of these buttons has been clicked. We need to know if it's the left button or the right button. We can do this by adding an ID to each one of these, so the leftArrow.id is simply equal to left. Then go down to the rightArrow.id right. Now we can access this ID by the elements information from the event. We know from previously, by doing a console log, if we log the value of e.target, we get the actual elements inside the console. Click on any of these get the right button, and then the left button. We can also filter this object down, grab just the ID. This now gives us a unique pointer as to which button has been pressed. We can now remove this from a console log, store this inside of a constant called direction. Now what we're going to do is we'll loop over our images array up at the very top. We'll make sure we cover all five of these images. We'll then determine if the left button or the right button has been clicked, and then we use this to reorder our images. These new images will be stored inside of a new array called newArray, which will have the initial value of an empty array, and then we can loop over all of our images. Do this with a forEach loop, pass in our function. Then inside of this function it's going to take in two things. First, as ever we'll pass in a variable name, which is going to be each image on that particular loop, and then we can also access the index number. For the first loop, this will be the first item, which is our beach with index number of 0. Then this will be incremented one on each loop. To rearrange these images, we need to first check if the direction will begin with left. If not, we'll add an else section which will run if the direction is equal to right. Let's think about what we want to do if the direction is left. If this left button is clicked on, we need to loop through the original array which we are doing and for the very first item inside of here, we want to push this to the end of our new array, and then for the remaining four images down at the bottom, we want to shift these back one position. We can do this inside of the left button. We'll check if the index number which will have access to just here is equal to 0, so i.e it's the main featured image at the top. If this is the case, we want to push it to the very end of our new array. We can do this by accessing this variable. We can position this at the very end by accessing our images.length property. For this example, this should be our new array in index Position 5. We'll set this to be the first image. Grabbing our first image from the original array or pushing it to the end of our new one. We'll also call it newArray.shift in case there is anything at the beginning of this array. This is the very first image taken care of, but what about the remaining four? Well, for the remaining four images, all we need to do is grab the current index number and shift this back by one. We can do this inside of an else section just after if, placing else. This will be the case for the remaining four images. All we want to do is to grab our new array, select the current index adopt the value of one, and set this equal to our current image. For example, if our current image is index Number 3, this will be moved back to Number 2, and this will be the same for the four remaining images. Before we go any further, let's try this out. Currently our function is being called and it's reordering the array, we will also need to override the original images array with our new one. We can do this at the bottom of our function, set our images array to be equal to the new array. Also once we reset our images array, we need to call the set images function, which is actually looping over this array and displaying them on the screen. We'll do this at the bottom. Call this function, and let's try this out. Refresh. If we click on the "Right Arrow," we get an error because we haven't handled this case yet. Let's try left. We have the elephants, which has now moved up to the first index position. Let's click "Left" again. This has moved to the end. This all seems to be working fine. Just to recap, we're grabbing the very first image and then pushing this at the end of our new array. Currently it's the beach, this goes to the end, and the remaining four images will be moved to the left by one index number. Next we'll take care of the L section, which is if the right button has been clicked. What we're going to do in here is basically the opposite of this line just here. We need to, rather than remove one index number to move it to the left, we need to add one to move each one to the right. We'll paste this in, all at an index number of one. This time rather than checking if we are accessing the first image, we need to check if we're accessing the last image. If it's the last image, it then needs to be removed from the end of the array and placed at the very beginning. We can do this inside of an if section. If the index plus one is equal to images or length. The reason we've done this, because remember index numbers begin at 0, but when we're accessing the length of the array, this will be the actual number. Currently this is 5, but the index number only goes up to 4, meaning we need to plus 1. Check if this is also equal to 5. So if this is equal to 5, this is our very last value in the array. We need to set this to be at the very beginning. The very beginning of our new array is going to be index Number 0, which we can set to be the current image. Also just like we did when we removed the very first item from the array, this time we need to remove the very last one, newArray.pop. Let's save this and try this one out. To the right, we should see the houses moved to the top and the beach moved to the left. Good. Now the lake, the grass, the elephants. This now works completely fine in both directions. 68. Image Carousel- Swapping Images: Our next and final task for this project is to allow the user to click on any one of these small thumbnail images, and then this will be swapped with the main featured image at the top. The small image will be placed in the large section and the large image will then drop down to the thumbnail area. For this one we create our small images of any set images function jump into the else section, where we add the class of small. What we'll do here is we'll add an event listener to each one. Just after we add the class. Before we append this to our wrapper, we'll select our elements, add an event listener, where we listen off the click, which is going to trigger a function which will create in just a moment called swapImages. Down to the bottom. Our function will swap images. Inside of here we've added the event listener, which is going to trigger this function, each time we click on one of the small images, but just as an extra precautionary step, we'll add an if statement to return out of this function if the large image has been clicked. What we'll do is since this is an event, click "Event", we'll parse in at the event information, we'll access the elements with e.target. Then we can check if the classList contains, using a contains method, the class of large. If it does, we'll return out of this function. This is just for our precaution. Next, what we'll do is we'll grab using the event.target information, the actual image which has been clicked on. All we need to do is grab the source attribute, find out which one of these images needs to be placed in the featured area. We can do this, install this inside of a constant called image source, set this equal to e.target. We use getAttribute, where we'll grab the source. Now we have this image source, which is the file path. We can use it to grab the index number of our array. We'll grab our images array. We'll then use the method called indexOf, and then parse in our source. So the images, indexOf, as in our variable name, which is image source. This is going to return back an index number which you can store inside of a constant called selectedImageIndex. What we have now is the index number of the clicked on thumbnail. Now we need to swap this with the image which is at index position 0. But before we actually make this swap, we need to first store which image is currently in index position 0. We'll store this inside of a constant called firstImage. Set these two images at index number 0. Then we can reassign the original first image, so images 0 is going to be now equal to images, and parsing this selected image index. This replaces the first image with the clicked on thumbnail, and then we need to do the reverse by, again, selecting our images at the selectedImageIndex. Swap this with our first image. This is a reason why we originally start off firstImage because on the next line, we're reassigning the first image. Therefore, it gives us the wrong value at the bottom. At the end we'll call our setImages function, to re-update the browser with the new order of the array. Let's try this out for the grass. The beach drops down to the bottom, we'll try this one. Good. This now completes our image carousel project. I hope you've enjoyed it and learned some new tricks along the way. 69. Follow me on Skillshare: A huge congratulations from me for reaching the end of this class. I hope you've really enjoyed it and gained some knowledge from it. If you've enjoyed this class, make sure you check out the rest of my classes here on Skillshare, and also follow me for any updates and also to be informed of any new classes as they become available. Thank you once again, good luck, and hopefully, I'll see you again in a future class.