Full Stack Web Development for Beginners- Part 4: Final Project, Node, Express & MongoDB | Chris Dixon | Skillshare

Full Stack Web Development for Beginners- Part 4: Final Project, Node, Express & MongoDB

Chris Dixon, Web Developer & Online Teacher

Play Speed
  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x
66 Lessons (10h 7m)
    • 1. Welcome to the course!

    • 2. What we will be building

    • 3. What is Node & NPM?

    • 4. Static v dynamic web server

    • 5. Express.js and express generator

    • 6. Express project structure

    • 7. Using Nodemon

    • 8. Serving static files

    • 9. Introduction to Pug

    • 10. Template inheritance

    • 11. Time to practice: Creating the header

    • 12. Solution: Creating the header

    • 13. Mixins

    • 14. Basic routing

    • 15. Route parameters

    • 16. MVC Pattern

    • 17. Using controllers

    • 18. Using middleware

    • 19. Important Update: mLab now part of Mongo

    • 20. Getting started with Mongo

    • 21. Mongoose models

    • 22. Creating our hotel upload form

    • 23. Pushing to the database

    • 24. Querying the database

    • 25. Distinct values

    • 26. The aggregation pipeline

    • 27. The edit and remove form

    • 28. Updating records

    • 29. Deleting records

    • 30. Hotel detail view

    • 31. Locals and conditional rendering

    • 32. Hotels by country

    • 33. Styling the header- small screen

    • 34. Styling the content- small screen

    • 35. Large screen styling

    • 36. Countries mixin

    • 37. Promise.all and array destructuring

    • 38. Environment variables

    • 39. Handling file uploads

    • 40. Saving images to the cloud

    • 41. Retrieving images from the cloud

    • 42. Hotel search form part 1

    • 43. Hotel search form part 2

    • 44. Search results template

    • 45. Hotel detail search from

    • 46. Creating the user model

    • 47. Sign up form

    • 48. Validating user input

    • 49. Passing errors to the template and sanitization

    • 50. Registering new users

    • 51. Password encryption

    • 52. Logging in

    • 53. Logging out

    • 54. Working with sessions

    • 55. Providing user feedback with flash messages

    • 56. User conditional rendering

    • 57. The order model

    • 58. Booking confirmation page

    • 59. Placing orders

    • 60. User account area

    • 61. Displaying all orders

    • 62. Final CSS

    • 63. Preparing for production

    • 64. Pushing our express app to Heroku

    • 65. Thank you

    • 66. Follow me on Skillshare!

17 students are watching this class

About This Class

Welcome to Full Stack Web Development for Beginners!

This course is designed to teach beginners everything they need to know to build full stack websites and applications!

This is part four of this huge course, teaching you all about Node, Express, Mongo, Mongoose, Routing, Templating, Authentication and deployment!

This course is all about moving to the back end of websites where you will learn lots of amazing things.

We start off with Node and the Express framework where we set up a travel booking application called let’s travel.

We will build this project throughout the course so everything you learn will be immediately put into practice.

Node and express are really popular and learning these technologies will leave you in high demand.

After this, we move onto routing and templating.

This allows us to switch between pages and navigate through our app, along with setting up templates to display not just content we have created, but also to render data from databases too.

And databases are what the next section is all about, where we look at MongoDB and Mongoose.

You will learn so much including modelling our data, create, read, update and delete actions, along with filtering and aggregation to get back the exact data we need.

After this we push on with styling and adding lots of nice features to our project, along with learning many next generation Javascript techniques from ES6 and beyond.

You will also learn how to allow users to upload images, and how we can save and retrieve these images from cloud storage.

Of course, most apps nowadays need to deal with user accounts and authentication, and this is something we will also learn about while applying all this to our project.

 You will learn how to create user accounts, logging in and out, validating the users information, authentication, storing passwords safely and so much more.

We finish off our app by allowing the user to place orders and save to the database.

Then we create an account are where the user can log in and see any bookings which they have made, and also admin users can go into the admin section too to see a list of all orders from the site.

 The course ends by showing you some security tips and recommendations to prepare your application for production.

 We then push our app to a live server for the rest of the world to see.

All while explaining things in a straightforward, simple to understand way which even beginners will understand, along with reinforcing things with a fun, yet challenging project as we go.

I hope your excited to learn about Javascript, Node, Express, Mongo, user accounts and authentication, routing, deployment and so much more, in the final part of this course….


1. Welcome to the course!: Welcome to Full Stack Web Development for beginners. This course is designed to take you from a beginner to a web developer capable of building not only the front-end user interface, but also to design and build the backend to interact with too. Who am I? My name is Chris and I will be your instructor throughout this course. I am a web developer and also the producer of lots of tutorials, teaching thousands of students the skills they need to build websites and applications. This is the fourth part in the full series, where we will continue to build on everything from the first three parts of this course. This course is all about moving to the backend of websites, where you will learn lots of amazing things. We start off with node and the express framework, where we setup a travel book in application called Let's Travel. We will build this project throughout the course. Everything you learn will be immediately put into practice. Node and Express are really popular and learning these technologies will leave you in high-demand. After this, we move on to routing and templating, which will allow us to switch between pages and navigate through our app, along with setting up templates to display not just the content we've created, we'll too also render data from our database too. Databases is what the next section is all about, where we'll look at MongoDB and Mongoose. You will learn so much including modeling our data, create, read, update and delete actions, along with filtering and aggregation to get back the exact data which we need. After this, we push on with styling and adding lots of nice features to our project, along with learning many next-generation JavaScript techniques from ES6 and beyond. You will also learn how to allow users to upload images and how we can save and retrieved these images from our Cloud storage. Of course, most apps nowadays need to deal with user accounts and authentication. This is something which we'll learn about while also applying all of these to our project. You will learn how to create user account, login in and out, validating new user's information, authentication, storing passwords safely and so much more. We finish off our app by allowing the user to place orders and then save them to the database. Then we create an account area where the user can log in and see any bookings which they have made. Also admin users can go into the admin section to see lists of all orders which have been placed. This course ends by showing you some security tips and recommendations to prepare your application for production. We then push our app to a live server for the rest of the world to see, all while explaining things in a straightforward, simple to understand way, which even beginners will understand, along with reinforcing things with a fun yet challenging projects as we go. I hope you're really excited to learn about all of these things, in the final part of this course. 2. What we will be building: In this section and for pretty much the remainder of this course, we're going to build the niche travel application, when user can login and make bookings for hotels in various countries. This is going to be the homepage, which is going to be the starting point where a user can search for hotels in different countries. We can also add the number of nights and also the number of guests, as well as certain filters such as the star rating, and we can also solve the hotel's price wise from low to high or high to low. Further down, we're also pulling in some random hotels from the database and restricted needs to be the first nine. The user can click on any of these hotels and find out more information. He will get an extended view of the hotel. We also get a description and then at the bottom, we get the chance to then search for this hotel with the current availability and also the current price. If we go back to the homepage further down at the bottom after the hotels, we also have a list of countries where we can filter down the hotels by the various countries. If we click on each one of these, we can then see each hotel which is available for that particular country. Along with these filters, we can also click on the "All Countries" and then see a list of all available countries which we have hotels available for. Once we add new hotels as an Admin, these countries are automatically updated on the front-end too. So we don't need to worry about adding all these in, each time we add a new country, as well as these countries. If we go back up to the hotels, we also have a link to see all the available hotels. If want to scroll through all the ones which you have on the database rather than filtering down by the countries by using a Search. Service application will be a node-based application using the express framework which we'll learn about in this section and the forthcoming sections two. Will also be using various technologies to join this project, such as MongoDB to store our data. We use Mongoose for various things such as structuring our models or other data. Along with all this, will also have the facility for the user to go ahead and login. We can log in with an email and password. So let's listen now. Will also be using flush messages, just like you see here, to give the user some feedback about when a login or logout, along with the admin to be able to see when a hotel has been successfully added to the database. Once we login, we now have an account section which we can click on. We can also check out the current bookings which each user has available. Along with this, if the user is an admin, so let's go to '"/admin". Currently, the username and password which I've entered is down as an admin. So we now have access to this admin section of the website, which is going to be the back end where can have some administrator privileges, such as adding new hotels to the database, which we can do with this form here. The admin can also edit details of a hotel or completely remove them from the database too. All we need to do is, add the hotel's ID, or we can search by the hotel name, if we're not sure of the ID. Back to the admin, we can also view all of the available bookings which being placed by all users. Once we're logged in as a user and perform search, let's search for Jamaica, seven nights, and we can add a date, number of guests, the star rating, and also the price filters. We can click on "Search" and then we've taken it to the search results. So this is the hotel which matches our filters and we'll also have a section on the right-hand side which calculates the total per person and as well as the total cost of the booking. We can then continue through to the confirmation screen which provides the full description of the hotel along with the facility to place an order. Once it is placed on and taken to our counts and then we can see down at the bottom that our order has been added down at the bottom with a unique order reference. If you go to the admin, it should also be added inside here too because we're logged in as an admin too for this current user. We can also go to View bookings, and then see the bookings placed down at the bottom too. If we're to go ahead and log out and then try this admin section. We can see we're redirected back to the homepage because this route is protected. So during this project, we're going to be learning a variety of things. As I mentioned before, we'll be using node for the back end, express as the framework to build this project, Mongoose and MongoDB for our back-end data, route into navigate through our projects along with the MVC pattern which will allow us to add some structure to our project too. Along with this will learn so much more including authentication, how to keep users logged in using sessions, along with so much more, and we'll find out all about this in the upcoming sections. So we're going to kick off this project in the next video, where we'll take a look at node and MPM along with installing this on our system. 3. What is Node & NPM?: Welcome back. If we head over to nodejs.org, this is the official homepage of Node.js, which we'll be using to build this final project. We see at the top there's some information about what Node.js is. Basically, Node.js is a JavaScript Runtime, built on Chrome's V8 engine. What exactly does this mean? Well, V8 is engine which makes JavaScript work inside the Google's Chrome web browser. When we've been using JavaScript so far on this course, it's been running inside the browser. Chrome uses its own V8 engine, and also other browsers have the own version too. Historically, inside of the browser is where JavaScript is run, on the client side. However though, since Node.js was developed, we can also write JavaScript code, which runs on the server too. One of the key things about V8, is that it can also run anywhere. Not just inside of Chrome, making it available to work in other applications too, which is wrote in the C++ programming language. With this, Node.js was created using the V8 engine, which will allow our JavaScript code to be run on the server sign two. This was huge for a lot of developers who already knew JavaScript, as they can now write the front-end and also the back-end of applications using the same language. Before this, we would have to learn another server side language, such as PHP. Why do we want to run our code on the server? This is because it allows us to create dynamic web pages. This means, the web page is created on the server first, and can also include any dynamic data, pulled in from our database or other sources. Also, it can check if the user is logged in, for example, before sending back any sensitive information. If you've not already done so, make sure we click on the download button for the current version of Node and go ahead and follow the installation instructions. This on our system will allow us to run Node locally and create a web server on our own computer for development. When we're downloading Node.js, it will also include npm, which is the Node's package manager. This is the collection of thousands of packages which we can use with Node to build almost any type for project which we wants. Also on [inaudible] 2 , if we build something ourselves, which we think may be useful for somebody else. We can then bundle it into what's called a module and also publish our own module two on npm. As we go through this project, we'll be using npm modules to add functionality. Such as a module called passport. We search for passport, this is a Node module which we are going to be using to provide user authentication, so users can login with a email and password. We'll also use many more npm packages too, as a progress, to allow our passwords to be encrypted, to allow file uploads, for security and many more, which will discover soon. This is Node and npm and an overview of what they can do. We'll discover more about them as we go through this project too. If your Node download is now finished, go ahead and click through the installation steps to install on your computer. Then I will see you in the next video. 4. Static v dynamic web server: You may be thinking, why are we using a web server to build projects? Haven't we gone fine so far without one? Well, this is a fair points among which I'll try to explain in this video. In a general way, we can categorize our websites into either static or dynamic. On the screen here we have our shape matching game opened up in the index.html. In all of our previous projects so far, if we open up the index.html and also opening up inside the browser, we have our HTML content. This HTML is all static as the content does not change. Yes, we may have some shapes appear in when the game starts. This is all done in the browser by using JavaScript. Inside the browser, if we go to right click and view page source, this will open up in a new tab. This is the exact same code displayed here as we see over in Visual Studio in our HTML. Even if we uploaded this project to a web server and made it live on the web, all of this content is still static and we'll get back the same results from the server. Basically in a static project like this, the server will send back what we gave it, such as the index page. Dynamic web pages on t [inaudible] he rondo can come back from the server a lot different than the code we can see in our text editor. If we go over to the finished version of our troubled projects and also open the browser. So don't worry about [inaudible] , how all this looks. We'll learn about all this code during the next few sections. I'm going to go over to one of the hotel templates, which is inside views, and then if we go to hotel.pug, let's close it up. Again, don't worry about all this complicated code. For now though, I want you to concentrate on one thing. This is the hotel name, which is in a level three heading. The syntax might look a little confusing because of this shorter h3. But this just a h3 elements we've already learned about. After this is hotel.hotel_name. If we go over to the browser, we can see the hotel's actual name, such as Hotel 11 or Hotel nine, rather than this hotel.hotel name, which we'll see in Visual Studio. If we go to the browser, we can see the hotel's actual name is also available in the source. If we go to right click Inspect and then click on our hotel name, go to the elements and struck this down. Here we can see our outputted HTML which is returned back from the server. We have our h3, which we can also see here. Both is dynamic data has now been replaced with hotel name. Here we see that the web server this time is taken our hotel template from Visual Studio and filled in the missing data with data from our database before returning back towards in the browser. This is what dynamic web pages are all about. Static sites, just like the one we've seen before with the Shape matcher, a totally fine for simple applications. Even ones which still use API data too, such as our song finder. But dynamic science is perfect when we want to change data before sending it back to the browser. Or for security related tasks, such as handling sensitive information from the user. As we don't want it to be handled inside the browser. Hope it make sense. Next we're going to get up and running with our project using the Express framework. 5. Express.js and express generator: For this project, we're going to be taking advantage of a lightweight framework for Node called Express. Express is a really popular framework in the Node community, and it's the ideal platform for us to begin our project. Over in the homepage which is expressjs.com, we can see this homepage, as it says here, is a fast, and unopinionated, and minimalist framework for Node.js. This means it does not assume how our project will be. We are free to basically take advantage of what Express provides without having to adhere to a lot of strict rules, which a lot of other frameworks force upon us. It's minimalist, which means it provides the base features we'll almost certainly need, such as a web server, route end to switch between pages, error handling and templating, boost any extra functionality is up to boost the ads by using the node package manager, which we looked at before. Express provides a web server which we can use to serve our pages, and this also serves them to all browser with the dynamic content just like we looked at in the last video. Even installed in Express 2, is done as an npm module. As we see down here, we have the terminal code to set the server as a node module, so we can set things up manually, or Express also provides a generator. We have everything we need to get going. If we go to the menu and Getting started, hover over this and then we can click on the Express generator. We need to install this via npm, so I'm going to head over to the terminal to install. Windows users can open up the PowerShell program for the stage, or any other program which you may prefer. I'm going to open up iTerm and make us a little bit bigger. Before we continue, we need to make sure Node and npm is correctly installed. We can do this by typing inside of the terminal or inside a PowerShell. We can check Node is correctly installed by typing node -v. If we see a version number here, it means the Node is correctly installed. We can do the same with npm -v. Again, if we have a version number appearing, this means that node and npm is correctly installed. If you don't see the version number or you have an error, do make sure to go ahead and re-install Node, and make sure this is in place before moving on. We can then go ahead and install the Express generator using npm. So type in npm install exepress-generator, and then dash g at the end. Mac users may also need to add the sudo keyword before if you hit an error. Just before this, we need to add sudo and then "Enter", and this will then prompt us for the password, then hit "Enter". Now is, we'll go ahead and download the Express generator from npm. The dash g flag which we add at the end of here, will install this package globally. This means it can be used in any project, not just the one we are creating. Now we need to navigate to where we want to create our projects. I'm going to be adding mine to the desktop. At present, I am in my current user directory, so I'm going to use cd to change the directory to the Desktop. Hit "Enter" and now we can see we're inside of the desktop. Of course, you can change it to be any location which you prefer, I'm just keeping mine on the desktop for ease of access. Now to create a new project in this directory, we can run this command. So express followed by the name of our project, I'm going to call mine lets-travel, and then dash dash view is equal to pug, hit "Enter" and let us go ahead and create our projects, which is also using the pug templating language, which we'll cover soon. If we scroll up inside the terminal, we can see a list of files and folders which have been created for us, and also some instructions on how to get started. I'm going to be using Visual Studio's built-in terminal from now. I also recommend you do this too throughout this course. If you prefer, you can keep on going in a separate terminal, but you will need to go ahead and first change into the current directory for the project. Then you would need to run npm install to get all the dependencies, and then start the application with these commands down at the bottom. If you are following along in Visual Studio Code, we can now close down the terminal, the browser, open up Visual Studio Code, and then drag inside our project folder. We can open up Visual Studio as built-in terminal, by going up to View in a sub menu, and then go down to Integrated Terminal. This will then open up the terminal down at the bottom, listed are our terminal commands. This also has the benefit of having our directory automatically setup to the column project folder on the desktop. We don't need to navigate to where our folder is located. We're going to take a better look around all of these files and folders soon, but for now, if we open up the package.json and then close the sidebar, inside here we see some dependencies, which inside of this dependencies object just here, which are needed for this project. These dependencies are node modules which you can install using npm install. Down in the terminal, run npm install, hit "Enter" and then give, say a few moments to run through and pulling all the packages we need from npm. npm install will grab everything we need listed inside of this package.json, and then place them inside of our projects in a node modules folder. Also, when we add more modules later, again we will use this npm install command, but followed by the module name we want to install. Great. Once this is done, this should now be a node_modules folder. If we open up the sidebar, if we open this up, we just got a drop-down, we see listed everything which we're using for this project. It will have things such as a debug module. We also have express which is just here, and also pug, our templating engine amongst others which we'll also use. Now all that is left to do, is start up our web server and open it up inside the browser. Still inside this package.json file, up at the top we have something called start inside of our scripts. We can use start script inside the terminal, to then go ahead and kickstart our application so we can view it in the browser. Down inside the terminal, let's run npm start, hit "Enter" and then open up the web browser, which you want to use. Navigate to localhost, colon 3000, hit "Enter" and now we can see our basic Express up is now running. But how do we know it's port 3000 which node is running on? Well, if we go over to the package.json, the start command has a file path of bin, forward slash, www. If we open up this file inside the same bar, inside of this file is a variable which is set to port 3000. Here we have a variable called port, which is set to be port 3000. Also, if you happen to use port 3000 for anything else, you can also change this number to be something different, such as 3001. Its file structure and setup is a little different to what we've used so far. In the next video, we'll take a better look at what we have here in our Express Generator project. 6. Express project structure: The project structure which we have here can look a bit intimidating if you're used to using static websites. However, it's not too bad once you get used to it. If we open up our sidebar on the left-hand side, I'll make it a little bit bigger. From the top we have the bin folder, which is used for any startup scripts. We touched on this in the last video where we seen these start script inside of the package.json file, which then points to this www file, which contains our startup scripts. This file inside here sets the port number we want to use, and also goes ahead and sets up a HTTP server to then serve up our projects. Under this we have our node modules folder, just down here. This contains all of the packages or modules which our application needs. Each time we install a module from MPM, it will then appear inside of here and also be listed inside of the package.json file as a dependency tool. Since these modules also listed in the package.json file, we can even remove or delete this full node modules folder, and an MPM install command will then again, add this back to our project. This is useful for things such as storing our project on GitHub, as the node modules folder can often get really big and we don't want a huge folder like this saving to GitHub or elsewhere if we don't need to. Download this, if you're closing node modules, we also have a public folder. The public folder contains our static files, such as any images, any style sheets, and also any JavaScript files or libraries for the front end. Here we can add our project images, any custom third-party libraries or frameworks such as Bootstrap CSS and JavaScript files. This folder is not for any JavaScript files or the server, such as our page templates or anything with sensitive information, such as an E configuration files. Under the public folder, we then have our routes folder. Each folder will contain one or more JavaScript files, which handle what to do when a user visits a certain URL. As an example, if we open up this index.js, and I close the sidebar, you will see the router.get, which handles the homepage. Inside a router.get, we first see the route of forward slash, so when the user visits the home router or forward slash, these enrages a function which then goes ahead and renders the index templates, which we want you use. Then after this we have a objects where we'll pass the page title of simply express, and later on we'll also pass different information such as variables to our page template too. This moves on to the views folder if we open a sidebar and then open up our views, which is a view which the user sees. It contains all page templates which are created on the server before then sending back to us. All these files have the file extension of.pug. This is because we're using the pug templating engine, which also used to be known as J2. You may come across some j references in the documentation or one searching on the web. You can use other templating languages if you prefer, such as EJS. But this will be up to you to implement if you want to make this change. If we'll open up the index.pug template. This is a template being called from the router page we've seen before, so this is the index which rendered when a user visits his home route. Block and extends, which we see at the top of the file, we will look at this soon. But it's h1 and also p elements are what we see when we visit the homepage. We have the title and then the text of welcome to, and then the title. Inside of Chrome, if open this up, this is the text we see inside of here. H1 equals title, is the title which is passed from the router. Again in index.js, this is the title we see just after we declare which template we want to use. The text of express is then being passed to our index and that's why we see the text inside the browser. Below this we have a p elements with a text of welcome to and this will be express. We can also use this as a variable inside of a string. We'll cover all of these templates in syntax in the next section. Down after the views we have the app.js file. This app.js is the app's starting point and basically the main page which connects everything together. It loads up everything we need for the project and by default import any packages we need lope at the top from the node modules folder. It also import our routes from our routes folder, which we can see here, by these file paths, and then stores them inside of a variable we see as below. It then goes ahead and kicks off our new express app instance and assigns it to a variable called app. After this we set pug view engine, which is used here, which declares which templating language we wants to use. After this we have app.use on various lines. This is used to mount any middleware to our application. We'll look a middleware in more detail later. But basically middleware is a series of actions or functions which we can run our code through. An example could be when a user logs in, we could add some middleware to validate user's information before moving along to the next stage. But again we will look more into this when we are at our own middleware to the project. If we scroll down, next up we have our routes, which again is middleware and these are the two variables which we had before, which is just about the top. These are the variables which link to our file path for the router. It would declare one wants to use our index router when the user visits any of the home routes, and we also have a default user's route too which has been setup with Express Generator, and these routes are stored inside our index and uses.js files. Scrolling further down, we also have some error handling, which again is middleware. App.use without a file path, will make these error handling functions available for all routes in our site. Finally down at the bottom we have module.exports equals app. This will make this file available in other parts of our application if needed. Back to our sidebar, the last files are the package.json files. Inside of our package.json, which we've briefly looked up. We have the information about our project, we have our startup scripts to run our web server. We can also add our own scripts here too, as a shortcut to type in out this longer command in the terminal. We also have the name which we set and also the version number which we can set too. Further down, we have the dependencies which we looked at before. These are the node modules, mid file projects and we can also add dev dependencies too, which is the modules we need for development only, and these will be ignored for production. Soon we'll be installing in the node mom package, which will be a dev dependency so I'll show you how to do that soon. If we open up the sidebar, we also have a package.json. For example, inside of our package.json, we have the Express dependency, which is just here. This says currently at the time of creating this app expresses our version 4.16.0. The tilda icon you see just at the beginning here, means we won't express version four, but we also want any minor update of versions two. Ie we can take 4.17 or 4.18 and so on. With this in mind, if we go over to this package-lock.json. And then if we do a search for Express, but then taken to the Express section of this file, we see the actual version is locked in at 4.16.3. Also, this module itself has dependencies too. If we close down this terminal and then scroll down you see we have this required section just here and express also requires a lot of different modules too, such as cookie, debug, escape HTML and also lots more. This is why when we go over to our node modules folder and open this up, there is lot more folders listed here or Lamar modules than we originally seen if we just go to the package.js. Let's close it down. All of our dependencies inside this package.js also has dependencies too and these are listed in the package-lock.json. This is an overview of what is included in the project to begin with, I know we've said it quite a few times already, but really don't get overwhelmed by all of this if it's new to you. We'll become a lot more familiar with the setup of the next few sections. 7. Using Nodemon: We are now going to install a node package, which will save us a lot of time during this project. If we go over the views inside the menu and then go to index.js, views, index.js, and then you can go ahead and make a small change to our text inside here. If we say, welcome to, and then say, let's travel. Give a save and then open the browser and then reload. We see this change has been reflected inside the browser. This is fine, and this is the result which we would expect. If now go over to a script file, such as inside the routes and then go to the index.js. Let's now make a change inside of here. The comma is out, it's res.render,/. Remember this is the line which renders our homepage or our index templates, and then instead if we go to the line below, say res.send and then the text off 'hello'. This will simply send a string of texts to the browser. Give a save and then reload and see that nothing happens. This is because if we make changes to a script file, we need to restart the server. We can do this if we go over to the terminal remember this is view, and then integrate the terminal, we can close the terminal downwards, Control C, and then we're taken back to our directory, and then again use npm start, to begin the server once more. Hit Enter, then once it's running, we can go to the browser and Hit Reload, and now the terminal has restarted the server. We'll now see the text of 'hello' has now been updated in the browser. Although this works fine, it's a bit of a pain to keep restarting the server, every time we make a change inside those files. To make things easier, we can use a package called nodemon. If we go over to nodemon.io, this is the homepage for the nodemon package, which we're going to be using. Nodemon will watch for any changes in our source code and then automatically restart the server for us. We can even install nodemon, as it suggests, using this npm install command, the name of nodemon for the package and we may also use this -g flag when installing the express generator, and it means we can use it globally in any project and not just the one we are currently working on, or alternatively, if we just want to use it in our single projects. This is simple to setup too. We can head over to the terminal in Visual Studio Code and then close down a terminal again with Control C and then run the following command against our npm install, and then this time we want to say --save-dev and in the name of our package, which is nodemon, Hit Enter and it will go ahead and grab the package from npm, save dev we'll save this in our project as a development dependency. Meaning we can use it during development, but is not required when we push the app to production. Give them moment to install and then once this is done, if we go over to the sidebar and open up the package.json. Inside of here we still have our dependencies, which we've seen earlier but further down we also have our devDependencies and they're listed as our nodemon package. Now for this to work in our app, we can create a script, just like the startup script, which we have at the top here. This one I'm going to call devstart. Add a comma after the first line, and then we can add devstart. This is the alias which we're going to give to this command. Add a colon, and then inside the quotations, we're going to add a command which is nodemon and then the same path which we have used here./bin/www. This is going to essentially run the same startup scripts but this time we're watching for any changes using nodemon. Give that a save and now we can go ahead and start our servers. This time if we go over to the terminal, make sure the server is closed down and then this time can run npm, run devstart. Of course devstart is the name of our script which we have just here. Hit enter, once it is up and running, you should see the green line of code just here and then over to the browser, hit reload and now everything should still be working. If we again go over to the index.js file and then make a change. Let's say 'hello again'. Save and as soon as we hit save, we can see the terminal at the server has restarted. Then reload the browser and now we'll see our text has been updated without us having to manually update the server. Let's now reinstate our res.render, so we can remove the res.send and then command and forward slash to now uncomment out this index page, save this, and then reload and refreshing the browser will now show these changes without having to close down the server and restart. 8. Serving static files: For this project, I have provided some images which you can also use, such as images for the hotels, the countries, and also the logo. You can of course choose your own if you prefer. The ones provided are inside this folder called images, which I have here saved onto the desktop. If you open up this folder, we can see we have the beach, which is one of the main images on the homepage. We have our logo and then our country's images and hotels organized in two folders. Let's also open up the project folder. Double-click on Let's Travel and then inside here, we can go to public, and then to images. Then if we select the four items from our images folder, and then drag these over to the images folder inside of our projects, so this is over and make sure these are inside of the images folder, rather than just the public section. We should be able now to see these images, if we go over to Visual Studio code. Open this up and then the sidebar and then inside of a public, we now have the images inside of images folder. If we go over to the index.pug, which is the main homepage templates, we can test this out by adding a image. Underneath our text of Welcome to Let's travel. We can add our image, we can add some attributes inside the quotations to set the image to use equal to our images which is the folder. Then let's go ahead and add beach.jpeg, which is this one just here. Note we don't need to add the public folder to our file path and then save this, open up Google Chrome or your browser, reloads and that's our image of the beach, great. Now all of our images and also our project structure is now in place. In the next section, we're going to dive deeper into our project by looking at routing and templating. 9. Introduction to Pug: We have already talked about how we will use templates to create our projects. These templates will be a combination of HTML, JavaScript along with any dynamic data mixed in, such as a hotel name, which we looked at in the last section. We know that we can't do all of this with the standard HTML files. So we need to use a templating language which compiles all of this into HTML. I'll be using a templating language called Pug to do this. It may look a little strange to begin with, but it's actually simpler than normal HTML tags. To see how to use Pug, let's head over to our index.pug file. There was a sidebar to a give small space, and we've already had a quick look here with the p elements and also with an [inaudible] image. We have extends and block at the top, which we'll come back to soon. For now let's concentrate on the features of pug. Generally, using Pug is just the HTML opening tag to make for the shorter syntax, just like this p element with the text of a text-based elements work in a similar way, such as add in a heading. So let's add a h1, let's say title, over to the browser, and then reload and we have a level one heading down here. Attributes are added just like with normal HTML tags. But instead with Pug they add it inside brackets. If we wanted to add a link and then at the href, we do this inside of the brackets, and then the rest is just added as normal. So let's add a link to Google. So www.google.com, we can also add our classes. So let's add a class of button, and then afterwards we add our text outside the brackets, which you want to add for the link. So link to Google text. Save this and then reload and now have our hyperlink at the bottom, and if you click on this, it will work just like normal HTML a tag. Back over to our project and the index.pug. The indentation is also really important when using Pug. In normal HTML, indentation is only really for readability. But when using Pug, it's necessary to use it to show what level each element is on. For example, if we added a div to contain this title on the link, just like this, and then if we go to the browser, and then go into developer tools would right-click and inspect, and then select this div just here. So this is a div which we just added, and the developer tool shows that the div title and also our hyperlink are all on separate lines. They effectively all at the same level, we don't have the title and the link inside of this div tags. But if we go ahead and indent the h1 and the link, and then refresh this. We now see that the div opening tag and closing tag now surrounds our title and link. So the indentation causes these two elements now to be nested inside of the parent div. Another thing about indentation inside of a pug file is only mixins, which we'll cover later, and also this block declaration at the top, and extends can be at the top level i.e. on the far left of the file. If we move over a nav element, so our link for example if we move this over to the left of the file, save this and then reload the browser. We now get a error saying only named blocks and mixins can appear at the top level of a template; This is basically because this file will be used inside of a NAV file. So this indentation keeps everything right when the HTML is compiled. Let's go ahead and reinstate this link, and clear the error. Something you may have noticed is above, we also use a equals for this title. This is because we can also include JavaScript in these Pug files too. If you remember, the title was passed from our router, which was index.js, just here inside of this title. So this is JavaScript being passed to our template in the index.pug. Therefore, we need to use the equals rather than just a plain text element, just like this and also our p elements just here. This title is also displayed in the browser sub too about the top here. Use an equals will also render to the screen the result of any JavaScript. So instead, if we say rather than title, add some JavaScript of 5 plus 12 over to the browser, we have the results of 17. But instead if we go ahead and remove the equals, you got to save and then back to the browser. This now displays as a text string of 5 plus 12 rather than outputting the sum of 5 plus 12. So let's reinstate this back to title. So you don't have to remember this but I'll put in the result like this is called buffered code. It is also unbuffered code too which does not directly add to the output; This can be any normal JavaScript with a dash prefix. So for example, we can add a dash and then add any JavaScript such as a constant of name, and it's our name to be Chris, and then this can be used where we want to place it. So h1, we can place our title with our variable of name. Since it's a JavaScript we'll also need to add the equals and test this out, and then down at the bottom there's our variable name of Chris. So this unbuffered code, it's just basically declaring line of JavaScript, and then we can go ahead and use it anywhere we want inside the templates. This JavaScript can be pretty much anything. So we could have an array of foods, cheese, eggs, and chicken, and now we have this array. It gives us a chance to take a look at the special syntax which Pug provides for creating a for loop. To do this, I'm going to add this at the bottom, indent this the same level as the link, and then create a unordered list for our foods. Indented one more level we're going to create a loop with each food in foods. So foods is the name of our array which is just here, and then each individual item in the array is going to be stored inside this food variable. So after here we can set our list item to be equal to food. Again this is JavaScript, so we need to add the equals symbol. So we don't output this as a string. Say this, and then test this out. We now have cheese, eggs, and chicken at the bottom. This output can also be mixed with an eText too. So rather than just the outputted individual food, we can add a string of I love, and then add plus food. Actually about a space just after there and try this out, and our text is also now mixed with our JavaScript variable; This is just a overview of what Pug can do, and it really is simple enough once you get used to it, we will use a lot of Pug features for this course. However, if you prefer to take a deeper look now, you can head over to Pugjs.org and take a deeper look, at the top of this file we also have this extends and also this block content section. We have not yet discussed what this means yet, but we'll go ahead and cover this in the next video. 10. Template inheritance: We have both block and extends keywords, inside the pug files at the top just here. If we open up our layout to pug file, which is available in the view section, click on layout the pug. This layout file has no extends keyword at the top. This is because it acts as the main pug templates. The files will then extend this main layout. This is why we can open up our index the pug and also our error the pug as well, which is available in the same folder, and then see the extends layout at the top. If we go back to the layout the pug file. There is also a block contents section here down at the bottom. This is what it sounds like. It's basically a block of code. Any of the files such as our index the pug can go ahead and replace this section called content. Inside of our index the pug file, we'll open this up. All this section here, basically everything from our unordered list all the way up to our title, will replaced inside of the block or inside the space which we specify inside the layout. We can also have multiple blocks too, each with a different name, such as footer or a sidebar block. These can also be added to another file, and then referenced by the block name, and the same way as his content section. We freeze, then add anything else around this block. For example, above the contents and we can add some text. Above the contents, and then below it, below the content, and now if we go to the main index page, and then reload, we see at the very top we have the text of above the contents. and then at the bottom we have the text of below the contents, and then everything in the middle, right through from the title down to all unordered list isn't provided by this block content section, which is an overridden by the contents of our index the pug. Once you understand that, we can now create sections of our code inside of a layout, and then we can outsource the contents to a separate file, skip all code, more organized, more maintainable, and we can also reuse these sections of content too in multiple files. Now let's go to the layouts, and delete these two p elements which we created, and then give that save. This layout is useful for anything we want to display in all of our pages on our site, such as adding a header and footer. We can then replace the main content down here or a new sections by adding more blocks. Now we know how our templates are laid out. Next, you will get the chance to get some practice by creating the header section. 11. Time to practice: Creating the header: When dealing with anything new, just like Prog , we really began to get better when we practice on our own. Without just following along. Here we can see the final version of the projects, which I would like you to go ahead and create this header section from the top navigation, which includes the logo and also the links at the top, right down to the main beach image just here. If you feel confident, you can also add the search form two, which is in the middle. Just as a guide for where you're going. In this, we'll need to go inside of auto-layout dot Prog file, inside of the body section. So just above this block content. So it's at the very top of the page. I'll be going over all of this in the next video. So don't worry about messing up. It's all good practice. So I would recommend you pause the video now on this final version and then it give this a go. 12. Solution: Creating the header: I hope you managed to give that a go and hopefully have some header content. Now on the screen, I'm going to go ahead and create my version of this header. If yours is different to mine, you can either change it to be the same as ones created in this video or keep yours as you would like. Either way is fine. I would maybe recommend though keeping the same class names as we use in this video so the CSS matches up later. Let's begin over any layout docktype file. In between the body section and the block content. I'm going to begin by creating the header section just like we would normally do with HTML. Nested inside within this nav element. This logo can be a link. This is so the user can click on it and then be taken back to the index page. Our a for our link, which can include the href inside of the brackets which simply links to forward slash, which is the homepage. Then one level in from our link. If we go ahead and add our image, this will then be clickable and also link to this homepage which is forward slash. Inside of the brackets we add our source, so SRC and the sequence be forward slash images. This is logo.png. We can add a class or an ID to our element. By adding this inside the brackets as a attributes or we can add it just after the element name. Add image and the harsh and logo. This will give the ID of logo for this image. Then just after this we can go ahead and create our another list which is going to be for our sign up and login links. This needs to be at the same level as our surrounding link above, so ul followed by our list items. If we want to make these links, we need to indent the a tag plus the href. We don't have these templates or these routes setup just yet but we can still go ahead and link these to sign up. With a text of sign up to and then do the same below add our next list item at the same level as the one above. Turn this into a link. This time this one is going to be for login, which is the routes of forward slash login and the text of login to. If you've created this and you've not added the href in, I would recommend you keep yours consistent with mine so it has no problems further down the line. I added forward slash login and also forward slash sign-up. That give us save name over to the browser. There's a logo and then our two links at the top too. The next thing to do is to create our form input for our search. Which is where we can type in the destination, the duration, the departure dates and also the number of guests that we want to search for, so we do this just with a simple HTML form. This form is going to be in a surrounding div. This div needs to be on the same level as our nav element. Come down for the nav element and then begin this at the same level. When creating a div with the class, we can even create the element just like this and then add the class name as a attribute or instead we can have a shorthand which is simply dot and the name of our class. If we wanted a div with the class of search nav, we would just do it simply like this. This will then be outputted as a div with this class. Then inside we can nest our form. This form is going to be made up of a series of form input and each one is going to have a surrounding div of input underscore wrapper. This will make each input block level, so they appear on their own line. Then we need to label for our first one which is going to be destination. We add the for attribute or destination and then a text of destination. Then we can add our input, the type of text, the idea of destination which will match this label just here. The name of destination too. I will just change the style so it's a little bit more readable and then the required attribute on the very end. Save this and then let's see how it's looking in the browser and now we have our destination form input. Now this is working, we can go ahead and copy this input_wrapper and then paste this in and make sure this is at the same level as above. This one is going to be for the duration. Change the label to duration, the text and then we can add nights inside here because we're going to be sign the duration per night. The input type of text is fine, the ID needs to match alteration and the name of duration too. This field is also required so we can leave this in too. The next one is going to be for the departure date so the label text. This time the input is going to have the type of date so it drops down as a date picker. The ID of departure date too and then the name, date of departure. This is going to be CamelCase. This field is also required just like the others. I'll do this the same one more time this one is going to be a number field. The input type of number because this is going to be for the number of guests, so number-guests. The name of number of guests and then the ID which must match this label of number guests. I have a typo though so change that. Then finally the name, again in CamelCase of number of guests. Let's check this out in the browser. Great, that's our four inputs. We can see if we click on the date, we now have a drop-down date picker. It should be a input type number which is on our two text fields at the top. Back to our layout, after these first four input we're now going to change this up. We need a couple more and one is going to be for the star rating. This is going to be a select input with different options through from one to five. We are then going to have an input with a select again, which is going to be for sorting the price from low to high or high to low. Then finally the Submit button at the end is going to use the same input wrapper, so.input_wrapper. This is a select with a name equal to stars. Remember from earlier the select input do need to have an option to select. Add our first option inside here with a value to then pass to the server once selected. It's just going to be simply a number for the number stars and the text of min one star. We can go ahead and copy this in and paste in four more times. The second one is for two-star, 3, 4 and 5 and also the same for the text too. The last input, again these ones have the same input_wrapper so we keep the styling consistent. This will also be a select and this is for the price sorting from low to high or high to low. We can add the name of the select to be sort. Paste in the option with a value of one. This is going to for the price set from low to high. We're also going to paste in the same but this time option can have a value of negative one. This is because these are the values which you required when searching Mongo database to then sort the return queries from high to low or low to high. We'll see this in more detail later on. This can be also change. This time let's see price from high to low. The last input also needs the input wrapper and this is the Submit button. Button with the type of submit and then the text of search.That should lead us now to form. Let's check for any errors. The star rating from one through to five. We have the price from low to high and high to low. Then I will submit button at the bottom. We also want this beach image be part of the header too. Inside this header section, just after the form, we need to make sure this image is indented at the same level as our navigation. If we scroll up and then go to our search nav and keep an eye on this line which we see in the text editor. Now we could start our image, so img. The source just as before, is going to be equal to forward slash images which is inside the public folder, the beach d.JPEG. Then let's bring up the block contents. Save and then reload the browser. Now, we have the image inside the header. We also have some cleanup work to do just below and this is only consent from the index.pugfile. Go over to index.pug. Then we can remove our examples from earlier. We can move out another list, our links and array. We don't need the image. We don't need the text or the title. Let's just leave in place the extends layouts and the block contents and off to the browser. Now, we just have the header content from our layout file. There we go. There is our header content now in place. Next we'll move on looking at using mix-ins, which are a great way to reuse the same code in multiple templates. 13. Mixins: One of the things we usually want to avoid when coding is repetition. If we reuse the same code more than once, it often makes sense to do things a little differently. Thankfully, Vue gives us the opportunity to use what is called mixins. If we look at the finished version here. Take our hotels here on the home page, for example. The same hotel structure which you see just here. Also the layout is used if we perform a search tool. Here we have our listed hotels which follow a same pattern. If you do a search and filling all the fields just on here, hit search. Where you see our search results follow a similar layout and pattern as our hotels on the home page. This is a good use case for a mixins even though the hotel data is different, such as the description and also the title, we can make parts of the mixins dynamic. It's really flexible to use. Over in the index dot pug file inside of Visual Studio Code, let's begin by adding the hotel info we need to begin. Starting with the wrappers and then link to all hotels. Just have block content, make sure you have this intended. Then we can add our outer div. Outer underscore wrapper. Inside here we also want to have a second wrapper for each individual hotel. Hotel underscore wrapper. Then the h2 of hotels. This level two heading is also going to have a link. Just after this we are going to add our link, which is going to link to all hotels which are available. Add a href, which is going to link to forward slash all. Then in brackets a text of "see all" you're going to save this and then go to the browser in the home page and then refresh. Down at the bottom we have our title of hotels and then we'll have a link which we'll wire it up later to see all the available hotels in the database. The reason we have this link to see all hotels, is because the hotels which will display on the home page are only going to be restricted to nine random hotels pulled in from the database. This is so the home page doesn't get too crowded when we have lots of hotels inside of our database. Now go ahead and add a dummy hotel. You can see how this is looking. After our links and at the same level as our h2, we can add a hotel wrapper, so dot hotel nest. Inside here we're going to have a couple of different sections. The first one is going to be for the hotel image. Hotel img. This is going to be the section which is going to appear on the left hand side and it's going to have a image of the hotel which we'll then link to the full hotel description. We need a link with the href. We can leave this empty for now because this data is going to be dynamic and it's going to link to the current hotel which we're viewing. After here we're going to add a image which is the main hotel image and we could just add a dummy image now. Forward slash images forward slash hotels. Then we can select any hotel we want from our public folder. Let's drop hotels down and you can choose any one of these images from there. I'm just going to go for hotel one dot JPEG, and just like this link above, this will also be dynamic too and the information will be pulled in from the database and then we can grab the correct image. After this hotel image section, let's add a new section surrounded by a div called hotel underscore info. This is going to contain information about the hotel, such as the hotel name, the star rating, the country, and also the price per night. The hotel name is also going to be a link just like this image, which will also link to the full hotel view, which will show a extended description. Add our surrounding link with an empty href for now. Our title of the hotel is going to go in a h3 element. We can add some dummy text of hotel one. A horizontal rule then separates the title from the rest of the information. Now it's just a case of adding some p elements. The first one is for the star rating. We can set it to be anything we want for now. Let's go for four. The country: Jamaica. Then finally the cost per night. Remember this is just some dummy data so we can see the structure. Then let's see how this is looking. There's our image section above, and then our hotel info with the name, star rating, the country, and also the price. Great. We now have a hotel on the Home page. We also need to create a view to link to you when the user clicks on this all hotels link. Let's go over to Visual Studio, open up the sidebar, and then inside the views we can create our new view called all underscore hotels dot pug. Inside of this template we also need to extend layout. We also need to add block contents. Now as you going to share a similar view to the hotel from the Home page. If we go over to the index dot pug and it will copy all the way from the cost per night right up to the hotel. This is the individual hotel div. Go to all hotels and then we can add our wrapper. So dot hotel underscore wrapper, indent it in one level and then we can paste in the code from the last video. Make sure this is just indented in one level and make sure our all hotels dot pug file is saved. If we go over to our home page, we now won't be able to see the view down at the very bottom. It is because we have not yet set up the routing to handle this forward slash all. But you can already see that we've repeated the same hotel code, both inside the all hotels template and also inside of the index dot pug. Now's our opportunity to reduce our code by moving this hotel into a mixin inside of the views folder, inside the sidebar. Let's create a new folder called mixins. Inside our mixins folder, I'm going to create a new file which is called underscore hotel dot pug and this is going to be the file for our mixin. I know we'd like to start a mixin name with a underscore but this is totally up to you. We begin by using the mixin keyword followed by a name we want to give to this mixin. Mixin hotel then we can go and copy over the hotel code. We already have in our index dot pug. We have this hotel all the way down to our star rating and cost per night. Copy this. Then if we go to our mixin which is underscore hotel. Paste this in and make sure this is indented correctly. One level layer, and then one further level for our image and info. Save this file and that's all we need to do to create our mixin. Now, index dot pug file, we then need to include this mixin file, which we just created. After extends layout. We can also include our mixin by adding the file path. Mixins, which is the folder name, forward slash underscore hotel. We don't need to add the dot pug extension. Then we need to remove the hotel code and then replace it with the name we gave the mixin. Cut or delete this hotel section from the very bottom and then we add our mixin with plus hotel. This hotel name is the name we gave to the mixin inside the file. Underscore hotel dot pug. This is a name which you set right at the top. If we now save this and then over to the index page by clicking on the logo and I scroll down, you can see we have a problem with the indentations. Let's go and check this out and this is an index dot pug, over to our index dot pug, and it looks as though this is not quite lined up with this line. These little small errors are things we need to watch out for with the indentation. Make sure everything works correctly. Let's try reloading this. There's our hotel back in the home page. But this time pulled in from a mixin. Now we can do the same with the all hotels page inside the all hotels dot pug file. We can also include the mixin in the same way as the index. After our extends declaration, we can include our mixin, which again is the file path of mixins, forward slash underscore hotel. Now we can replace this hotel code from dot hotel right down to the cost per night. Then replace this with the mixin using plus hotel. Now we've replaced a section of code from two files and added it into one mixin. We will come back to mixin soon by also passing in data to them about each hotel in the database. Along with also creating more mixins to you, as we go. Our code is now a little shorter now by including this and it will be used a few more times in this project too. Next, we're going to move on to routing and how we can use it to switch between pages in our application. 14. Basic routing: If we go over to Visual Studio Code, and at the moment, if you go inside of the routes folder, and then click on the index.js, we only have one route currently setup, and this is for the homepage. Now we're going to look at how to add more routes too and if routing will allow us to handle what happens when a URL is visited. First, I'm not going to be using the users.js file, which has been included with the express generator. So we can go down and delete users.js, so we can this delete this from our project. Then inside of the app.js, click on the main file here. We also have two references to this user's file, which we can also delete. First of all, we can remove this variable, which points to the user's routes. So delete this, leaving just our main index file. Then a little bit further down, we'll have a app.use which sets we want to use this user's router on the user's file path just here we. So we can also remove this. Now back over to our router index.js file. Let's close down some of these tabs. At the top of this file we have two variables. We have an Express variable and also a route variable here. We have these so we can use the Router functionality which comes with Express. First of all, we require Express, which is a node package and this is inside of the node modules folder. If we require any packages from inside of the node modules, which is just here, we just need to reference it by the module name. If we are requiring any of the file which is not inside the node modules folder, we will need to add the full file path before the name. After setting our Express variable, we then set to open Express router instance, and store it in a router variable. This router variable is also used down here, and also any future routes too. We then use.get here because we are handling a get request. Remember when a user visits any page in the browser, this is a get request. In the last video we added a link to forward slash all. We added this over in our index.pug template, just here. This was to provide a link to all hotels. But we've not handled the route just yet. We go over to index page and select this link. We see we have taken it to forward slash all, but down at the bottom we have a message of Not_Found. We see all the header content just a little still because this content has been added to main layout file. So now we can go ahead and write our own route to handle the forward slash all hotels routes. So back in the index.js, where we're going to be handling all of our routes, we can start just like above with router and this is a get request so we use.get. Inside here, we want this to apply to the forward slash all routes, and other function as the second parameter. So function which takes in the request, and also the response objects. These two variable names can be anything which you prefer. Then open up the curly braces and add a semicolon at the end. Request is an object containing all the information from the HTTP request. As an example, we'll use this soon to access data from within a form, which is passed along with the request. Response, on the other hand, is what we want to send back when we get a request. So request is the data coming into the server, and then response is a response from the server. If you take a look above out-of-home routes, We have res.render a page template as a response from the server. We also looked at res.send earlier too. Here we can also render our all hotels template which we created just here. So inside of router.gets/all we can say, res.render, pass in our templates of all_hotels. Then as an object, we can pass in our title of all hotels. The semicolon at the end here. Now we can test this by going over to the browser, hit "Save", and then refresh. Make sure you only foward/all routes and then scroll down to the bottom. Now we can see this hotel, which we added as a mix in in the last video. Let's also test this once more by going over to the homepage, by clicking on the "Logo", clicking on "See All", and once again we can see this is still working. So now we have two routes in place. One for all hotels and one for the homepage. This is a basic introduction to handling routes with Express. In the next video we'll look at passing data for the URL, when we covert routes parameters. 15. Route parameters: One of the things we have to deal with when routing is that we don't always know what the exact URL will be. What I mean is if we imagine a user's route, each user has a unique user ID. This could be something such as our localhost or our website URL, forward slash users. Then forward slash a username, which could be pretty much anything. This user section that we have just here, probably won't be known in advance to the developer. This section is something which we need to handle beforehand. For this, we can use route parameters to create a dynamic segments in the URL. If we go over to the index.js, which handles all of our routes, let's start by duplicating our forward slash all routes in the last video. Copy this section and then add it in just below. We can then tell express router which parts of the URL we want to be dynamic. After forward slash all, we can then go ahead and add forward slash and then create a dynamic segments using a colon. Then a name we want to give to this section. This name can be anything of our choosing. Then inside of our function just below, we can then access the name data from our URL. We use the request object. Remember we said that this holds information from the HTTP requests. First of all, we can access the request objects, then.params to access the data in the URL parameters, followed by this name variable were added after the colon. So request.params.name. Then if we saw this inside of a constance, so const name is equal to our parameters. This data can also be passed to the templates to use along with the page title. After the title of all hotels, add a comma. Then we can also pass in this name data. This name data is passed to the all hotels templates along with this name. So click on our all hotels.pug file. Then this variable can easily be accessed in the template just by referencing the name. Down at the bottom of the file, p equals our name variable. Then over to the browser. Now if we go to forward slash users and then forward slash, we can add any name into here, hit enter. In fact, this was all an increase and hit enter. Down at the bottom we now see I would name of Chris, which we passed in. We can try this again with anything we want to add. This data is then grabbed from our URL, stored inside the request.params objects. Then we can pass is now down to our template to use in any way which we choose. We can also add as many dynamic segments as we need in the URL. Rather than just having one in index.js, just like this. We can also add this dynamic segment into any section we wanted. We could also grab the age and store it in an age variable. But this all depends on what type of website you are creating. Another thing we can also do if we don't want to grab the data inside of the routes, we can also just add a star. Just like this, we could add a star and then this route, just here, all this function will then run every time a route follows this forward slash all, and then forward slash any data after this. This star can be placed in any section of the URL which you want. This will be useful for handling our user names, even if we didn't want to grab the actual data and store it in a variable. I'm now going to remove this code from the video. Inside of all routes, let's remove the router.get section, as we don't need this for this project. Then all hotels.pug, all we need to remove is p equals name, and restore this box how it was. But we'll come back to route parameters quite a bit later on in this project, where we'll be passing in any hotel IDs along with booking information. 16. MVC Pattern: We're going to be structuring this project using what is known as the MVC pattern. MVC stands for Model View Controller and it's basically a way of separating our logic into different parts. At the top of the diagram here we see the model, the model defines how our data should be structured. As an example, our hotel information will have a model and this model will stay at that each hotel needs to have a name. It's name must be present, and also a string which no longer referred to coat Islam. Also our hotel model must have a description, an image, a price, and so on. Next up and probably the most easy to grasp is the view. The view, which as it sounds is basically the user interface. We've already touched on this in the section where we've created a page templates so this should be fairly straightforward. Then there is the controller. This controller can update the view or send data to the model. A typical use for a controller in our project will be to search our hotel model for matches based on a country, then it's data can then be passed to the template or to the view. We've actually already done something similar in the last video, where we looked at route parameters. Instead of the routes index or js file, we use a controller to get the name from the URL, then we passed this name to the view to show on the homepage. We'll also be using the controller to do other things too, such as form validation when a user signs up before we push this data to the users model. This is a pattern which will be following for the rest of these projects. It's keeping nicely structured and organized. It may seem a little confusing to begin but we will get lots of practice and it will soon become clear. In the next video, we're going to be starting this separation process by creating our controllers. 17. Using controllers: At the moment we are handling overall logic inside of this routers index.js file. We navigate into a certain route and then all the logic is handled inside of this function and also this one which is below. This works fine for small applications, but we will soon outgrow this type of setup. I'm going to separate this logic inside and create a controllers folder in the root of all projects. Let's go over to the sidebar and create a new folder called controllers. Make sure this is at the same level as all level folders, such as the bin and the node modules. Inside here we can add a new JavaScript file for each controller which you want to create. Let's click on controllers and then create a new file. I'm going to create separate controller for the hotel related logic. Then one later on for the users to keep things organized. Let's begin by creating hotel controller.js. Controller with a capital C and then hit "Enter." This file will be a series of functions and we'll basically be outsourcing this function section from our router. We're going to take this logic, put it into our controller, and then it references inside of our router. Let's begin in our hotel controller.js and begin with A exports. This will allow this code to be available in other parts of our application. We then give this exported function a name of our choice. Try to keep it descriptive though so we know what each one will be doing. Let's call this the homepage, and then set this to a function. This is a function which takes in the request and response objects. Let's add these in, so we have full access to them inside of our function. Then if we go over to our index.js, we can then cut out the res.render from our home routes and then add it to our controller and now would also be a good time to change the page title. Let's set this to "Let's travel." We now have our logic separated, so we can now go over to our routers index.js file. We can remove this function leaving in just the initial routes and then we need to reference our host cell controller.homepage. Let's add hotel controller.homepage and then give that a save. If we now go over to the browser and then hit "Reload," and go to the homepage, we now see a message saying the site can't be reached. If we go to Visual Studio and then open up the terminal, we can see that the app has crushed. This is because we need to require this hotel controller file before we can access it. Currently, we're trying to access the hotel controller, but we've not yet imported this file. To do this, let's go to the top of our file and then we can add a comment. So require controllers and then set up a constant, so const hotel controller, which matches this name just here and then we can require the file. We need to add the file path because this is not inside of the node modules folder. This is inside of the controllers folder. So controllers, forward slash hotel controller and now hit "Save." We should now see the app has reloaded. We now have the green text. Over to the browser, and the app is now working in once more. Then we can do the same with the all hotels route too. First, let's go over to the hotel controller and create this. So just like before, we can say exports.listallhotels. Except the E function which takes in the request, the response and then over to a router. We can take the res.render from these, forward slash all. Paste this in, and then references function inside of our router. So remove the function from before. Again, we want the hotel controller file. But this time we want list all hotels. Now, let's try this router on the browser. So the home route forward slash all, scroll down and this still works to. So at the moment we've not gained a lot by having separate controllers. But these controllers will soon become more complex. Especially when we start dealing with databases and obtain the views, along with checking any user data for validation. It makes sense to start separating things from the start, so things don't get too messy as our project grows. 18. Using middleware: Middleware is a really important concept to learn, and it is used quite heavily when building Express apps. While we will be using middleware for his projects, I just wanted to give you a quick introduction first, so we at least understand the basics. If we go over to Visual Studio then open up our hotel controller, we have the request and response objects for each router. Request is the data coming in and response is the data which is returned from the server. We can use middleware in-between to basically change our data or do something with it. Basically, a middleware acts like a series of functions which we pass through. An example of its use in our project, will be when a user signs up. Inside this hotelController.js file, I want to show you a quick example and these examples are just for demonstration purposes. You don't need to follow along if you don't want. Let's make some more space and I'm going to create two more functions. Exports, sign-up, passing in the request and response objects. The sign-up section is going to handle the data validation. This will validate any user info as it comes in then this second one is going to be the functionality to login. Exports.login, passing your request and response and this is going to handle the login. Let's say we want to have the functionality to first sign up the user. The sign-up section also validates the user details then follows up by login, the user in. This is usually the functionality we want. When we sign up for new websites, we often want to be immediately logged in. All of the code to handle both of these sections could be done inside of one single controller. But for this case, it makes sense to break things up into separate actions. This is because not only do we want to sign up and then login straight away, we also want the functionality for this login to be separate. Just when a user has returned and then just wants to login. Let's avoid repeating the same login code more than once. How does Express know we want to run the sign-up function then followed by the login? First of all, we need to pass in a third argument to our function. We usually call this variable next, with their needs call next inside of our function body, when we are ready to move on to the next piece of middleware, so we call next inside here. When we want it to move down the chain onto the next piece of middleware. There is still one more thing to do. Although we call next inside this function, it doesn't automatically know what the next piece of middleware is. All that we know we want to move on to login, Express doesn't know this by default. We do this by declaring the order of middleware inside the router file over to the router index.js. We can then set up a new example routes, we've router.gets. Let's create a sign-up routes with the forward slash and then we can add our controllers. The hotelController.sign-Up. If you just wanted to use this sign-up section, we would just use a like this. We can add more than one. We can then follow up with hotelController.login, and we can pass in as many of these as you want to use and then these executed in sequence, each one requiring the next call inside the function. First of all, we will use the sign-up function, then next we'll pass it over to the login function and since these are now separate functions, this makes sense when we want to create a route just for login into. If we have, router.gets, when we get to this stage, we also want a login routes and then we can reuse hotelController.login. Now we're using the same login functionality without repeating the same code in multiple functions. We can see this is working by adding some console logs to all middleware over to the controller, just before next we can do a console log, and then a simple message of sign-up middleware, lowercase c, then copy this then add this into our login. Changes to be login middleware, save our files and and over to the projects. We need to go to our up routes, which we set just here. Forward slash sign-up, at this end then hit enter. Now only sign-up routes over to the console and make some more space. We now see inside the console at the bottom we have sign-up middleware called first, which you'd expect because this is called first and the controller then we have the login middleware just afterwards. This means that the router is now passing through both pieces of our middleware in the correct sequence. If we go ahead though, and comments sound is next function, save the file then reload the browser on the sign-up routes. Over in a terminal we now see that only the sign-up middleware has run. The code has got to this section just here then it hasn't been passed to the next piece of middleware because we haven't called next. This is a basic introduction to how middleware works. I'm going to remove these two functions as we don't need these in our projects. They just for demonstration and also the two new routes to set-up in the index.js and then check this working okay. Head to the home routes and we're now back to normal. We can load these routes in later on when we come back to this part of the app. Finally, we can also set a middleware to use across the whole site, rather than just one specific route over in the app.js, which is the main file. Click on this then scroll down to the section with app.use, which is just here. Here you can see app.use, and this is where we can set up any middleware such as cookie parser to use for all routes. Below we can see we have the index router setup here too. Both for this and all of the middleware, we can first add a route as the first argument to restrict the middleware to only apply to this particular routes. There is also many of the uses for middleware too, such as third party plugins and we will look at these more throughout this project. 19. Important Update: mLab now part of Mongo: As we progress through the following project, we use a hosted database on a service called mLab. MLab is a fully managed Cloud database service which we use to host our Mongo database. As we can see on the homepage here, mLab has since being acquired by Mongo itself. So we now need to use this service in its place. The service is called Mongo Atlas and it's a pretty straightforward swap since we just set up a database in a similar way and then use the connection string provided in our projects. Mongo Atlas is also free to sign up for and it has a free tier for development too. So let's start by going over to mongodb.com/cloud/atlas. If you've used Atlas before and already have an account, you can go ahead and login. If not, you'll need to register first before we can create our first database cluster. So if you need to go ahead and sign up, but I'm going to go down and login to Atlas now. Then once you're all setup and registered, we need to go ahead and create a new cluster. Create a new cluster may pop up as part of the registration process. So let's go ahead and build a new cluster which is going to allow us to select our region or our plan. There is some pre-configured options and you can leave the defaults as they are or change to your closest region. So I'm going to select the closest regions me. Also keep an eye out for the free tier label, which isn't in each one. Everything else, I'm going to keep us default. Just make sure you see the cost down at the bottom to be free. Then we can go ahead and create our cluster by clicking on the green button. A new cluster can take a few minutes to get set up. So I'm going to go away now and come back as soon as this is all done. So this is my cluster all now setup and the next step is to create a new user. If we go to the security tab and then go to add new user, this user is going to be for ourselves. So we can select the atlas Admin, which is one of the options on the privileges. You can of course add more users with different permissions at a later date if you need to. Then add a username and password of your choice. I'm going to add a username and a password and then go ahead and add our user. The next step is to add our own computers' IP address to Mongo's whitelist. This is a security feature so only our machine is granted permission to access our cluster. You may need to bear this in mind at a later stage when deploying the application to other services. So let's go on to the Security tab and click on 'IP whitelist'. Add IP address. We get a pop-up and we can confirm that we want to use our current IP address by clicking this button here. Then we'll get the IP address added and this field follows. So we can just go ahead and confirm. You may need to give this a few moments to get setup if you see this pending spinner just here. If you've not used Mongo Atlas before, we can check the contents of our database by clicking on the collections button. The collections button is in the overview tab and then collections. This gives us access to all of the collections which our database has and we can interact with our data. Add new fields, add new collections and see all the information which is stored in our database. Of course, we don't have any data just yet, but this is where you can access all of our database information, such as any hotels and users, which we'll go ahead and save from our project. Finally, we need a connection string. If we go to overview and then click on 'Connect'. The option we want to use is connect your application. There is also options here to use MongoDB Compass and also connect with the Mongo Shell. Both connect your application is the one we need for now. We also need to change the driver version to be version two. Then we see our connection string is displayed just here and we can also copy this to the clipboard. This connection string is the one which we'll use in our project in place of the one provided by mLab. This is done for this update. Just keep this open in the browser and you can use it in the next video when we connect to our database. Also just bear in mind as you go through the course, you will need to go through these Mongo Atlas surveys to see your data rather than mLab as I occasionally do in the class. All you need to do to see this is click on the collections button us we looked at before. 20. Getting started with Mongo: In this project, we're going to be dealing with quite a bit of information. We'll have information about how hotels we have and uses any orders which you placed and also any session data which we'll get into later. Of course, so we need somewhere to store all of this data, and I'm going to be using a MongoDB database, in this course, which is really popular database for Node applications, along with many of this too. MongoDB allows us to store our data in a JSON-like format. This makes it really easy to work with, especially when we used to JavaScript type applications. We've already worked with JSON data, so this should be fairly familiar. It also makes learning things easier too. There's also lots of helpful queries which it makes available. The query is a search on our database, and Mongo makes this really easy. We have lots of different ways we can perform searches to only get the exact data we need. For example, one of the queries which we'll be using is to search the database using a search term which they use Enter and then also filtered out by the star rating and availability, and then finally sought the results in price order. We'll also look at lots of queries too unit section. MongoDB is also free and open source too. I will also be using a hosted version in this course, which is also free. The hosted version is going to be over mLab, which you can find our mLab.com. This hosted solution is also known as a database, as a service. It basically allows us to quickly get going with MongoDB. Our database is then hosted in the cloud photos. You can also set Mongo up locally, we have in our database already hosted is really useful for later when we push our application to be live server. It also saves the configuration. The first thing we need to do is sign up for a user accounts, so if you don't already have an account with mLab, I would suggest you go ahead and pause the video and then sign-up now. I already have an account with mLab, so I'm going to go ahead and login, so add in the login details. Once we're logged in, we can now go ahead and create a new MongoDB deployments. Go to the top, and click create new, then we have some options to select, I'll be using Amazon for the provider, so click on this, and then the free sandbox plan, which is fine for development and learning. Select this and select a region. Amazon is hosted in multiple locations across the world, we only have a few options for is sandbox plan, so AWS will be fine. We can continue, and we can select one of these. Then continue again, and then we can add our database name. I'm going to call mine, let's-travel. Continue. We can review any of this and then hit Submit Order, and there we go that's our let's-travel database on our setup. Our database is empty, so it doesn't have any collections. Just gets, if we click on this, we can then take a look inside. Under the Collection Tab we see we don't have any at this time, and the collection is just a way of grouping our documents, which we store, as an example, we have a hotel's collection to store our hotel records, a user's collection, to store assigned abuses and so on. The top, we also have a URI which we can use in our project to connect to this database. There is a space in this URI for our user and also a password, so we need to go ahead and set this up under the user's tab. Click on this and then go to Add database user. We can add a username and password, so I'm going to just call mine travel as username, and traveled on as the password. Create our user, great. Now have the username and password to fill in these blanks. But first there is one more thing which needs setup, and this is mongoose. js. We are free to use Mongo directly if you want, but I'm going to be using a nose package called Mongoose instead. Mongoose basically allows us to give our data some structure in which is called a schema. If we write directly to Mongo, you can make a mistake pretty easily. If we do not set up how our data should be, Mongoose will allow us to set how our data would look. For example, will have a hotel schema, and this will have fields such as a name and description. We can now answer the datatype, each field should be, such as a string, and also restrict the minimum and maximum characters it should be, and also if the field is to be required and so on. Basically it stops us from doing things such as entry and a text string into a price field, which should be a number. This package will also allow us to create our model, which is the model we talked about when we looked at the MVC pattern, given our data some consistency. Let's go ahead and install Mongoose in our application. Let's close the terminal down with Control C. Then type in npm i mongoose. Notice this time using the shorter i command, this is just a shorthand for install and if works fine. Hit "Enter" give it some moment to pull-in from mpm. I'm checking whether this is all okay by opening up our package.json, and in the dependencies will now see we have Mongoose listed here. Over a in our app.js, we can now set up our connection. Again in the sidebar we can open up app.js. Then close this, so the first thing we need to do is to setup our connection. We need to first require the Mongoose package, which we just imported. Just after our import, I'm going to use a constant, and it doesn't matter if you use a constant or a variable, but I'm going to use the constants from now on, so const Mongoose equals require Mongoose, and remember if we're requiring a package from the node modules folder, we just simply reference it by the package name rather than adding a file path which leads to it. Then we can set up our connection using the connect method, so that's first access Mongoose. Scroll down on the app.set. Let's setup our Mongoose connection, so Mongoose variable.connect and then open up the brackets. Inside of connect, we can pass in our connection URI from mLab,so back out to mLab, copy the full URI, and as a string, open the quotations and then paste this in. Rather, we need to change our username and password, so remove the user and our username was travel and the password was travel on. Of course, when dealing with databases, you want a more secure password, but this is just for demonstration. Also have NSURI in here is not the best way to do this, but we'll move this to somewhere more suitable later. On the next line on the Mongoose. connect, we need to set Mongoose. Promise, P, this is going to be equal to the global.Promise, P again. Once we start to query our database, we need to deal with the information which is returned back to us. In earlier versions of Mongoose, we used a callback based setup, but now we can make use of promises which are lot simpler and easier to maintain. We can set Mongo to use the Promise library such as blueband, if we wanted to, which we can get as an NPM module, or I'm going to set it to be the global. Promise you have here, which allows us to make use of the native Promises available in ES6 rather than installing another node module. Next, under this, we can check for any connection errors. We first check, we have a Mongoose connection, and then once we do, we can call.on,.on is a node method which adds an event listener. In our case, we want to list now for any errors, so compositing error as the first parameter, and then as a second argument, passing a callback function to display this error. Let's create a function where we're passing error, which is going to output any error messages to the web console. We do this wave console.error, and can passing this error.message. Pass our message to the console, so let's give this a safe and a semicolon at the ends and then over to the browser or to our index and then reload, and in fact we need to restart our terminal after install Mongoose, so let's go to the terminal and then run npm run devstart, wave it to kick in and then reload the browser and check everything it still works okay. If you don't see any error messages inside of Visual Studio's terminal this should be all now setup. If you have an error do check for any typos and also check that your database URI matches the one on mLab along with the correct user and password, and once this is working and you're stage, you will now good to move on to creating our Mongoose model. 21. Mongoose models: We've already talked a little about what models, we are going to using a Mongoose sets up our models, and this will keep our data structured, so there is less chance of messing up. These models are responsible for creating data before sending off to the database along with written documents from the database too. Over in our project, we can begin by creating a models folder to keep our code organized. Open up the sidebar and then the root of the project, create New Folder called Models. Now we have models and our views, and our controllers folders and this is the MVC pattern we talked about earlier. This model we're creating is going to be for our hotels. This will have the structure for our hotel name, hotel description, star rating, and so on. Inside its models folder, create a New File, call it hotel.js. Since we use mongoose for our schema, we need to require the mongoose module. Let's close on these files down and concentrates on hotel.js. Inside here we create our constant of mongoose and require the mongoose package, semicolon and then we can create our hotel schema, so const hotelSchema, and this is equal to a new mongoose.Schema with a capital S. The Schema will map or match to the data inside of our database, therefore, what we aren't in here will shape how our database data will be constructed. The schema takes in an object inside the brackets, where we can begin to construct how each hotel would look. We need a hotel name, so let's add our first phoneme of hotel_name. Now we can set this up as an object, we want the hotel name to be of type. This is going to be a string separated by commas. We can also add some more restrictions to this data, we can also set if this is to be required, this can be a boolean value of true or false. If the field must be present or instead, we can simply add a string with a message if this field is missing, such as hotel name is required. I come on to the end. Then we can set the maximum number of characters to be 32. Then finally, we're going to set the trim to be a boolean value of true. We'll remove any wide spaces from the field from the beginning and end, leaving just the characters which answers. This is the schema for our hotel name, and we can go ahead and add a similar setup for our description. Separated by a comma, we can ask the hotel_description. The description again should be type of string required. Again, we can set this to be true or instead we can pass in a string which will be returned if the field is missing, so hotel description is required. We can also trim any wide space, set this to be true. Now we have the hotel name and the description, separate this with a comma, we now have a field for the image. The image is going to be a name, so it's going to be a string for now, we will come back to this image later on in the course because it's one or two things we need to deal with to get this working correctly. Next up we have the star rating, the star rating is going to be a type of number. We also want this to be required like all the rest of the fields. We can say hotel star rating is required, add a common onto the ends. Then we set the maximum value to be five, because we only want the star rating to between one and five. After the star rating, it's the country, the country is a type of string. This is also required, the text of country is required, the comma after required. We also want to finish, so this is a boolean value of true. That's all we need at the moment for our country. After the country, we want to set the cost per night. Cost per night is going to be the type of number, as this will be a price, and also want this to be required. With a string of cost per night, is required. The last piece of information we want to store in our hotel model is available. This is so the unmanned concise if this Hotel is currently available for sale and this will be a boolean value of true or false. Let's set the type to be boolean and the only other field we need is required, so availability is required. Once you've gone ahead and typed all this out, right at the very bottom. The final thing we want to do is export our model so we can use it in other files. Down at the bottom must create a comment of export model. We do this with module dot exports, answer this to mongoose.model, the first volume we want to add is hotel. Hotel is a name I'm going to give to this model and separated by a comma, we also pass in the hotel schema, which we just created. Good, this is now how our hotel would be constructed. Now we've setup our model. It means nobody could just go ahead and add any fields how they like. We now have a strict set of rules which each hotel must abide by. Later we'll add another model for our user too and also for any orders. We can also shape how they will look too. For now though, we're going to stick with the hotels. The next video is all about using this model to create our add new hotel phone, so we can adds new hotels to our database. 22. Creating our hotel upload form: Before we can push new hotels to the database, we need to create a HTML form, so we can add the details we want to enter. This formal parts of our admin section. So let's add this admin route first over in the index.js. Open the sidebar, into the routes, and then index.js. I'm going to go down to the bottom of our router just for the export. Let's make a comment, and I will say "ADMIN Routes". The first one we're going to use is router.get, since this is a GET request. We want this to be for the forward slash admin routes. Then we want to run our hotelController, I'm going to call it call it the adminPage, semicolon at the end. As we can see with the red area down at the bottom, we don't yet have this adminPage in the control yet, so this should be next. Open the sidebar and go to our hotelController.js file, and then we can add this right at the bottom. Exports towards adminPage, it's going to be equal to our function, which takes in the request and response objects. Then inside the function body, what we're going to do is a res.render, this is going to render an admin template, and then take in an options object where we will pass in the title like we've done previously. The title can simply be Admin, and then add a semicolon at the end. Now for the admin.book file to display this. Let's go and create this admin template, open up the sidebar, into our views folder, create a new file called admin with the dot pug extension. This admin route is going to be fairly simple. At the moment all we're going to do is pass in the title and then create a unordered list. This is going to have some links for the admin to use, such as the links to our new hotel, to edit or remove hotels, and to see any bookings which has been made. Let's extend our layout. Extends layout at the very top, and then replace the content block. Indent it one level we can pass in our h2, which is the title. Then want to separate this title with the links with the horizontal line. These three links are going to be an unordered list. The first list item, nested inside we can add a a for a link with the href equal to forward slash admin, and then forward slash add. This is going to be the route which is going to handle the add in new hotels to the database. The texts of Add new hotel. Then we'll do this two more times. Our second list item is also a link. This href is going to go to forward slash admin and then forward slash edit dash remove. The text of Edit forward slash Remove Hotel. We'll come back to this one later on when we look at editing and removing hotels. The third one again is going to be for later too and this is going to be a link which is going to link to a route which is forward slash admin forward slash orders. The text of View bookings and give that a save. You can test if it's working by going over to the browser and then checking out the forward slash admin routes, and then hit and enter. If we scroll down, we have our title of Admin, which is passed to the templates and then our three links which we just created. If we go ahead and click on "Add new hotel" at the top, we're taken to forward slash admin forward slash add, which was set up just here. This results in an error down at the bottom because we also need to set up this route too, along with a page template. Back over to our router file, which is index.js. Let's set this up with router.get. This router was forward slash admin, forward slash add, to add a new hotel, and then setup our hotelController, and the function name of createHotelGet with a semicolon at the end. You may be wondering why we've called this createHotelGet, rather than simply create hotel. I've added Get onto the end because this is a GET request. Later will also be creating a POST request to this create hotel route. It makes it more clear when we get to that stage. This is now our route. We can now move on to the controller to render our view. Let's click on "hotelController.js" down at the bottom. Let's set this up. It was exports.createHotelGet sets up our function with the request and response objects. This is going to simply render a view. We do this with res.render, just like we did with the adminPage. The template we're going to create is going to be add underscore hotel, and then pass in the objects, which sends the title of Add new hotel and a semicolon at the end. Just like we this admin two we've not yet created this add hotel page. Go to the sidebar, go to the views, and create a new file, called add underscore hotel with the dot plug extension. Now it's a case of making this a form, which is going to be used to submit the hotel to our database. This needs to extend our layout, select all of the files, and then block content. Just before we get to adding our form, I'm going to add a link at the top of the page. This link is going to link back to the admin section, so we can quickly switch between the add new hotel and then go back to our three main links. The link with the href equals forward slash admin. This is going to be a button. We can add a button type. So type equals button. Then we'll also add a class which we are going to be using later when we add some CSS or button underscore small. The text goes back to admin as this is where this is linking to. Then at the very bottom we pass in our page title. To keep this consistent we'll add this in a h2. So h2 equals title. Give this a save and check if it's working. Refresh forward slash admin, forward slash add. Underneath the layer so we can now see our button of back to admin, click on this and then we're taken back to our three links. We can now go back to add new hotel. We need create our form now which is going to have all the fields we need for our hotel. These fields need so much of the data inside our model. Let's go ahead and create our form underneath the h2. The form and then the attributes inside the brackets, the action. This is going to link to the same page, so we can keep the routes with an empty string. The method, this is going to be a post request. Then indent it in one level. I'm going to create a div which is going to have the class of form underscore input. Each one of these form groups is going to have the same class. We can keep the styling consistent when we get to the CSS later. The first one will be labeled and this is going to be for hotel name. So hotel underscore name, and then the text of Hotel name. After the label will then add our input. This input is going to have the type of text, the name of hotel_name. Like I mentioned before, these fields need to match the data in our model. If we go over to our hotel.js and we'll begin right at the top with hotel name. This needs much name, which we gave this in our schema. Hotel_name. Then we'll do the same for description and also for the rest of the fields inside here. Back to our form. The name of hotel name and this field is also required. The next one is going to be for the description. The surrounding div of form input, the label. This one is going to be for hotel description. Then it's x-naught hotel description. This time rather than an input, this is going to be a text area. We do this input, just like the rest of the elements. We can add the name of texts area, and then we add the brackets or the attributes. The name of hotel_description. The ID, which is also hotel_description and let's make this smaller so it all fits on one line with the text area. You can also set the default number of columns and also rows. So I'm going to set the columns to be 13 and also the rows to be ten. This is also required too, like all the rest of the fields. Below this thing,next one is going to be for the hotel image. So I'm going to go ahead and add the wrapper which is form inputs, the label for the image, the textile photo image. This time it's going to be an input for the file. So the inputs with the type of file, since we'll be using uploaded images from the user machine. So the type of file, the name is going to be image along with the ID. Let's go ahead and copy this hotel name. Then after the image paces in, this one is going to be for the star rating. So the label will have the name of star_rating and this will be a star rating of one to five. Star rating for the name is input type is going to be of number. To restrict this from one to five with the name of star_rating. This is also required to. Let's Keep this between one and five. We can also add the min attributes of one and also the maximum attributes of five. Go to under the star rating, we can add this in again, make sure the indentation is correct. This one after the star rating is going to be for the country. So the name of country, the same for the text. The input type is also going to be text too. So we can name this the name of country and also let's give this an ID of country too. This is also required too. The same again after the country. This one is going to be for the cost per night. So the label is going to be for cost_per_night. Text of cost per night to, the inputs is going to be for price. So we can set this to be a number. The name can also match this, so we can copy this and paste this in for the inputs. So we have the type, the name, and we also need the ID of cost per night too. So add this in and the next one after this, if we go right down to the very bottom, is going to be for the availability. So we're going to add some radio buttons. Which we can select if the hotel is available or unavailable. So the wrapper of form inputs is going to have two radio buttons. The first one can have a label and this is for available, the text is available too. Then our input, which is the type of radio. After the type we can add the ID and this one is going to be the same. This also needs a name. This is the time of available. This is the data which we sent to the server. The value is going to be equal to true and we'll set the next one to be equal to false. So if this one is checked, we'll get the available equal to true, and the next one will be available equal to false. By default, we want this true to be checked. So we can also add the checked attribute inside there. Then we just need to do the same for unavailable so we can copy these two lines and then add them below. This is unavailable as is the text and then the input. We can add on, save the name, the value of false. We can also remove this checked attribute because we only want one checked at once. So now the last thing we need to do is a button which is going to go ahead and submit this form. This can have the same form input wrapper. Skip the styling consistent. This time this is a button with the type of submit, the class, the class we've already used before of button_small. This will keep the CSS more consistent and then in capital we're also going to add the button text of Confirm. We can now save this and then go over to our admin. Make sure we're on forward/admin,forward /ads. Now we should see the add new hotel form down at the bottom. If you've seen your form with no errors, congratulations. If you do see any errors, make sure you check over your code for any typos. Before moving on to the next video, we will finally get a hotel push to our database 23. Pushing to the database: We all now set to get to work pushing the hotel data to our Mongo database. In the last video, we created a template called Art_hotel. This form is setup to make a post request. If you go to the top, we can see the method is set to post. This will post our form data so we can go ahead and use it in our controller. Also, the action is set to an empty string, which we can see just here. This will post the form data to the current routes, which is forward/admin, forward/add. If we go over to our routes and enter the index.js, we already have a get request on this forward/add route just here to display our at new hotel form. So let's duplicate this line to create a post request. So copy this and paste this below. We need this to be a post request as we're dealing with a post request from our form. So router.post, again we can keep this one as forward/admin, forward/add because this is the file path which we're going to be posting to, since we've not set our y's in our action. So since this is a post request, we can change create hotel post, and this create hotel post middle-ware will handle what to do when we make a post request to this route, i.e. when we submit the form. Let's set this up in the hotel controller.js under createHotelGet. We can do the same for createHotelPost. So createHotelPost sets up our function with the request and response. The first thing I'm going to do inside here is to see what data we're working with. We can see what data is being sent by the form by using res.json, so I'll put the data as JSON, then pass in the request a body, and this is where the data is stored in our quest objects. So inside of our function at res.json and the form data is stored in the body of the request objects so pass in request.body gives us a save and then over to the browser, get that reload. Now we can fill in some form data to submit. That's just adding a test. That's a test data, choose an image, into our Travel project, and then the public folder, images, and we can choose any hotel image. So I'm going to select Hotel 1, a star rating of three, country, Portugal and any price is fine. We confirm, so as soon as we hit Confirm, we then make a post request from this form. This post request is going to forward/Admin, forward/add. We set this up inside of our index.js to handle this post request to this route. This is then triggering our hotel controller, which is then returning our JSON since we are doing res.json and then passed in the request.body, which stores the data being sent by the form. So now we can see the JSON version of our hotel which we just added. We can see this data is setup in the same format as our model. This gives us a better idea of the data we're now working with. This form has been set up to be the same as our model so the data is in the correct format. Now we know we have an object for our hotel stored in request.body. Will we use this data in our model to push to the database? So we need to require our hotel model first, the top level file. So back to the hotel controller, and at the very top, we can set up a constant called Hotel with capital H, and this will require the models. So as a string when it's passing the file path, so let's go up to our model's folder, and then the name of the model was Hotel. We can then use this Hotel model down in createHotelPost. So we're going to set up a new Hotel, pass in the data from request.body, which we've seen is the object which contains all the fields from our form. They install is inside of a variable or a constant. So const hotel equals our new Hotel. So now we have our hotel and we can go ahead and call safe. But one thing first, I'm going to mark this function as async. Just after the equals, we can mark this function as an async function. This is something which is new in ES 2017 called async await. It really does make our lives a lot easier when working with asynchronous code. What it basically allows us to do is to pause a function until a line of code has finished running. First of all, we mark the function async, just like we did there, and then the next task our function has, is to call save to say this to our database. We do this with our hotel constant and then call.save. With the save, however, we want to make sure the hotel has finished saving before we can start doing things with it. To do this, we can add a wait before our hotel.save, adding a wait before this line. We'll make sure this code pauses and then wait for this to finish before moving on to the next line. The reason why we want to make sure we await the hotel saving before moving on is because we will assume new this hotel data immediately after the save. So we want to make sure that the save has completed, it's available before calling any more lines of code which need this hotel data. So if we give this to save and then over to the browser, gives this a reload and resubmit the form, and then go back over to mLab and login to database. So let's add in our user details. Once our database loads up, we can now see on Java collections we have the hotel collection, which now has one documents. If we click on next to expand, we're then taken to our test, which is the data which we just submitted. This is a big step because we've now saved our hotel to the database. But what if there is an error when saving the hotel? We need to add something inside of our controller to handle any errors. First, we can wrap the code inside the try block. So back to createHotelPost, we can add try and then move these two lines inside of this try block. This will try to run the code inside and test for any errors. If there are any errors, we can handle them with a catch statements. We do this at the end, we catch, we pass in the error, and then inside here we call next, which also takes in the error. Calling next, I'm passing in the era, will pass the error along the middle-ware chain until it reaches an error handler which can deal with it correctly. Remember, we already have error handlers setup with the express framework inside of our app.js, which is down at the bottom here. So back to our controller for this next to work correctly, we also need to pass in next after the request and response objects. So passing next here since we're now using it inside of our function. If we head over to mLab, inside the browser, we can look at our hotel. If we click on this corner and then drag this down. If we notice, inside of this hotel which we just added, there's been a unique ID added with the field of underscore ID, which is just here. Remember from before, we said we wanted to use await to wait on the hotel saving this database before moving on. Making sure the hotel has successfully saved means we now have this ID available before move on to the next line of code. This only because I now want to redirect to the hotel once it's been saved. We can do this inside of our controller with res.redirect. Then passing the file path we want to go to, I'm going to use the back ticks since we're going to add some dynamic data. So forward/all, and then forward/. We can pass in the $ symbol and our curly braces. This is something we looked at early on in the JavaScript section. So inside here we can pass in a variable. So we can access our hotel object, which is just here, and then the field which is underscore ID, and this is the idea which had been added inside of our database just here. Add a semicolon at the end. Now let's check this is working okay by adding a new hotel. So let's go to forward/Admin forward/add, reload the page. Let's say test 2. Test 2 for the description, any image is five here. Then click Confirm. We're now redirected to our route, which we set just here, which will be foward/all, and then the hotel ID. We can now see this in the URL bar at the top. We have our unique ID, which is now pulled in from the database because we waited on this hotel to be created first before moving on to the redirect. If we scroll down, we see an error of Not Found. This is fine because we know we have not created this route yet, but the main thing is we have this unique ID now any in the URL. We'll come back to this later when we create a template to display the full hotel detail. This is a big step forward now, we saved into the database. So congratulations, if you now have this working. If you don't, make sure to check over your code and take a look at the finished code provided or ask in the Q&A sections before moving on to the next video. 24. Querying the database: Before we look at how to get our data from the database or from a query, we first need to add some more data to get back. If you go over to mLab and if you have any this test data coming in place, we can remove it with the bin icon on the right-hand side. I want to clear all of the records in our database and make sure they're all gone. Let's go ahead and create five new hotels to work with. We can do this if we go to admin, so vote/admin/vote/add and then go down to [inaudible] at the bottom. The first one I want to call this Hotel 1 and of course with a more creative name if you prefer. I'm going to grab some [inaudible] Ipsum texts to add for the description. Let's go down and create two paragraphs. It generates, Copy the sample text and Paste it in to our text area. The hotel image for Hotel 1 then select this. The star rating can be four, country Jamaica. Cost per night, now we can leave this as available. Now we redirect it to the hotel. We need to go back to our admin/add. Create Hotel 2. Paste in the description the image for Hotel 2. Then a star rating will go for five, country of Dominican Republic. Costs per night, add something there and confirm. It should be two hotels now in our database if we hit Reload, and there we are. Let's add three more. Again, /admin/adds. We can add hotel number three, adds the description hotel3.jpg. A star rating we go for three this time and Netherlands. Cost per night, say 45 and then confirm. Then we can add Hotel 4, admin adds. Then down to the bottom Hotel 4 Paste in the description the image. The star rating will go for five this time and the country of the Maldives. Cost per night, let's go for 89. Let me some how make this unavailable. It looks like we had a little issue there actually, we have both of these checked. Let's go to our form, add hotel and down to the check boxes or the radio buttons. Sorry. These needs have the same name, them too much in the same group, let's try reload in. Yet now we can just select one of these. Let's go over to the database. Now, we have all these available as true. I'm just going to go into any of these and click on the edit button. We'll set the availability this time to be false. It's Save and go back. Because now I have hotel number three to be set to false. Let's add one more which is Hotel 5. The description Hotel 5 image. The star rating let go for two this time. The country of Greece, cost per night and we can keep this one as available. Now, over in mLab we should now have five records with one of these being unavailable, which are said to be Hotel number three. We'll add the rest of the hotel's later on. But now we have some data to work with. I'm going to show you how to get it into our application inside of the hotelController.js. Let's select this and then we can go back to our list all hotels function. If we scroll up, we have the list all hotels just here. Returning all the data in our database is fairly easy using Mongos find method. Before we render all hotels, let's create a constant called all hotels and I'm going to set this to be await because we want this data to be pulled in before rendering template. We want to select our hotel model and then use the dot find method and a semicolon at the end. The find method will find all documents in our hotel collection and also search the hotel collection because we're using the hotel model just here. Here since we're using await once again, we also need to mark this function as a sync for it to work. Add sync just before our function parameters, we also want to handle any errors again two so we can wrap this code in a try block. Let's cut all these two lines of code, add a try block, paste this back-in, followed by a catch block to handle any errors. This catch block also takes in the errors as an argument and then we can also pass these on to next. Since we now call next, we also need to pass this into the function. Our next as the third arguments and before moving on we should check this is working. We can comment out this res.render that we have above and instead replace it with a res.json. This will add the data to the screen in JSON format. The data want to output is all hotels, which is this constant just here. So save this. Then we need to go over to the browser, and then go to /all hit, "Enter" and now we see all of our hotels in JSON format. This is all the data which we now pull in from the database. This looks like all of our Hotel is being returned. We can see all of our fields including the generated ID. Now, we know this is working we can then pass this data to our page template to go ahead and render. Back over to the controller. Let's comment out the res.json and uncomment out this render method. Along with rendering it, the all hotels templates and passing along the title, we also want to pass in this hotel data of all hotels. Separated by a comma, we can also pass in all hotels and this will now be available to use in the templates. If you give this a save and then go over to the all hotels templates, which is in views. Let's open this up. Let's test this working by selecting p elements and send this to the value of all hotels. Give that a save. Then over to the browser, we can reload the /all routes. Okay and scroll down. We see one giant object on the screen now. This is all the data which is now pulled in from the database. We can see if we look closely, we have hotel one, and then if we go further across, we have hotel two just here, and then hotel three further down. This is all the information from our hotels collection. We can also filter this down if we just want the first hotel, for example. We could select it by the index number. All hotels, the index number of zero, reload. That's all the data from our first hotel. Even further, we can narrow this down to the hotel name. Remember, hotel name is stored in hotel underscore name, so we can access it using the dot notation, so hotel name. There we go. There's our hotel one name. Now we have access to all this hotel data. We need to live through all hotels and display each one in this hotel mix-in. We already have the hotel mix-in just here. Once you create a loop which displays this mix-in with all the hotel information. Delete this p element from here. We can add our level two heading, which is the title. Then after this, we want to create our loop, and we'll do this with each hotel in all hotels, and then indent both these lines in. All hotels is the data which will be passed to the template with all the information from hotel one through to five. Each individual hotel will be stored in this hotel variable. Now if we save this and then reload the forward slash all routes and then scroll down, we see we have hotel number one. If we keep going down, we should have hotel one for each one of the items in our database. This is now repeated the same hotel in our mix-in for each item. This is a step in the right direction because we now have five items on the screen, but we want each hotel to be different. To do this, we need a way of passing the unique hotel data into the mix-in. Remember we said, before that this hotel variable here holds the individual hotel information, so this is the information which we need to pass to the mix-in. We can do this with our mix-in just here and pass in the hotel. This works because mix-ins are compiled to functions which can take in arguments. If we save this and then go over to our hotel data in our mix-in, down to mix-ins then underscore hotel up to our mix-in name at the top. We can also receive this hotel data, so passing hotel as an argument, and now we have the individual hotel data inside of this mix-in. This is where the good part begins to happen. Let's begin by displaying the hotel name. Scroll down to our level three heading. Here we have some hard-coded text because this is a variable we add to the equals, access the hotel, and then dot hotel underscore name. If we save this and then reload the browser, back up to the top, we have hotel one, hotel two, hotel three, four, and five. Now we see all the hotel names are unique. We can now carry on with the rest of the details making them all dynamic. Next, we can add the data from the two links. The href just up here, let's change this to be back ticks because this will be dynamic. This is going to link to the full hotel view, which is going to be our forward slash all. Then we can add our dynamic section, which is hotel._id. We'll deal with this route later on. We'll also do the same for the link below. Copy this and paste it in for the second link. Having these two links means both the image and also the hotel name will link to the full view of the hotel when the user clicks on either of these. Then we can deal with the file path for the image. At the moment, we just have the image hotel one hard-coded inside here. Let's change this to be back ticks forward slash images, the hotel's folder inside the images, and then forward slash we can open up the curly braces and then add hotel dot image. Inside of our database for the image, these images are saved. If we take a look, for example, image here is saved as hotel2.jpg. If we go over to Visual Studio and then into public and then images inside of the hotels, this name will match the name of the images which we'll have in here. Now if we save this and then reload the browser, we should now see the unique image for each hotel. We'll come back to the images later because we're going to be using Cloud Storage for image uploads rather than storing in our own project. Now let's head back over and finish off the rest of this dynamic data. The p elements are the bottom, but also now going to be dynamic. We need to surround this in back ticks, change the star. Rather than having the hard-coded value of four, we can again pass in our dynamic data. Hotel and then the field name, which is star underscore rating. The same for our country. We can surround this in back ticks, replace the hard-coded country with hotel dot country. The cost per night. First of all, we can add a currency symbol and then a space to create our dynamic data. Hotel.cost_per_night. Let's head over to the browser and see how this looks. Refresh our all hotels routes and check these all difference. We have four, Jamaica, and 67. Then we have the Dominican, Netherlands, and also the Maldives with different star ratings and prices too. Excellent. You should now be seeing all of your hotel data from the database. You may be also wondering where we have the hotel description, well we'll add this back in later because this is only to be displayed on the full hotel detail view where we have more available space. There is one little problem here though. The problem being we can also see hotel three. If we scroll down to hotel three just here, remember we set this hotel three to be unavailable when we first created it. This is pretty easy to resolve. All we need to do rather than just using the find method, we can also pass in a query. Back over to the hotel controller and to list all hotels. Inside of this find method we have here, we can begin by passing in a object, and then we can select the available fields from our database. Now we only want to find hotels which has this field set to true. We can do this with the $ symbol eq and set this to true. $ sign eq is a MongoDB query operator which checks for equality. Basically, only hotels with the field of available will then be returned. Now if we save this and then reload, now hotel four, and then it jumps to hotel two. It looks as though now hotel three is not being pulled in from the database because it doesn't match our query. Good. This is now all working. We're going to continue pulling in data from our database in the next video where we will be getting our hotels based on the country. 25. Distinct values: If we head over to mongodb.com, which is a homepage for our database. Up at the top, we can see a link to the documentation. This documentation is going to give us all the information we need to query our database. On the left-hand side, if we click on getting started. Here, we can find a full reference to all the database commands, which we're use in this course, along with many others. Down at the bottom we have a reference section. Click on this, and then go to database commands. This will give us a list of different methods which we have available. Let's scroll down to the use commands. Underneath here we have a find method. If we scroll down to the query and write operation commands, you have this fine method which we used in the last video to get all of our hotels. The next one which will be covering in this course is distinct and this command is near the top. We have this just here. For this project, we need to get a list of available countries which have hotels located in. We may have multiple hotels with the same query law. For example, we could have six hotels located in Mexico and we don't want the word Mexico to a appear six times in our country's list. Distinct will allow us to return an array of only the distinctive countries, meaning the only Mexico will appear once from our example. Let's begin by creating the all countries templates for this page. Open up the sidebar, let's close off some of these. I close this down. If we go to the views, we can create a new file inside of here called, all_countries with the.pug extension. We go ahead and add our basic code; extends layout, and then the block content, the h2 of title. Then next stop, we can add the route to the index of JS file. Go to our index inside the routes folder, open this up, and then after the " /all route", we're going to add router.get. This you got to handle the /countries routes, the hotelcontroller, and this time we're going to set up a function called listAllcountries, add the semicolon at the end. We have not yet created lists all countries. So, head over to the hotel controller file and then we can add it in. Let's open this up. After a list all hotels let's add exports.listAllcountries. Setup our function. I'm going to mark this as async, because we're going to need an await inside of here. We can pass in our request, our response, and also next. Then add our try block, try and run the code, followed by our catch, which is going to take in any errors and then pass them over to next. Make my error with no s. The code inside of the try block will be fairly similar to the all hotels above. We begin by creating a constant to store our data in. I'm going to call this constant allcountries. This time now we select our hotel model, so set this equal to Hotel capital H. Instead of the find method that we used before, this time we use.distinct then to return an array of distinct countries, we can pass in the country field as a string, and then under this we can render our templates with res.render. The template we want to add is the one that we just created of all underscore countries. Separated by comma we can pass in our title. Way to the text of, browse by country, I make this little bit smaller, then we can pass in our all countries data, which we set up here. Make sure that this is available to use inside of our template. Once this is done, hit save and then go to the browser, open up our projects, then we can go to /countries, and then scroll down, and we'll see the page title of browse by country. We only see this page title, because this is all we have currently setup in the template. Let's go to all countries.pug, and fix this by adding the all countries data. Which we now pass in to the template. I'm going to begin with a wrap if, just like we did with the hotels. This is going to be called country wrapper, then create an unordered list to display the list of all countries. To get all of these countries, we need to loop through this all countries data, which will pass to this template. We can do this with a loop, so each country in all countries, create a list item, which is also going to be a link. Pass in the href. This is going to be equal to our back takes, and then /countries/, then we can add our dynamic country name. So these are the country inside here, which is this individual variable that we loop through. We can then output our country name. And we can make this dynamic using the # and then the {}, and then output the country. If no countries are available inside the database, we can then follow up with an else block. Just on the same level as each, we can add else, which I'll put a list item with the text of, there are no countries. Now if we save this file and then over to our Projects and then reload our forward/countries routes. Then scroll down. We don't quite see the information which we're expecting. We were expecting a list of countries. Again, a lot of strange looking code down below. The reason this is happening is because we are not awaiting our data to come back before we're trying to render this to the screen. This is one of the problems we mentioned before, because we're using a single weight, we need to await our data to come back from the database before we try to use it in our application. If we go back over to the hotel controller and the list all countries, we have this function marked as a sink, but we're not awaiting the hotel.distinct value to be returned back from the database before we pass it to our templates. Hopefully now if we save this and then reload, we now get list of countries being displayed. If we click on one of these, we're then it taken to our route of countries, forward slash and then Jamaica. We have an error down below because we're not handled this route just yet. Let's try another one for the Netherlands. These all appear to be working. It would also look nice too, along with this country name if we can also put in a image related to this country. We already have the country images, which is stored inside of our Images folder. Public images. Then we have some countries with images down below. Let's go ahead and make use of these images in our templates. So just under our link, go on to the next line. Then we can set a image indentity in one level. This also links to the same route above. If the image needs a source, is it going to be equal to o back ticks, the forward/images folder, the country's folder. Then we can add in the country name, which is simply country. Then we need to add the.jpg extension onto the end. If we now save this and then go over to our forward/countries routes, reload. It looks like we're typing errors. So let's take look at this. It's just because we've added a semicolon in our templates, which we don't use in pug. Refresh. There's our country images next to the name. At the moment, this looks like they are now all working but at the moment though we can't be too sure. This is because we only have one hotel in each of these countries. So we don't know if it's showing a distinct value just yet. We can test this by adding small hotels to our database. I know it's a bit repetitive, but let's now go ahead and add the remainder of our hotels. Then we can use this for the rest of the project. Let's go to forward/admin, forward/add, down to the bottom, I'm going to add hotel number 6 and then crop the Lorem Ipsum. Go to lipsum.com, I'm going to create two paragraphs and then hit "Generate". Copy this and paste in our description. Hotel 6 has the image, the star rates in this time of four, the country, Sri Lanka, the costs, 57. This cone can be available too. Admin/add, Hotel 7. Add the description and image. The star rating of five, the country of USA, 78. Keep this as available. Back to our admin routes. Create hotel 8. I'm going to go up to hotel 12 to much all images which have been provided with the course. So add this in and hotel 8, the star rating, the country of Maldives and the availability as true. Now we can see we already have more than one hotel in the Maldives. Back to forward/admin, forward/add. Hotel 9. Based on a description. This one can be a star rating of four. The country of Mexico. Cost per night. Confirm. We need it now, let's go on to the admin adds and creates number 10. [inaudible] four, hotel number 10, the description and also the image which is number 10 too. Open this up, the star rating of three. Let's again go for Mexico. Have a price and then hit "Confirm". Admin adds, hotel 11. The star rating, let's go for four, the country of Thailand, cost per night, 39. Confirm. Finally, we can add the hotel number 12, which is the last one. Sounds at the bottom. Hotel 12. The star rating of three, Dominican Republic, 56 and hit "Confirm". Great. Now over two mLab we can now refresh. I know this is little bit boring and repetitive. But now we have all 12 hotels now in the database. So we have plenty of information to now work with in our projects. So I've provided 12 images. You can of course add more hotels, if you prefer. There is now more than one hotel located in the Maldives, Mexico, and also the Dominican Republic. Now if we go over to forward/countries and then hit "Enter", scroll down. We can now see all of the extra countries which we've added. There is only one of each volume. So there is only one Mexico, one Dominican Republic, and also one Maldives, which means that with distinct values are now pulling in correctly. Now we're going to move on to looking at the aggregation pipelines. 26. The aggregation pipeline: The aggregation pipeline is an interesting feature of MongoDB. It basically allows us to process data one stage at a time. Currently, only Mongo documentation from before. If we go to the menu on the left, we can go up to the aggregation section, click on this. If we scroll down, we see a diagram which has an example of how we can use the aggregation pipeline in our projects. This example uses a collection called orders, which we can see here. Its comparable to our hotels selection, which we have in our database. This image shows free stages of the pipeline which results in the data we eventually want over on the right-hand side. Each stage in the operation could do things such as filtering, grouping, or sorting documents until we end up with the correct data. The first stage in this example here shows four records inside of our collection. We then sets a matching stage, we then declare that we only want to match any documents with the stars code of A. Over on the left-hand side, we see the only freedom of this A code, and the last one has D. Therefore, only three of these four documents can match, then these three move on to the next stage, which is in the middle of this diagram. The stages are grouped together by the customer ID, which we set here with the group stage, where we're grouping with an ID field. These two have the same Customer ID. Therefore, these are grouped into the same results. Then the third one is unique too. We now filter down to two results. The second part of this stage is to group together the total amount of these two orders the same customer has placed. This is what we see in the total of the final stage. To find out more about what we can do for each of these stages, we can click on the sidebar and go down to aggregation reference, then aggregation pipeline quick reference, then scroll down. Here, we see a list of all the stages which we can use. We've already seen some of these in the examples before, such as the group stage. We have group just here, and also scrolling further down. This is the match stage which we've also seen. You can click on any of these listed stages and find out what each one does. Or I'm going to run through some of these examples now, inside of our projects. If we go over to the hotel controller.js file, we have functions to get all of the hotels and all of the countries in the database. Which of these two just here, but what if we want to be a little bit more specific about the data which we got back on the homepage. I also want to show these hotels both limit the results to be just nine so we don't have an overcrowded homepage. Once our database stores a lot more different records. Also the same for the countries too. For these we can use the aggregation pipeline to filter down these results for the homepage. Let's create some filters to filter down these values. Exports.home, I'm going to call this function the homepage filters. We set this up as an async function so we can use await, pass in the request, the response, and also next. Then a try-catch block to handle any errors, passing the error. Then call next with this error. Let's first deal with filtering the hotels inside of the try block at the top. We can use the aggregation method. First of all, let's set up a constant to hold these hotels in. Const hotels equals awaits our hotel model. Then we call a method on our hotel model, just like we did above with distinct and also for the find method. But this time now we use hotel.aggregates with a semicolon at the end. This takes in an array of the various stages. Add an empty array inside here. The first stage I'm going to use is the match stage. Open up the curly braces, $ symbol match. Then we want to match the hotels which are available. Set the available fields to be true, then add a comma the end. Next step, so the homepage it doesn't get too crowded. The $ sign sample stage. Will randomly select the number of documents which we specified. $ sign sample, we can set this sample size to only return nine documents. You can of course change this to be any value which you prefer. This aggregation which we setup will return towards nine random hotels, which have their availability set to two. We can now do a similar thing with the countries. We also only want to show nine random countries on the homepage too. Just like earlier when we were dealing with countries, this needs to again, only return each country once. Even if there's more than one hotel per country. To do this, we have the group stage. Let's set up a number constant this time called countries, set this to be hotel. aggregate, passing our array. The first one is going to be the group stage, $ symbol group. When we're using the group stage, we also need to pass in an ID with -id is equal to output our documents with an ID field which contains the distinct group by a key. This field is mandatory and we're going to group this by a key name of $ symbol country. This will group all of our hotels by their country and then separated by a comma. We can again setup our sample, the sample, just like the hotels is going to return the sample size of nine countries. The group stage will take in all countries as an input, then I'll put one distinct value. For example, if there are two hotels in the USA, we only get the value of USA ones inside of our array. Now we've created our filters. We want this data to be displayed on the homepage. Let's go and start this over in the index.js. Yes. We can change the controller up at the top. So for the forward slash home route, instead of using the hotel controller to homepage. We can change this to be the homepage filters, which we'll setup, back over in the hotel controller. If we now scroll up and find this export.homepage, we don't need this anymore, so we can comment this out. Finally down in our filters, down at the bottom, the final stage of this try block is to do a res.render. We want to render our index page, which is the homepage. Then inside here we're going to pass in our two values, which is the hotels and the countries. We can loop through these on the homepage, parsing the countries and then now hotels and actually we also need to await of countries too. So as a side note, awaiting to promises like this, using await here and also await here is not a great idea. This is something which we'll come back to you and fix later on. For now though, over in our index or poke file, we can deal with these countries and also the hotels. So for now though over in our index.pug file, we can now deal with these countries and hotels data. So go to views and then index.pug. Let's close the sidebar. At the moment if we go to our home route. So click on the logo at the top. On this homepage, we have an error because we're not yet parsing any country detail to this hotel mix in. Let's now go ahead and loop through all of the data which will now be in past and then we can display this hotel mix-in for each one. After our text of CO, create on another list, we can then loop through all hotels with each hotel in hotels. Remember hotels is the data which has been passed to this template just here. So each hotel in hotels. For each one in the database, we also want to display this mix in and as well as displaying this, we also need to pass in the individual hotel data, so this is available in the mix in. Let's give this a save and then reload on to the homepage. Now we can see some hotels now listed on the screen. Let's just check. We have nine. We have 1, 2, 3, 4, 5, 6, 7, 8, 9. That all seems to be working okay. Back over to the index. We need to do a similar thing now for the countries. Underneath here we can add a wrapper. Make sure this is at the same level as the hotel wrapper above at.country_wrapper, for the CSS later. The text h2 of countries, a link, and this is just like the link from above here, which goes half the href to forward slash countries and then inside the brackets the text of see all. We have these two links on here for the countries and also for the hotels. Because remember we limited the sample size and the homepage to only show nine hotels on nine countries. Therefore, link in to a new page for all hotels and also all countries will then allow the user to see everything which is in our database. But we'll come back to this later on. Then I will unorder list to display the countries, will do the same as above. We'll say each country in countries and then create a list item for each. With a link nested inside. The href is with dynamic so open up the back takes to go on to link to forward slash countries. Inside here we want to pass in the country._id. We need to use country._ id because if you remember from before in the aggregation method, if we go back to our controller, we set the unique ID in the group stage to be the country. Now inside of our index, this ID field is where our country name is now stored. Then we can display the same value. So the harsh, the curly braces and then country._ id to display this as text next to the link. The final thing for this template is to also add the image, the image source. Again, this uses the back takes. So forward slash this is the images folder, the country's folder to grab the country image and then just like above, we can pass in the country name, which is the value of country._id with the. JPG extension. So just so this underscore ID is a little bit more clearer, if we go to the hotel controller rather than rendering this index page, let's just do a quick res.json and then we can display the countries data. Save this and then reload the homepage. Now, we see this mandatory ID field is now being set to the individual country. This is why we are using the underscore ID in our template to access the country values, and then display them on the screen. Now, if we reinstate our hotel controller, remove all res.json and add the res.render back in, save this and then reload our homepage. We should now also see nine countries too. Let's go down to the bottom, 1, 2, 3, 4, 5, 6, 7, 8, 9. For hotels, we also say nine, which we counted before and if we scroll through, we shouldn't see any reference to hotel 3 because this one is said to be unavailable. So this all looks fine and each time we refresh, we should see these in a different order because we're using a random selection of our hotels. This is an introduction to the aggregation pipeline. We will return to this later when we begin working with the search facility we added in the header. In the next video though, we'll continue to work with Mongo by looking at how to update data in our database. 27. The edit and remove form: If you go to our application and then go over to the admin section, so /admin and then go down to the bottom, we've already used this add new hotel link, which you see down here. But now we're going to move on and work with the Edits/Remove Hotel link. It is going to link to a form where the admin can search for a hotel by either using the hotel's id or the hotel name. Then once this form is submitted, it will return the match in hotel and allow us to move on to either update or delete the hotel. The first step is to create a page template with a form. Let's go over to the sidebar and then into our views, create a new file called edit_remove.pug. Inside here we can extend the layouts so extends layouts and then block contents and make sure that's spelled correctly. I'm just going to take a simple form where you can search for the hotel id or the hotel name. To begin, I'm just going to add a level 3 heading for the title which we'll pass later, the form, the action can be equal to an empty string because we're going to be adding a post request to the current route which we're on. The method is going to be POST and then nested inside here I'm going to add a div with the class of form_input. Let's begin by adding a label for the first one which is going to be the hotel id, so label for hotel_id and then the text of Hotel id. The input, it's going to have the type of text, the name of hotel_id, and then an id which matches its label. Remember before we said that we can either search for this hotel that wants to update or delete by using this hotel id, or we can search for the hotel name if we prefer. Let's add a p elements with the text of or so the user knows they can either uses it's id or the name. I'm going to copy this form inputs and then paste this in below. Make sure that it's all lined up nicely and then this one's going to be for the hotel name. Change id to be name, the name too, and also the id. This also has the input type of text too and the final thing we need to do is add a new form input. This is going to be for the button to submit which is going to be type of submit, and also the class to match some of the other buttons which we created earlier of button_small. The texts of confirm. Save that and then we're good to go. This is a form which is going to search for the hotel which you want to update or delete. If we now go over to our admin and.pug file, this is the middle link which looked at before. This now links to /admin/edit-remove so I'm going to copy this and then we can go ahead and deal with the route that this is linking to. We do this as always inside of the index.js file. I'm going to add this inside of this admin section. Router, and this is a get request, pasting the file path of edit remove. This is going to run the hotelController and I'm going to create a function called editRemoveGet. Now we can create this editRemoveGet inside of the hotelController, so down at the bottom, exports.editRemoveGet and set this up to be a function which takes in a request and response objects. All we need to do inside here is to arrest or render for all page template which is created. The page template was called edits_remove separated by comma. We can then pass in our title for our page of Search for hotel to edit or remove. Add a semicolon at the end. Save this and go over to the browser and then click on Edit/Remove Hotel. Hopefully we should get our form down at the bottom. Now we have our form once the admin hits the confirm button after adding an id or a name. This will then send a post request therefore we need to solve this post request again in the index.js. Then duplicate the code from before, paste this in. We are going to be using the same route but this time creating a post request. router.post and instead of editRemoveGet, it's going to be editRemovePost. Then set this up inside of our controller, also controller.js, so exports.editRemovePost. This is going to be dealing with the database so we can mark this as async so we can use a wait inside the function, pass in a request, response, and also next. Set up our try block and also the catch for any errors which would then pass to next. The first thing we're going to do in side of this try block is to grab the data which is being sent to us. Inside of our form, we're going to either receive a hotel id or the hotel name so let's have some constants to store these values. The first one of hotelId. This hotelId is going to be stored inside of the request.body. Because we're making a post request, we can access this data if we go over to our form in Edit/Remove. Now we can access this with the name which we gave it inside here of hotel_id. We use this inside here, so hotel_id, and I'm going to use the two pipe operator to say all or null. The reason we're doing this is because only either the hotel id or the hotel name is going to be present. Therefore, the overall is going to be null. Therefore, we need to handle what will happen if we get a null value. We can do the same just below. Constant for hotelName equals req.body, and this one is.hotel_name, so we will either have the hotel name or it will be null. Just like earlier, we're also now going to search or model using the.find method. Let's have the constants called hotelData equal to await Hotel.find. We're going to do something a little different this time because we don't know if we're searching for the hotel id or the hotel name. Because we can't be sure which data is being passed to us, Mongo provides us with the all operator and then we can provide an array of these two values to either search for one or the other. Passing our objects and then use the $or. This is going to take in an array and inside this array we can pass in our two values that we want to search for. Open up the curly braces. The first one is our hotel id. If we receive the hotel id from the form we want to search by the id. The id Mongo is _id so we can check if this is equal to hotel id which is our constant just here. If this isn't present, separated by comma, we can add a second check. The second case is for if we receive the hotel name instead of the id. Therefore, we want to check the field called hotel_name from our database. Then we want to check if this is equal to our hotelName variable, which we have just here. Add hotelName- I hope this makes sense. We are doing a find method, and we're using the o operator to check if one of these fields is a match. After using our dot find method, we're now going to specify a collation to search for. If we just remove the semicolon at the end for now, and then chain onto the end.collation, open up the brackets, and then pass in an object. Collation allows us to make language specific matches, so I'm just going to type itself and now. The locale is going to be sent to en, add a comma, and then the strength as a value of two, so let's add a semicolon at the end. Using collation, like we have here, collation allows us to make language specific matches. Here we're declaring we're using English texts, and the strength is an optional value. Setting the value of two is a secondary level of comparison, meaning it's not case sensitive. This is good because it means we can, for example, just type the word hotel inside of our form down here, just like this, without using a capital h, and you'll still find the hotel from the database. There is also different numbers you can use here too, and these are all listed in the documentation if you ever have a need for them. Then we're going to add an if else statements to handle the outcome of what to do if a result was found in the database. Back over to our code. After this creates an if statement. If the hotelData which is this constant just here,.length is greater than zero. Here we're basically checking if this fine method has stored any values inside the hotelData. If it does, the value will be greater than zero, so we can then go ahead and do a res.json, and output our hotelData. We will of course come back to this after making the hotelData our template, but for now we can just leave this as a res.json, then we add to the return keyword afterwards, so we don't move on to the l statement if the section is true. If it's false, we then create an else statement, and then we could do res.redirect to redirect the user to /admin/edit-remove. Basically if no data is found in the database or there is no matches, we'll just get redirected to the current page, so off to the browser we can give this a go. Then let's test for hotel 7, it confirm, and then we get our res.json with the hotelData returned. The hotel data matches hotel 7 which is good, and we also used the lower case for this search 2. Let's also try this with the hotel ID. Let's grab one of these hotel IDs from mLab, hotel 6, add this in, it confirm. Now we get back the value of hotel 6. What I want to do now, rather than doing a res,json just here, I'm going to create a new page template called hotel on the scroll detail. This will basically be the extended view of the hotel with the full description. Let's begin by removing our res.json, and instead do in res.render, pass in our template which we are going to create of hotel_detail. The title for the page of add/Remove Hotel, and then pass in our hotelData, then open up the sidebar. We can now create this hotel detail templates. Inside of views, create a new file of hotel_detail. I'll put. This templates will also be reused later, we'll also need it when we click on any of the individual hotels in our list to be then taken to the extended description view, so let's get to work on our hotel detail, so extends our layouts. This page is also going to be used to replace this res.json, so as soon as we have a matching hotel, we'll then display this hotel on the screen. We also need to import our hotel Mixin so we can reuse the same code and display this in place of this res.json. In our template, we can include mixins/_hotel, block contents. Indented m we're now going to loop through each hotel in hotelData. HotelData, remember, was passed to this template just here, back to our templates, we can create our loop, each hotel in hotelData. We can use the div of.hotel, so much as the rest of the CSS later, and then other will mixing will plus hotel passing in the individual hotel which we have here in the loop. Now if we save this, and then over to our code, reload the browser, and then scroll down. Now rather than this res.json, we're now rendering our hotel using this hotel detail.profile. We also pass in his hotel to our hotel Mixin to reuse the code, which displays our hotel. We're just about done for this video, the final thing I want to do at the top of this hotel is to add two buttons. One is going to be a button which is going to go ahead update this hotel which we selected, and then the second one is going to be to delete this hotel. In the hotel detail above our Mixin, let's add a link for our button. The href is going to go, I need the abatics, the hotel symbol. Hotel._ id/update. Here we're creating a route of the hotel ID, followed by /update. This is what we use in the next video to handle the update, nested inside here, add our button with the class of button small, and then the text of update hotel. Now if just copy these two lines, and add this in once more just below. These can be also for our delete routes, so change is to delete. Then this one can be Delete Hotel. Give that save and then reload the browser, confirm the form submission, and there's our update and delete buttons at the top. Later on, we'll also hide these buttons so only the admin can see them. Now inside of our admin section, we've created a button down at the very bottom which links to the edit remove hotel view. Inside here we can now search for a hotel by either using the ID or the name of our hotel just like this. We can then click confirm, were then taken to the hotel which was selected, and then we have the option to either update or delete this hotel, and this update hotel functionality is what we're going to be moving onto in the next video. 28. Updating records: We've now successfully searched the database for the hotel and we show it in our view. In the last video, we also added these two buttons to update and also delete the hotel. If we click on the ''Update Hotel'' button, we now pass the hotel ID in the URL as a parameter, just before forward slash updates. This is because we set this up in the hotel detail.profile. We set this up just here inside of our link. Having this unique hotel ID is how we're going to be selecting the hotel from the database we want to update or delete. First, we can handle the route in the index.js file. In our admin section on the edit remove, let's add router.get. In this video, we're going to be handling the updates. The route is forward slash admin forward slash. We want this section to be dynamic so we use a colon and give this ID a name of hotel ID. Then update. We want to run the hotel controller. Then create a function called Update hotel get. This will then display a form on a screen which will allow us to change the hotel details before creating a post request to actually submit these to database. Over in hotel controller, we create this update hotel gets. Let's go to the hotel controller.js. Down at the bottom, exports towards updates. Hotel gets, which is going to be a sink. Smart dysfunction with the a sync keyword, passing new request, the response and also next. We can add a try block. Then add a constant of hotel. This is going to add weight on the data when we go to the database and find one record. The one record we want to find is the hotel which is passed in as the parameter at the top here. Inside of the request object we'd use need.params. Awaits the hotel. Let's find one which will return one record which matches. We can match this with the _ID field. The ID we want to match is stored inside request.params. We named this if we go to index.js hotel ID. Request.params hotel ID. After this we then want to add our cache block just afterwards. To cache any errors pass this on to next for our middle ware, so next error. To check this is all working okay after our constant just here. I'm going to do res.json to see what data is returned back to us. We can then pass in this hotel which we are searching for and then go over to our project and then hit reload. Now, we can see we getting the details back from hotel full which is the ID which is passed in as a parameter in the URL. If we go back to our admin and search for a different hotel in Number 6. I'm going to update. We got the value of hotel 6 returned back to us. Now we know we're getting the correct information instead of this res.json we now want to render a page templates. The template I'm going to reuse is the add hotel templates. This is basically the form which has all the fields which we need for our hotel. We can go ahead and modify any of these and then update. Instead of the res.json changes to be res.render. Passing in our templates of add hotel. The page title of update hotel. Then finally we can also pass the data stored in our constants of hotel. Passes to our templates and give them a safe. Now, we go to the browser and then he Reload instead of the JSON we should now see our page now has a form is at the bottom. This form is going to be used to update the hotel. Inside of this form, something we ideally want to do is to have the data passed into all these fields already. For example, it should say hotel 6. We can go in and just modify the data which is there. We can use these values straightforward just before we do this, I'm going to put this form into a mixin to keep things organized. Over to the sidebar and then side the Views and Mixins, create a new file called underscore hotel underscore form. With the.org extension create our mixin name at the top just like we did before. Hotel form which is going to receive the hotel data as an argument. Then Hotel.org on the sidebar. This is the form which will now rendering for the updates and also the Add Hotel section. Then we can put this down from our form all the way right down to the bottom. Our full form section and save the file. Now go back into a mixin of hotel form and we can paste this in. If we go back up to the top and and then indented correctly, save that file. With mixin now setup we can now go back to add hotel.pug. Then include the mixin at the top of the file. Include the mixins which is a folder and the name of underscore hotel, underscore form. Remember we don't need the PAG extension. We can include this mixin anywhere in our file. I'm going to add my back end at the bottom. We plus hotel form. Person in the hotel data. If we now save this and test, it's working okay. I reload in, we still see the form is now on the screen but we've outsourced this to a mixin. Back to making these form fields, have the hotel data already populated. This can be added inside of the mixin that we just created to the hotel form. Lets go down to one of our fields to begin with. Let's start with the hotel name. The way we can do this to set the volume. Inside the inputs we can set the value equal to a hotel which we receive in as an argument here. Then the name we want is.hotel_name. Actually this is a string. We don't want to use the quotations. Now if we save this and then it reload our form. We now see the value of hotel 6 which is now being passed into our form. We can do the same with the other fields too. The description. Go into our text area because we say text area. We need do this a little differently. We need to set the text to be equal to hotel.hotel_description. Rather than using the volume attributes like we do in other inputs we can go down to the star rating. We did the image so we don't need this for now. The star rating takes you come back to the value of hotel.star_rating. The country. Hotel, country, the cost per night. Again after required value is going to be equal to hotel dot cost per night using underscores. Save this and then check this out in the browser. Reload. Great, this now makes updating the information for a hotel so much easier. Next, we need to set up the post request to actually handle the updates when we click on Confirm button. Pass over to the router, which is inside of the index dot js. Let's close these down, open up the index dot js duplicates over get request for updates. But this time, changes to be post and then the hotel controller is going to be update hotel post. Then create this over in the hotel controller. Exports dot updates hotel post. This is going to be in a sync function with the request and the response objects all the way next for the middleware. Setup our function. We can begin with the error handling. Try and also a catch block, checking in the errors. Then passes to one middleware with next. There we go. Inside of our try block, the first thing I want to do is settle by constant. This is going to be to store the hotel Id which has been passed to us. This hotel Id number is available as a parameter which we have just here. Let set this up now, const hotel Id is equal to request dot params dot hotel Id capital I. Then a second constant of hotel, which is going to be equal to await hotel, which is our model. This time we're going to be using a method called find by Id and update or a common case or find by Id and update. This is a Mongo method which we can use to then pass in the hotel Id, which we have star just here. We can then obtain the record inside Mongo and then return back towards the new details. First of all, the first arguments which we're going to add, this is variable of hotel Id. This first argument is the idea of the record, which we want to find inside of our database, separated by a comma. The second parameter is the data we want to use to update it with. This data can be found inside of the request, the body. We also use requester body when originally created the hotel, which is just above. If will go up to create hotel post, which was a function we originally used to setup a new hotel. Remember inside here we created a new hotel using information from the request object stored inside the body. This is the data which is passed in from the form. We're going to be using the same data down below. But this time, rather than creating a hotel, we'll be using it to update. The third parameter. Finally, I'm going to add a options objects, so separated by comma at an objects and we can set new to be true. By default, after updating, we will still get the original record returned back to us. If we go ahead and set new to be true is we'll make sure we get back the modified or the updated version to show in our app. Then over to the browser. We can now make a change. Let's call this the hotel 66, it confirm. We don't see anything on the screen because we're not setup what's doing next. But instead, if we go over to mLab and then refresh. Now we can see we have the hotel 66 inside of our records. Back to our project. We can see this is still spinning in the corner. Ravenous browse hung and we're going to do a rest or redirect to then redirect this to the route, which won't handle this. After our constant of hotel, let's do a rest dot redirect. Inside the back ticks we can add all slash all and then forward slash the Id of the hotel. We have this stored inside of this variable here. We can paste this in, save this, and then reload. Our post requests is now updated database and also redirected us to forward slash all and then forward slash the Id of the hotel. Down at the bottom, we see we haven't set up this route just yet and this is why we see an error. But the hotel is still updating inside the mLab. We'll handle this route later on. This same route is also needed when we click on Hotel. If you go to the homepage by clicking the logo, and then click on any of these hotels. See the full detail. This takes us to the same route which is forward slash all and then the hotel Id and of course we've got the message of not found because we are not yet created this in the browser. Before we leave this video there, let's try one more updates on a different hotel to make sure everything is working okay. Back to the Admin, so forward slash admin, Edits and Remove. We can go for hotel number 12, Confirm. There's hotel 12, click on the Update button and changes to be hotel 122, Confirm with the mLab. Let's scroll up and down so you can see these reports, our normal hotels there. Go to the next page. There's our updated hotel name just there. I'm quickly going to just reinstate these back to how the were. Hotel 12, Confirm this. Then we can go back to Admin, just forward slash admin inside the URL. We can go also to hotel 66, which is the first one which we edited. We can see we've not added an image for this. Let's go to update changes back to hotel six at the hotel six image. Then update this in the database. This is all our updates now working fine. Before we move on now this one small thing we need to fix only if we go over to the Admin. Then if we go to Edit and Remove, search for a hotel, click Confirm and then to Update. Currently we have all the fields inside here or repopulated and this works really well when updating the hotel. However person in this data will create an issue when we're adding a new hotel. Let's just quickly add the hotel 12 image back in and then Confirm. Then if we go to Admin and then forward slash add. Remember, forward slash adds uses the same templates of the same form as we used to update the hotel. But we can see inside of the template that we have an error. These errors are caused because inside of the form we access in the hotel data. Go to a mixin and here we're accessing hotel, which is passed in a pile of options here. Basically this form is expecting to receive the hotel data. However, if we go to the hotel controller and then if we go to update hotel get. Here, we presented the hotel data which it needs. But if you scroll up to where we created the hotel, which is in create hotel get just here. This is also using the same add hotel form. However, we don't pass in any hotel info, and in fact we have no reason to. One way around this is over in the hotel form mixin. Underscore hotel, underscore form, we can go ahead and initially set hotel to be an empty object. Hotel is equal to an empty object and then save this and reload. Now we can see when we add a new hotel, we now have this form back on the screen. Adding hotel to be in an empty object this way will make the template aware of the hotel name and you will know if there's an error. But since it's an empty object it won't interfere with our fields. Great, the main objective in this video was to successfully update the hotels in our database and we now have this working. Next, we'll be covering another important task too and this is to be able to delete records from our database. 29. Deleting records: The final big action we want to perform is to be able to delete items from our database. You will often hear the acronym CRUD, when dealing with databases. Which is short for the four main actions which are create, read, update, and delete. We've already created data, we can also read data too and then in the last video we updated our data. It's now time to look at deleting records too. Let's go ahead and create a test hotel to work with over an admin folds/add. That's our test, test, and we can choose any image, any star rating is fine and the country and then confirm. After this redirect, we now redirected to formal/all and then the ID of the country which we created. Grab this new hotels ID by copying this section here. Then check this is stored in a database over an mlab, so hit reload. Just double check, we have our test, so go to the first section, and there we are. There's our test hotel inside of the database. If we go back over to our projects and then go to admin so forward/admin, we can select, edit, and remove hotel. Just like we did in the last video, we can paste in hotel ID, which was created for tests, confirm, and then we're taken to the full view and we will have the buttons from the last video where we can update and delete the hotel. Click on the delete button this time and then forwarded to forward/admin, forward/our hotel ID, forwad/delete. This is because we said this earlier in the hotel detailed templates. Open up the sidebar, and then go into hotel_detail. This is the link which we said use inside of here, and this is what we're going to go ahead and handle in the routers index [inaudible] file. Close it down and then over in the index.js, this time we're going to set router.get to be the string winter scene of admin forward/our dynamic segments, which is hotel ID capital I, and then forward/delete. This follows the same pattern as the update section just above but this time using delete. We're then going to create our hotel controller.delete hotel get. Then over to the hotel controller we can now create this function. Hotel controller.js and then down to the bottom, so this is exports.delete hotel guests. This will be a sync function so mark this as a sync. As in our objects or request response and next fall or middle ware setup all function so this is going to be pretty similar to a booth. We also need to ground this hotel ID from the premises, so paste this in. Willing not to say a power hotel constant, so const hotel and this is going to be equal to await, wait of a hotel model and then use the method called find one. This is going to find one record inside of our database and we want to find it by the hotel ID, which we have stored just here. As an object, add this in. We want to find one record by the underscore ID field and the ID we want to match to is hotel ID, which is this variable just here. Then we can go ahead and do a rest or render to display the contents of our templates, which just like before when updating, we're going to render the same ad hotel templates. For this time, clicking and confirm at the bottom of our form. We'll then go ahead and delete our hotel rather than update. Add_hotel as in our object, the title of delete hotel, an then passing our hotel variable. The reason we're using this add hotel template once more is so as you can see all of the hotel details influencables to make sure that this is the one we want to delete. We also pass in this hotel, which we're going to be deleting. Once again, you can populate all fields inside of our form. Now if we say this makes you on the same routes as before, which is admin, our hotel ID, and then delete. We can now reload and now we get the add hotel form. Now what this mean? Now we have this get request all setup. We need to now handle how we delete the hotel. To do this, we can create a post request to the same route. Over to the index.js, let's duplicate this line here, paste this in, this time this is a post request and delete hotel post over to the hotel controller and this is exports.delete hotel post. This is also a sync function since we're dealing with data from our database, passing request, response and next. Next thing to do is to add our error handling we try and catch. I just noticed above, we also need to add this into that too. Just for moments will ask the error and then pass our error to next and then we can add this to delete hotel get too so try. We can add these three lines until a try block and then add catch and emphasis to next with our error. Good, so back to our post requests below inside of the try section. Again, we want to grab the ID from the parameters so we can copy this line here. This in an asset of our hotel so const hotel awaits, our hotel model and to remove an item from [inaudible] , we can use a method called find by ID and remove, which is fairly similar to the one we used above, but this one was find by ID and update. Down to our post request, we can again find by ID and remove. Then inside here all we need to do is pass in the ID of the hotel we want to remove. ID, the field we want to target, and then matches to our hotel ID, which is this constant just here, so semicolon at the end. Once we've deleted this hotel from the database, we'll then want to perform a redirect. Rest or redirect and where do you want to go too? Well, before when we're looking at updating hotels, it made sense to redirect to the current hotel with the updated information. However, we can't do the same when delete in a hotel because this hotel no longer exists. Instead, I'm just going to redirect to the home route, gives us a save and then over to the browser. If we reload, so now we're currently on our test hotel and now for click ''confirmed'' creates a post request. This is a good sign were being redirected to the homepage. Now over to mlab refresh. We now down to 12 records so we have hotel 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. On the next page we have 11 and 12, so it looks like our hotel has been successfully deleted. If yours been deleted, congratulations, you have now performed create, read, update, and delete actions on your database. This is a big step for our application and we've made a lot of progress. In the next section of this course, we're going to be pushing on with our projects by adding, styling, more templates and features and generally making improvements. look forward to seeing you in the next section and bye for now. 30. Hotel detail view: In this section, we're going to be pushing on with our projects and doing some general work, includes styling and improvements. I'm going to kick things off by working with the hotel detailed templates which we created to display the hotel we searched for before editing or deleting. We're again going to reuse these templates in a few places. First of all, if we go over to the homepage or the home routes, and then click on any of our hotels, go down to the bottom of our templates, we see an error message of not found. This is because we need to handle these routes which you have at the top of forward slash all, then forward slash the hotel ID. With these few, we can reuse the hotel at detailed templates which we created and also adding these routes will fix other areas too. For example, if we go back to the homepage and then you click on, see all, clicking on any of these hotels is again taken to the same route. So click on hotel one and we have the same routes of foward slash all and then our hotel ID along with the error at the bottom. This will fix both of these problems, and also again, if we go over to the hotelController.js and go to create hotel post. Scroll up, so you create hotel post here and this res.redirect, also redirect to this same routes here. This is after we create a new hotel, will then redirect this hotel detail page. This is a good one to get working now. Let's start with the route over any index dot js. If we scroll up, we should already have the route or the get to the forward slash all route. Let's keep these in sequence and add this below. So router.get around this time, as we know, is forward slash all, and then the hotel ID, which you can add as a dynamic segment. I'm going to call this variable the hotel. This is also going to use the hotel controller and then use a function called hotel detail, semicolon at the ends. Then we can go ahead and create hotel detail over in the controller. We can add this anywhere, let's go down to the bottom. We start as always with exports, and then the name of hotel detail, and then set this to a sync function, pass in the request, the response and also next, add the body of our function. Then I'll try catch block. So try and then catch which takes in the error, and then pass the error to next. Okay, good. We're going to begin by creating a couple of constants. The first constant is going to grab the parameter, which is the hotel ID. We're going to use this hotel dynamic segments, which is in the URL. Let's first say this is in a constant. So const, hotelparam is equal to the request dot params and then dot hotel, which is the name we gave it. A second constant, which is for the hotel data. We're going to use this to search our database using this hotel parameter and then find the unique hotel which we need. We're again going to use await, to wait on states are coming back before moving on. We need to search for the hotel model, capital H, use the find method. Then we need to pass in the field that we want to find. We want to use the underscore ID fields and check for any ID's which match our hotel param variable. Pass in the hotel param, add a semicolon at the end. Then to finish this off, we're going to do a res.render to render out templates to the screen. The template we're going to use is hotel underscore detail. Pass in the title of let's travel and then pass along our variable of hotel data, which is this variable here, which stores the unique hotel from the database. Now since we already have hotel underscore detail inside of our sidebar and then in the views. We have this views down here. We only have this setup and this is also receiving the same variable name of hotel data. Now if we give this a safe, say the controller and then go back over to our browser and now reload. We now grabbing the hotel ID from the URL personally to our controller, which is then getting the information back from our database and then sending this to our hotel detail template. We should also see this is working if we go to the homepage and click on any of these hotels, to be taken to the hotel detail page. Let's also test the routes, which is all the hotels. Click on see all, and again, any of these hotels, and this one's working fine too. Finally we can go to add new hotel. Go to our admin forward slash at and let's create a test hotel. Any information in here is fine. Then confirm, scroll down and there's our test hotel, which we just created and as we've seen before we get a res dot redirect, which goes through forward slash all and then this hotel ID. Although this hotel detail view at the moment, looks the same as all of the hotels, there will be some differences soon. When we go ahead and add some styling, multiple hotels will fit on the same page just like in this homepage here. But if you click on this and look at the hotel detail view, this will be a single view for just one hotel. This will also give us the space to add more details, such as a hotel description down near the bottom, and this is what we will do in the next video when we look at conditional rendering. 31. Locals and conditional rendering: We're going to cover a few different things in this video. Start with locals, all local variables. This is something we've already covered really when templating, but we're going to also look at how to make these available to all of the templates too. Currently over in the hotelController. Let's click on the hotelController.js and go down to the hotel detail. Just here, we already passed a local variable to our templates, just like we've done many times. The data which we passed into this template, if we add this to it's own line to make it a little bit more clear, this is a object which currently we have the title, which is a name value pair, and then also a hotel data which is a variable, which we created just above. Here we're passing in the title and the hotel data which we pulled in from the database. We are free to use these locals to pass anything we want to use in this template. For example, we'll go ahead and add the name of Chris and then over in his hotel detail view. We've already seen we can use these just like normal JavaScript variables, just like we did here, using hotel and then accessing the ID from the object. Here we're using the local variables with back ticks, so you can mix them with some text. We've already also outputted these variables with the equals symbol. So we know how to do that. It's p equals, and in this name, reloads and there we go, that's our local variable as the templates, and also how we can output a variable when used with plain text using a hash. Let's remove this. If it mixes with some plain text, such as here, we can use the hash, the curly braces, and then also pass in our name variable, save and then reload. There we go. There's our Update hotel and our name of Chris mixed in with the button text. Let's remove these examples. If we go over to any of the templates, for example, if we go to all hotels, let's try to do the same. Let's try to output our name variable. So p equals name, and go out to all hotels routes. Click on see all. Now if we scroll down we don't see any reference to the name. This is because locals, as they sound, they are local variables scoped to only a single template, which we'll pass them to, so let's remove this, p equals name. Also in our hotel controller, let's remove our name from here too. But it also often cases when we want to pass certain variables to all of our templates to use rather than creating a variable in each one of these functions and then passing the same data. If you remember from early on in the projects over in the app.js. Let's go to app.js. We talked a little about the app.use middleware, which will have just here. This middleware, when we set no routes as the first parameter, is an action which is used for every request to our application. It basically adds a layer which we pass through for each request. We can make use of app.use to create some middleware for all requests, which will then go ahead and make our variables available in all templates. So let's create this within app.use. Let's go up to our app.set and then add in our app.use middleware. This is going to take in a function which has access to the request, the response, and also next. Let's set this up as a normal function. When using app.use, this function, which is called will also have access to the request and response objects too. Remember though if we only want this function to run on a request to a particular route, we can add the routing first before this. So as the first parameter we can add the string, a forward slash admin for example, separated by a comma, and then our function as the second value. Now, anything we run inside of here will only work on this admin route. But we want this to run on every template in our app. So I'm going to leave the first parameter empty. See there's an action we can add a console log inside of the function body, add console log, and then simply add some texts of hello. Give this a save and then over to the browser. Now, if we click on our logo to make a request to our site, over to Visual Studio Code and now we can see down at the bottom we have the texts of hello, retries a few more times. So keep clicking on this to make a request. We see for every request we get the console log of hello. Inside of the browser though, if we take a look at the spinning icon at the top, we see our app begins to hang. It's because middleware is meant to be passed through and here we have not added in the next call to move on to the next piece of middleware in the chain. So it's basically stuck on it's route. Let's go over to our app.use, and then inside our function, I'll hit next, give it a save. Now if we reload, we can see we can reload this route as many times as we want and it's still working. So over on, the request object which we have here, we have access to a property called the path. This will return the path name of the current request or basically the current URL. Let's take a look at this. Let's say the current path is, and then add on to the end the request, which is this object just here dot path. Now give it a save and then go to any route. For example, let's go to forward slash sign-up, hit Enter. Now in Visual Studio Code, let's lift up this terminologies here, and we can see here our current path is forward slash sign-up. This is the console log which we set just here. I am now going to make this URL available to use as a variable which will have access to any template. Therefore, we can do some conditional rendering later on, which will allow us to only display certain information based on the current route. First of all, let's reduce these down to make some more space and delete our console log, leaving in only the request dot path. Now this request dot path can then be assigned to res dot locals. So res dot locals equals the request dot path. This will then assign our request dot path to the locals object, which is on the response. We can also give this particular local or this local variable a name of our choice. To keep it descriptive, I'm going to call this dot URL. Therefore, we can access this variable or this path in our templates by its local name of URL. What does this mean now for our projects? Well, it now means we can access this URL local in any of our templates inside the project, because it's middleware, which we set up just here, is always passed through for every request. We will also be adding more locals just like this as we go for this project. For example, to make flash messages available in all templates too, but this URL variable, we can now use it for conditional rendering. Conditional rendering allows us to display certain data depending on a condition. Just like when we use a if statements. It will be really useful for us in this project. Since we are reusing templates, we can now only show certain parts of the templates, for example, on certain routes or could show or hide certain parts of that template, depending if a user is logged in. The first thing I want to do is remove the update and delete buttons for certain routes. So if we go to our homepage and click on any of these hotels, and I scroll down, we see we have this Update and Delete Hotel button, which is showing on this route here. This is something we only want to show in the admin routes. To hide these, we can make use of conditional rendering to only show if the URL or the path begins with forward slash Admin. So over to the hotel_detail.pug. Save our app.js. Let's first begin by creating an if Statement using our URL variable. Just after the dot hotel div, indent them in one level if url, which is the name of the local variable, which will now pass to all templates and then use dot startsWith. Add the brackets afterwards. StartsWith is a regular JavaScript method which will be true if we pass in a string inside the brackets, which matches the beginning of the URL. So to check if the URL begins with forward slash admin, we can add this in as a string. Now, if we indent these four lines here, which are our buttons. Now if our URL starts with forward slash admin, everything which is nested inside this if statement, i.e our buttons will now be conditionally rendered otherwise, anything else which is not nested inside, such as our hotel mixin, will still display regardless of the route. So over to the browser and let's give this a try. If it reloads and then scroll down, we can see these buttons are now missing from the top of our templates. Let's try some more, open the homepage, see all, click on any one of these, and the buttons are now still missing. Let's try the admin route and check the button if they're there. So forward slash admin, and then go down to Edit, remove hotel. Let's search for any hotel name. So hotel 7, this now displays hotel 7, and we still have the updates and delete buttons. Because our URL begins with forward slash admin. Good, this conditional rendering is now working with our URL variable. Another use for this variable will be over in our hotel.pug mixin. So let's open up the sidebar. Mixins and then hotel.pug. We can finally make use of the hotel description we have available, but only display this in needful hotel view. So just after the hotel name, keep any horizontal line. Let's create another if statement using our URL. So dot startsWith, this time we can pass in a string which is forward slash all and then forward slash. Nested inside here we can set a p element which is equal to hotel. So it's hotel_description as a new horizontal line just below to separate this from the star rating, the country, and the price. Save this and then over to our browser. Let's try with the homepage. Now we see our hotel is listed with no description. However, if you click on one of our links to go over to the hotel detail page. We now see description is now added into our templates, but because we only forward slash all routes. If we go over to our homepage and then also click on see all. Here we also see all of our hotels, but with no description. But this routes also begins with forward slash all. This may seem a little confusing why we're not seeing the description on this page two. If we look a little closer and go over to our template, we see the trailing forward slash after all. If we go over to our routes in our index.js, having forward slash all, and then forward slash right at the very end only matches this second route on here, which renders our hotel detail. Since we using a additional forward slash and also our all hotels route here is only forward slash all with nothing at the end, this is why this description only works on the hotel detail page and not on the all hotels route, which we have here. We'll make more use of this URL variable for the course, but next we're going to be handling display in our hotels based on a particular country. 32. Hotels by country: If we head over to the homepage of our projects and then scroll down, below are hotels, and go down to other countries, which we have just here. We have a list of countries which have hotels located inside. If we click on any individual hotel link, such as this, this will take us to a route of /countries and then /country name. Currently we get a 404 because its route is not yet handled, as we see here, we will be fixing these in this video by displaying a template, which will display all the hotels in the database which are located in this particular country. As usual, let's get to work over in our index.js. Let's clean up some of these tabs for now. Index.js. Let's go down to our /countries and then add a new route which is below this. Since we are just getting a template, we can use a get request, so routed or gets, and then we can use /countries, just like we see in there. Then add our dynamic country name as a parameter. That's the colon, and let's call this the country. This is also going to use the hotel controller and then we can create hotels by country. If routs has a dynamic segments to capture the country from the URL. Let's go to our hotel controller. Create hotels by country function, and then we can grab this dynamic section from the URL. Hotel controller down at the very bottom, we will set this up as normal, export starts. Hotel by country will mark this as a sync, passing in the request, the response, and also next. Let's add our try section. Catch any errors and then as usual, we'll pass this to next. We'll begin by capturing the country from the overall parameters, and this is just like we did before with the hotel. Let's set obey constants called CountryParam, and this is the request..Params.country. Then we can setup our find method to search our database by the country. Columns, we'll call this the country lists, because it's going to be storing a list of countries which match our parameter, we will await Hotel.find, and then to only return our countries, we can pass in our objects passing the Country field which you want to match to and then match to our countryParam variable. Before we pass this data to our templates, let's first do a res.json to see what data is being returned from the database. res.json, and then pass in our country list, which should store a list of countries. It gives us the save and then reloads and make sure you still on the same routes as before, which is /countries and then a particular country just afterwards. Since we're on this USA route, we only seeing countries available in the USA. The test hotel were created before, was the country USA, and this hotel seven is the USA too. You may only have one per country depending on which country you clicked on. We can also change this in the URL. Change Mexico, and here we go. We'll have hotel nine and also hotel 10, which are in the country of Mexico. This is looking good. We now have the hotel data we need to pass to our templates. Now we can replace our res.json with a res.render. We're going to be creating a template called hotels by country. Using the underscores separated by comma, we can adds our objects which becomes contain the title or browse by country, and then also inside here we can add a dynamic section, which is going to be the name of the country which we're looking at. We're at this with the symbol, the curly braces, and then inside here we can add in the countryParam, and since we're now using some dynamic data in our string, we also need to change these quotations to be back ticks. Change these are the semicolon at the end and as well as its title. We can also add a comma and also possibly in our country list, which is the data and we're going to be needing inside the templates. CountryList and give us save. The final stage, as you already know, is to create these hotels by country.pug File, and make sure you spell correctly. Opened up the sidebar inside all views folder, create a new file called hotels by country.pug. This template like all others will extend our layout and we'll replace the block called content. Since it's templates will also be displaying the list of hotels, we also need to include our mixins. Include Mixins/_hotel, or hotelmixin. We can also pass in our title, h2 equals title. Now we need to loop through all the data in our hotel controller. Who seen in this country data is stored in a variable called countryList. Let's create a loop. Each hotel in countryList, creates a wrapper of.hotel_wrapper and impulse in our mixing with the plus symbol, plus hotel, and also passing the individual hotel data from our loop. We can also add a else block on here in case no matches are found for this country, display this on a list item. There are no hotels, and once you have a template which looks like this, let's give this a save and then reload. Now I'll res.json is replaced with our templates. Have a error, let's lookup the view hotels by country. Let's see what's going on. We have a spelling mistake, so hotel, and this is hotels, so just change this file name inside of our views. Rename, I just add a S on the end of that. Reload the browser. There's our dynamic level two heading or browse by country, when impulse in the country name, and there's a hotel nine and also the hotel 10, which we seen before inside of the JSON. Let's test a few more countries and see if this is all working. Let's go back to the homepage. Down to the very bottom. Let's try Jamaica. We have the dynamic title, and this country is in Jamaica. Down to Netherlands as our title, and our hotel free, which is inside of the Netherlands. Excellent, this is another step in our project, which we've now completed. I think now we have a lot of this working. We should now take a break from adding new features and go ahead and add some CSS styling to make it look a little nicer. 33. Styling the header- small screen: Now is the time to make our project look a little nicer with some CSS. I'm going to begin by styling the header section for the small screen view. Let's begin by shrinking down the browser. So shrink this down and then over in Visual Studio, we can also make this smaller too, open up the sidebar inside of our public file or public folder. Let's click on this and then we have a style-sheets folder with our style.css, and then close the sidebar. Inside here we have some defaults, styling, which is provided with the express generator. So I'm going to select all and remove. To begin, I'm going to add some general styling to the HTML on body sections. So as the HTML selector and then declare we want the background to be white. Then down to a body section and of course, feel free to make any changes to make this app more personal or follow along with me if you prefer the same styling. So the background for the bony section, I'm going to give this a value with the hash of eee, the center this inside the browser and we can use margin zero also set the maximum weight of the body to be 1500 pixels. This will make sure that on really large monitors, the content isn't too stretched and finally, some padding on the boundary of zero on the top and bottom and warn M on the left and right. So we save this and reload. We shouldn't see too much of a difference for now, but we can just see the gray background color, IPO decentralized and also a little bit upon him. From the top I'm going to begin with the nav links, which are these ones just here and these have a wrapper of nav inside here. I'm going to change the display type to make use of the flex-box. So display flex, and then we can set the flex direction to the column. This will set the flex items from the top to bottom. Also the align items property to the center and also declared the background color. So much the logo. So set the background to a volume using the hash for the hex values of 4dc2ca Reload this. There we go. So now our items are now centered in the middle of the page, and also have the same background color as a logo. It looks as though there's also some defaults, margins and plains on here. Let's get to work with our unordered list. First of all, remove any default put in a URL, and then uses just over to the left. The individual list items. We can make these a little larger by setting the font size to be 1.2 em. The display to be inline-block and then also the margin of zero on the top and bottom and ten pixels on the left and right. Reload. Okay, good. So now our list items are inline block, so they displayed across the page in online formats and also they are still below the logo because we said the flux direction of column on the nav elements, which includes the logo and also our list items. So down to our list items here. We can then target the links too. So first of all, if we set the text decoration to be non saving reload, and this will remove the defaults on the line from our links. We can also remove this default color by setting the color value, I want to use a RGB color. So the first one is red value of 43, 40, and 40. The green and blue refresh, which will give us this darker gray color. If we go over to our layout output file. So open the sidebar into the views, and layout that hook up to a form at the top. We added a wrapper classof.search nav, which is the main wrapper for all of these form items inside of our header and also each individual inputs also had a wrapper of dots input rapid too. So we'll go back to our style.css and begin working with our form inside the header. First of all, the main wrapper which was search nav. So search_nav. The backgrounds. I'm going to set this to a hex value of, c1e6e9. then make sure this is spelled correctly. Give that save and now we'll have the lighter blue color 404. A little padding inside here too, just add some spacing of 0.5 em. So next I'm going to move on to all of these items in sort of a form by setting the display type to be flex. We can also give these a flex direction of column for the mobile view. Later on, we'll also change these to be back to the default row, which will then display these across the page when we have more available space. So let's target these in the CSS. We've got search_nav and we can only select the form which is inside of this class here. Meaning the styles which are inside here will only display to this particular form and no other forms on all sides. So display type or flex. The flex direction of column. So this is a fact and some retriever and then we can go ahead and target the individual inputs. So the individual inputs for the smallest green, we won't need to be the full width of the page. Set the width to be 100 percent. We can declare the heights of 20 pixels. Save this, and reload. Okay, good. Let's also add some margins and patterns to give you some space into. The padding. So 0.5 em on the top and bottom and zero on the left and right. Skewed easy full width. So also some margin on the top, space out from the ones above and we all need a little bit of margin of 0.3 em. Save and then reload. I'm also going to remove this default border around the inputs. So let's set the border to be a value of zero. Reload, and now we have this gray line removed from each one of the inputs. At the moment on the mobile view, if we type into one of these destinations, the text line is over on the left-hand side. I'm going to change this to be in the sensor by using the text align property of center and also add some border-radius. So each one of these inputs of five pixels. Save then reload this and now we can see how text is now centered, and we have a little bit of radius on each one of the inputs. Then down to the input refer, which surrounds each one of our label on input combinations. Just to add some margin on to the top and bottom to out some foam spacing and also align this text inside the sensor for the label. So targets the input on a scale wrapper, the margin, the top and bottom values of 0.5 em, and then zero on the left and rights. We can align our labels with a text line of center. Save and then reload. Codes now look a lot nicer inside of the mobile view. We can now add some finishing touches to the select inputs and also the button's down at the bottom. We can select these by the element's name. So select and button. Let's declare the heights of 36 pixels. The width on the small screen of 100 percent. So much of the rest of the inputs and also remove the default border by setting to be none. Save and then refresh. Okay, good. So we needed an alpha of a form. The last thing I want to do is to target just the buttons to give this a background color of cadet blue and also give us a border-radius of five pixels. So much all the rest of the inputs. Okay, reload. Good. Our header section on our form is now looking a lot nicer on the small view. If we scroll down the final touch I'm going to make in this video is to set these header beach image and also any other images on the site to be 100 percent to benefit the container rather than overflowing like we see if we scroll to the right. So down below the button, select all the image elements. Set the width to be 100 percent. Refresh, and it instantly looks a lot better now. Good. Our header is now looking better on the small screen view next week click on to continue we will be styling for mobile sizes both apply these to a hotel's and countries. 34. Styling the content- small screen: With the header styling now complete for our mobile view, we can now move down to a style in the content area, which has the hotels and also the countries. If we go over to our index dot pug. Open the sidebar into the views and then our index dot pug. Over on the side here we have a outer wrapper, which is this one just here. Then nested inside we have a hotel wrapper which goes down the hotel section, and then a country wrapper, or the country section down at the bottom of our index page. Let's go to our style dot css and begin working with the outer wrapper. Make a comment. This is the content section. Hotels and countries, view. Okay, so let's start with the dot outer wrapper, with the under score. This is a wrapper for basically all hotels and countries we see over on the homepage here. We're going to use it to align the text to the center and also set the font size. The text-align property, of center and a font size of one em. Set this, and then reload. Now we can see our title and also all hotel information is now aligned to the center. Now on to the dot hotel div. This was the wrapper we used inside of each hotel. If we go to the mixins and then hotel dot pug, we gave each hotel a wrapper of dot hotel so let's use it now in the css. Below outer wrapper target the hotel. Okay, so we're going to give each individual hotel a background color of white, so it stands out against the Grey background. Background of white and also some margin of zero on the top, zero on the right, one em on the bottom, and zero on the left. If we now save this and then refresh, we now see the white background color and also the margin on the bottom separates out each hotel. Also inside of this mixin, we have the text fields inside of a div called hotel info. Back to our dot hotel dot pug, we have this hotel info section which contains the hotel name, and also in the hotel detail, we have the description and also the star rating, the country and the price. It's basically all these texts we see in each hotel. At the moment, if you click on any individual hotel and then scroll down, were then taken to the hotel detail view. All the text inside here is close to the edge. We can fix this with some padding. Style dot css, the hotel underscore info. All we need to do here to fix this, is to add some padding of one em and then reload. Now have some spacing around the title, the description, and also the information down at the bottom. Next, I'm going to move over to our forms. If we go over to our admin, we should make this a little bit bigger so we can see the URL. Admin and then forward slash add. Scroll down to our form, and currently our form doesn't look too great. Let's get to work on this now. Shrink the browser back down. We've already added certain class names inside of our views. We go to add hotel, close this down. We have this hotel form which is rendered as a mixin. If we go over to this we have each individual form group with the label an input surrounded by this form input wrapper. This can be used over in the style.css. First of all, form underscore input. We can add some margin. If we add one em and then zero, this will add one em of margin to the top and bottom. Give in some space in between each input. Then we can go ahead and target the individual input and also the text area. Because we want this label to appear to the left of each input. To begin, if we set each input to be the width of 70 percent, to make it a little bit narrower, this will then give us the space to add a label on the left. We target the form input, and then each individual input and then we also need to target the text area too. Set the width to be 70 percent. Also the text line to be on the left. Save and then refresh. Okay, that's better. Now on to our label. Again, the form input. But this time we're going to be targeting the label. Set the display to be inline-block. Then give this a width of 20 percent to make sure this fits on the same line as the input. If we reload, we now have each label to the left of the input. Onto this text area, we remove the border from all of the rest of the inputs and give these a border-radius of five pixels. Let's also apply this to the text area so it matches. The border of none and then the border radius of five pixels, semi-colon, and then reload. Now it's exterior matches the rest of the inputs. Then finally down at the bottom we have this large confirmed button inside of the hotel form. If we go down to button at the bottom, we gave this a class of button small. Let's copy this and over in the style dot css add the dot and paste this in. Let's make this smaller by adding the width of 100 pixels, and also some margin of 0.5 ems to give it some spacing, below the browser. There we go. Now the back to admin button and also our confirm button at the bottom is now using this button small class. Now this looks a lot nicer for our small screens. Back to the home page and scroll down and everything looks pretty much as it should be. However, though, if we stretch the browser, make this real wide, things begin to look a little too stretched. This is something we will move on to in the next video, where we'll begin styling the larger view by adding in a media query. 35. Large screen styling: If we make our project the full-width inside the browser, it now looks a little stretched because so far we have focused on the small screen sizes. Let's now add some CSS inside of a media query to fix this. Up to our style.css, right at the very bottom of the file, we add the media query with a media. I want to be targeting the minimum browser width of 1,000 pixels. Open up the code races. You can have a play around with what size works best for you, but I'm going to go for a 1,000 pixel breakpoints and then begin at the top with the navigation. Select the nav elements and make sure this is inside of these media query curly braces. Now we're on the largest green. Up at the top, we have the top header section set to be a flex direction of column, meaning the logo and also the nav links are unsalvageable. Now I'm going to change the flex direction to be back to be row, meaning the logo would be on the left-hand side, and then the links will be on the right. We do this with flex direction and satisfy row, reload. Inside of our navigation section, we have the nav, which is a link for our logo, and also have the another list for our two links here. I want to start the flex value for the logo to be a value of one, and then the another list to be a value of two, meaning it would take up twice the available space over on the right-hand side. We can then align the texts over to the right to make sure that this is over on the right-hand side of the header. Let's begin with the nav a. If it goes to the layout inside a here we have nav and then the a nest inside, and this is for our image logo. Then the another list which is not the same level, so this is going to be a flux value of one, and this will be the flex value of two, making it twice the available space. Inside of our nav a, this is going to take up the flex value of one. Then our nav ul will be the flex value of two. Save this and reload. We don't see too much of a difference but if we go into the developer tools hover over our nav, we see the blue outline for the one part. Then if we go to the another list, we can see this is twice the available width. Back over to the styling. After the flex, we can add the text alignment to be on the right-hand side, pushing over to the edge of the div. But this is probably a little too close to the edge, so a little margin right will fix this of one m. Reload. Now we'll have a nav bar more suited to a larger screen. Good. Now moving down to the search form below. Now we have many columns setup like this is better for the mobile view. On the largest screen like this, we want to change the flex direction once again to be row, so it's more suited to the more available space. Under our nav ul, let's target the search on the score nav. If we go to the layout.pug and then down to form, this is the outer wrapper for the whole of the form. After style.css open up the curly braces and then we can set the flex direction to once again be row. There is no change. In fact, we just needs to also target the form inside here and try this, and there we go. Let's continue with this flex styling. Justify the content to be in the center. This will give us equal spacing on the left and right-hand side. Then after this, the flex wrap, we're going to set this to a value of wrap so it can flow onto additional lines. Then finally, we'll align the items to be flex end. This will align all inputs vertically. Now if we save this one I'll push these inputs to be now in line with the rest of these. This gives us the horizontal form which we want, but it's still a little squashed up. Only when creating this form which surrounded each input with a div, with the class of input Rapa. If we go over to our layout of pug, inside of our form, we can see this just here. This is round and each one of our label and input groups. Over to the style.css and again, still inside this media query, we can now target these classes which was dot input_wrapper. Let's set the margin to be zero to remove any defaults. The Padian to be 0.5ems. Save this and then reload. There we go. We can now see the pattern has added some space in between each one of these inputs. Also restrict these to be a maximum weight of a 170 pixels so don't stretch too far. Then also set the text alignment to be back to the left. Wait for reload and now we'll have some additional spacing around each one of these inputs. Scrolling down to the hotels and countries, the text for the headings which you see here and also for the hotels, it's still inheriting the center alignments in the mobile view. I wanted is by targeting the outer wrapper div. Remember earlier we said the outer wrapper savvy.outer wrapper class. If we scroll up this was one just here which wraps all the hotels and countries on the homepage. Scroll down, we can override the text alignments inside the media query dot outer_wrapper, we can reinstate the text alignment to be on left. Refresh. Now onto each individual hotel. I'm going to be using the flex box for each one of these hotels. Let's set the display type over in the CSS. After outer wrapper, select the dot hotel, which is the div, which is surrounding each hotel in the mixin. The display type of flex. Then reload. This is how our hotels now look by default. It still needs a little work to look good though. If we go over to our hotel mixin, which is underscore hotel.pug. Make this a little bit larger. We added classes to both the image section, which is hotel image just here, and also for the inflow section. We can now use these in the CSS to make our hotel's look a lot nicer. Back to the style.css. Let's first go for the hotel img. Give us a flex value of one, and also some margin of one m to give some spacing. Save and reload. We can just about see the margin on the outside of the image. Now onto to the hotel info, which is the text on the right-hand side. So.hotel_info. We can also give us a flex value of one to make this equal to the image. Then some patterns, add some spacing zero on the top and bottom. Then one m on the left hand right. Save this and then reload. Go to homepage now looks much better. However, if we click on a hotel and go up to the hotel view and scroll down. The CSS we added also applies to this full hotel detail too. I only want this image and hotel to be side-by-side. When we list all the hotels on the homepage and also in the all hotels view. First we can restrict the CSS to only apply to the all hotels view over in the all hotels.pug. Let's take look for those templates. All hotels.pug, let's open this up. We surrounded the hotel's inside here with a.hotel wrapper. Meaning we can use this to be more specific about where we are applying our styling. This can be done by adding this wrapper class before the hotel class in the CSS. Go back to the style.css, let's copy this. Then just before the.hotel, let's add in the hotel wrapper, giving us a more specific CSS selector. Save this, and then it reloads. Still on the hotel detail page. We've now removed the flexbox from this view meaning we now have the content stacked on a full-size image. Let's just check over in the homepage. It still looks okay. Thank click on all hotels, and the flexbox skill takes effect in this view too. To finish things off, and I want to display the countries as a grid. If we go over to the homepage and then scroll down to the very bottom. We have the countries down at the bottom here, but the don't look too great. There's two places where we display the countries. He on the homepage and also if you click on see all, in this link here. This is pretty much the same view as the homepage. Both of these templates have a div with the class of country wrapper. First is over in the index.pug. Open up this in the views index. pug. We have contour upper down at the bottom here, surrounding our countries, and also in the all countries templates we have the same div just here to keep things consistent. Also these countries are outputted as a another list, which we can see here.. We can use this over in the CSS. Back to the style.css and then down to the bottom on the hotel info. Let's select our country wrapper. Another list. We can set the display type to be grid. We have three columns because as the grid template columns to repeat. Then inside the brackets we wants to repeat these three times using the one fr unit to make these equal. To space them out, we can also add the grid gap, which looked at early in the course of 20 pixels. Then also align the text to be in the center. Save this and then let's check this out in the browser. Reloads, and this is the forward slash countries routes, which seems to have some bold text from nasa will take a look at this. Then if we go to the homepage and right down to the bottom, we also have the grid for the homepage too. Let you check out this bold text. Let's click on see all. We can see it's just here. Let's go over to the all countries.pug file. I think it's just a indentation problem. We've got a level two heading here, and then inside of the h2 we have everything nested inside. Let's move all this over to be the same level as the h2 rather than nested inside and reload. That's a lot better. Click on a country. Then we're taken it to the country's view where we see our two available Dominican Republic hotels inside of our list. Once again, we can see how easy is to use the CSS grid. We have nicely aligned a grid layout with just a few lines of code. We'll come back to the CSS later on and add a few more changes as we go. One thing you may have noticed here is when dealing with the countries on the index page and also in the all countries templates, if we'll go over to our template here, we're reusing the same code flow to different templates. We'll fix this in the next video by moving our countries into a reusable mixin. 36. Countries mixin: When we have repeated code in multiple templates, it's often best to put this into a separate mixing, and this is what we'll be doing now with our country's list. In both the index.pug. Down at the bottom we have a list item which I'll puts our country. Also in the all countries.put templates, will have the same list item, displaying our link and our country image. In both these templates, we'll loop through these countries and display both the image and the name as a list. We already know how to use mixins. Let's go ahead and create a new file in the mixins folder to display these countries lists. Open up the sidebar. Inside of the mixins folder, let's create a new file. Underscore country, underscore list with the.pug extension. Let's give this mixin a name. So mixin country list is mixing moving past a country to output. So we can also add this variable into. Then save this file. Then over in the all countries.pug file, we can cut out the list item, the link, and also the image. Grab these three lines just here code this out and then we can go ahead and add these to our country mixing, paste these in, and makes sure the indentation is correct. We will move the list item too, so it's not at the real level. So this is our mixing now looking fine. We can save this, and then go back over to the all countries.pug and then up at the top we can include the mixin file. After the extends layouts, include the mixins, forward slash and then underscore the country underscore list. Remember you don't need the pug extension. Then we can add the mixing in by its name in place of the list item, which we put out indented in one level. Inside of our loop, we call this the country list. This country list is also going to take in the country, which is passed from our controller. We can now save this file and then go off to all countries, which we're currently on now. Reload this. We see the countries are now in place, but this time being pulled in from a mixin. Now all we need to do is repeat this for the index.pug which is this file just here. First of all, we can include the second mixin. So include mixins/. We also have the hotel mixin, but this time it's the country underscore list. Then we can go down and add this mixing in place of our list item. First of all, remember in this file we access the country name with the underscore ID and the link and also the image. This is because inside of our hotel controller.js, if go to the homepage filters, we group together the distinctive countries with this group in stage with the key of underscore ID. Mainly, we'll process ID into the mixin for it to work. So let's remove the free lines from the very bottom. We can replace this without mixing of country list, and we also put in our country._ID. If you save, now this is for the homepage. Go to the index and then scroll down below the hotels, we now have our full country list on the homepage too, as well as the all countries list. Meaning our mixing is now working and we've reduced our duplicate code. 37. Promise.all and array destructuring: Inside of the hotel controller, we created the homepage filters early in the course. You may remember that the other time we said that we're using multiple await calls, just like we've done here, is not always a good idea. Doing this is perfectly fine, however, if the second await call relies on the first one finishing before this runs. For example, if the first await at the top here, save the hotel, and then the second await call needed to access the hotel ID, it would then make sense to keep them both in this way to ensure that we have the hotel ID ready for the second one when needed. But here, we are blocking, fetching the countries from the database until this first await section has finished, and this makes no sense. What we really want to do is kick these both off at the same time. For this, we have something called promise to all. Promise to all is a method which basically is a giant promise which wraps all other promises inside. You maybe thinking, "What does promises have to do with async await?" Well, async await also returns a promise too, so let's take a look at this in action. First, let's remove the two awaits keywords as we don't need these anymore. Now, we're going to look at a few new techniques which will introduce in ES6 or ES2015. First is what is called destructuring. More specifically, for this example, we're going to be looking at array destructuring. We can use this to basically create an array of constant names, then assign these to an array of values which we unpack. It sounds complicated, but it's pretty simple when we see it all typed out. First, let's create a constant to begin with. After our countries, just down here, let's make some space, create a constant. This time, this is going to be an array of values. Passing two values, the first one, I'm going to call filteredCountries, and then the second one, filteredHotels. I have named these countries and hotel variables filtered because these results are filtered using the aggregation pipeline, then we use promise to all which is also new in ES6. This equal to, now, we're going to await, promise with a capital P,.all. Like we said before, Promise.all takes in multiple promises, so it can pass in our countries and also our hotel variables inside here. First of all, let's pass in the countries and this needs to be an array, and also our hotels. Now, this Promise.all, which we have here, will now be resolved once both the countries and also the hotel promises have successfully resolved. Whereas before, using await individually, rather than just once here, this caused both of them to run in order. Now, we can set both these off at the same time, resulting in faster performance. As for the array destructuring, these countries and also the hotels promises, will then be basically unpacked, and installed in the constant names which we set here in the same order. The countries will then be unpacked, installed into filteredCountries. Once resolved, also the hotels will then be stored inside the filteredCountries constants. Let's take a look at one more example to get our head around all this. We can leave this code in because this is what we need for the course. But this one is just going to be a simple example, so you don't need to type along if you don't want to. A consonant of food. Let's set this to an array and add some food values of cheese, fish, and also rice. Then a constant of a, b, and c. Now, if we want to destructure all the values from this array and install them inside of all three values here but in order, so a will become cheese, b will be fish, and c will be equal to rice. All we need to do is to set these values equal to our food array. Then a series with a res.send. Let's send the value of a. Check if this is working and comment out our res.render. Save this and we're also on the homepage. Let's go to localhost:3000. There's the value of cheese. Let's try b and also c, which should be rice. Reload. Now, we get the value of rice too, meaning our food array is now been unpacked and then stored into all three constants just here. This is pretty much the same thing which we are doing above with our filtered variables. Then we are setting these to our countries and hotels promises once the data has been resolved. Now, let's leave this example and [inaudible] our res.render. Good. Now, we have our two constant names, our filteredCountries, and filteredHotels. We also need to pass these to our template in place of our old constants here. This one is filteredCountries and this one is filteredHotels. Also since these variable names are now changed, we also need to change them in the template to match. The template is the index.code. We go into here. For the hotel, instead of looping through hotels, we need to loop through filteredHotels. Then do the same with the countries. This time, let's use is filteredCountries. Then save. Now, all that's left to do is to try this out over in the browser. On the homepage, hit refresh. We can still see our hotels being pulled in from the database, and also the countries down at the bottom too. This means both our destructuring and also our Promise.all method is now successfully working. How many hotels we have inside of our database, changing both our promises to run at once rather than one after the other, has probably not gained much in performance, but it's a useful improvement nevertheless, and some extra knowledge which is useful to have. This kind of code is something which will be more noticeable on a larger application. 38. Environment variables: In this video, we are going to be using what is called environment variables. This will basically be a separate configure file inside of our projects. Which lists all of our user account names, passwords and authentication details, all in one place. This has certain benefits. For example, it keeps our secret information in one place, meaning it easier to ignore this one file when sharing our projects all push into a service like GitHub. Meaning our code is in a much safer way for security. When attained up to production, many hosting providers also spots these environment variables, making setting up our hosting even easier and this is something which we'll look at later when we push our app to Heroku. Also if a reuse any of these variables, such as passport formation in multiple files, changing or leasing one configure file is a lot easier. For this, I'm going to be using a nose package called.env. This will allow us to basically create a new file with the.env extension and this will be used to store our variables inside. At the moment, the only sensitive information we have is stored inside of our app.js. Let's open this up. app.js, it's this information here, which is our database connection but we'll be adding more sensitive information in upcoming videos when we connect to Cloud Storage for images. First of all, we can import the package as usual inside the terminal. Down at the bottom we use a npm install, close down the server and run npm-i, then.env. Give us a moment to pull in a package from mpm. Let's just restart the server. Would npm run their stuffs? So now if we open up our sidebar, we can go ahead and create the Config file, which we are going to be using to store all of our variables inside. Close this down. Then in the root of the project create in a new file, which is simply.env and make sure this is in the root alongside the app.js. Then we add our variables using name, value pugs and also using the capital letters too. I'm going to use DB, which is for our database, and then satisfy DB variable to be equal to a database, URI. This is over in the app.js, open this up, then we can quote our database URI and the connection, take this out with the quotations and then paste this in as our DB variable. Behind the scenes this.env module, we'll take all the variables we create inside this file and add them to what is called the process.env objects, which is provided with node. This object contains information about the user environment such as our username and also the user directory. The variables were add inside this file, will also be added to this object too and this is how we access them inside of old files. To understand this better, we can output this process.env objects and see what it includes. If we go to the hotelController and then go to the homepage filters, which are before. Let's do any console log and see what's included. At the top of our clients section, let's add a console log, then it's logged to the console, the process.env and then go for.USER, which is capitals..USER is one of the properties on these objects and it contains the current uses name. If we save this, pull up the terminal and go to the browser, go to our homepage, it reloads, then over to Visual Studio Code. If we scroll up to the top, we now see the username of Chrisdixon, which is stored inside this use of variable. Along with many more things which are also on this objects. We can also access the present working directory with.PWD, save this and then reload the browser of the terminal. If we scroll down after the two green lines where the server has restarted, we can see the current path to the present working directory. Finally, you can also try our own DB variable which we just created. Change PWD to be DB. Reload the browser, Scroll down and we see the value of undefined down at the bottom here. This is because we need to require it first inside of our project if it work and inside of the app.js is where we're going to add this so it's available as early as possible inside of our projects. So app.js, let's go up to the very top, above all these variables and then require inside the brackets, the.env package. We don't need stall this inside of a constant as we don't need to access it again inside the file but instead, we said.config with the semicolon at the ends, which passes the contents of the env file and assigns it to the process.env objects, which we looked at before, then we can try again to reload the browser. Save this file, reload our projects. Now we see a problem inside the browser. If we go to Visual Studio Code, we can now see some error messages inside here. This is because we now try to setup our Mongoose connection, but we have a empty connection just here. So instead we can now pass in our DB variable, which you create it before. We can add the same just like we did inside the console log with process.env.DB for our variable. Save this and now if we reload the browser, this is all working again and then scroll down to the bottom of the terminal. We can now see we're all putting our database variable, which we still have in the console log just here. Now let's remove is console log as we don't need this anymore and make sure that this is still working in the browser. Good. If you still see the information from the database, such as our hotels and also the countries down at the bottom, everything is still working but by using environment variables. We will add more variables to in the next video, where we'll look at using cloud storage with Cloudinary. 39. Handling file uploads: At moments, our images for the hotels stored inside of our project folder, we saved to the database, a filename, which refers to the image in our public folder. This is fine for testing, but we also want somewhere to store our images, especially when our app is pushed to production. We don't want a admin to access our project files. To do this, I'm going to use a service called Cloudinary. Cloudinary is a Cloud storage platform which allows us to upload images and also videos. You can find this over at cloudinary.com. I'll be using the service to upload our images from the admin section when creating a new hotel. We can then retrieve this image when displaying our image in our website. Cloudinary also has lots of additional features too. Although we won't be getting into any of the advanced features of Cloudinary, there is a lot which you can do, so just cropping, scaling, and enhancing our images before delivery, along with adding different effects. But during this course we'll be keeping it as simple as possible by simply pushing and retrieving images from Cloudinary. First of all, we need head over to cloudinary.com and create a free account. Click the ''Sign Up'' button, and then add our name inside here, the e-mail address, password, and it's all optional. Image in video management and create an account. I want to click on "Developer", "NodeJS" and also will go for other click on ''Next'', and it closes down, and then we're taken straight to the Cloudinary dashboard. You will see there is some generous free upload limits and more than enough size for our project. Here we can see how many bytes we've used in our current storage. Over on the right-hand side, we can see we can get an extra file storage when sharing on social media. But we have more than enough to get started with. Up at the top of the page, we have our account details which we'll need connect to Cloudinary, including our API key and our secrets. We can copy these details and place them in our dot ENV file, which we created in the last video. First of all, let's copy the Cloudinary name. Click on this and then ''Copy''. Then over in our dot ENV file, let's start a new line and this can be our Cloudinary_name, and set this equal to our name we discovered. We also need a Cloudinary_API key. We can set this equal to our API key, which is on here. Copy and paste this in. The third one we also need is the API secret. This is also provided in the dashboard so Cloudinary API secret. We can go to the dashboard. The API secret is hidden by default so click on reveal, copy this, add this in, and give that a save. Then we need to install Cloudinary NPM package into our project. To do this down in the terminal, close down our server, control and C. Then we the command NPM, I , cloudinary. Remember, I is just the shortcut for install and give some moments to pull it in from NPM. It looks like we got a spelling mistake. [inaudible]. Lets go to the package dot JSON and check this is installed. You have Cloudinary as a dependency. We can now go over to our hotel controller so close this down, go to our hotel controller in the controllers folder. We will be accessing Cloudinary using our hotel controller so we need to require it in this JavaScript file. Up at the top sets up a constant of Cloudinary. This is equal to require, and this is a no package so we just simply reference this by its name, semicolon at the end. Then we can set up our Cloudinary config object, which will store all the conflict details which we have placed in our dots ENV file. Just in here, we access our Cloudinary variable dot config. This is a object which you pass in. First of all, we need to set the cloud_name, this is equal to our Cloudinary_name which we saved in the dot ENV file. Remember we can access these variables with process.env. Then in comes the letters or name of Cloudinary. Let's go and name. The next one we need, which is separated by a comma, is our API_key. Again, most of this to our environment variable so process.env Cloudinary_API_key, and the last one we need is the API secret. This is the process.env on the last one was the Cloudinary_API_secret. When uploading images, it's not straightforward as handling the other parts of our form data, such as the text fields for the name and description. If we go over to the hotel_form, which is a mixin. Open up the mixins folder. Open up hotel_form. Currently when saving our hotel, we use the default encoding, which handles all of our text-based inputs, which you haven't here. Currently we have a file inputs for the image. We have the inputs with the type of file, but present we are not really saving an image. All we're doing is saving a file name, which there matches a file inside of our public folder. When saving images in a form using a post request, which we are here, we need to change the encoding of the form to be what's called multi-part/form data. Just after our method, we can add the Ink type and "multi-part/form-data". This will allow our image file to also be included with our post request. However, we now need to add some middleware to our express application, which knows how to handle these multi-part/form-data. For this, I'll be using a package called Multer. Multer will basically take our images which we upload and then allow us to do something with them. It can save the images to insert in file location or even some memory, which is what we'll be doing in this project. We can then push these images to Cloudinary. The first thing we need to do is install the NPM package down in the terminal. NPM, I and then Multer , which is M-U-L-T-E-R. We'll also be using this in the hotel controller, so back over to this, click on this file. We can also require this at the very top. Comes multer equals require multer semicolon at the end and as we said before, multer gives us full control over where we store these images. We can go ahead and set this up now. Just our config. We say storage constants and set this equal to multer dot disc storage. Then passing AMC objects. Inside of disk storage, we can set an options object to setup a folder or destination where you want to save these images to. I will not be doing this because I'm going to be saving these images to Cloudinary. Therefore, we don't need to setup a storage folder in this case, if we just leave these options object empty, like we see here, the computer's default directory for saving temporary files is used instead. Then multer i