Build Fullstack Trello clone: WebSocket, Socket IO | Oleksandr Kocherhin | Skillshare

Playback Speed


1.0x


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

Build Fullstack Trello clone: WebSocket, Socket IO

teacher avatar Oleksandr Kocherhin

Watch this class and thousands more

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

Watch this class and thousands more

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

Lessons in This Class

    • 1.

      Introduction

      1:25

    • 2.

      What technologies do we use?

      3:33

    • 3.

      Downloadable resources

      0:40

    • 4.

      Installing Node & Angular

      8:09

    • 5.

      Configuring server

      5:05

    • 6.

      Installing database

      7:27

    • 7.

      Do you use a good editor?

      2:19

    • 8.

      Setting up socket with Express

      11:53

    • 9.

      Creating Mongoose user model

      22:20

    • 10.

      Adding registration

      20:10

    • 11.

      Implementing login

      11:03

    • 12.

      Creating auth middleware

      15:40

    • 13.

      Creating auth module

      18:59

    • 14.

      Register page - Markup + Form

      12:55

    • 15.

      Register page - service + validation

      11:06

    • 16.

      Login page

      10:00

    • 17.

      Home page

      8:13

    • 18.

      Auth interceptor

      8:05

    • 19.

      Auth guard

      13:52

    • 20.

      Gettings boards

      14:15

    • 21.

      Frontend for gettings boards

      10:00

    • 22.

      Inline form

      15:27

    • 23.

      Implementing creating a board

      19:19

    • 24.

      Adding Top bar and logout

      7:38

    • 25.

      Creating board module

      8:58

    • 26.

      Getting a single board

      2:46

    • 27.

      Adding board stream

      6:26

    • 28.

      Creating socket service

      9:55

    • 29.

      Joining and leaving board

      17:19

    • 30.

      Authentication in socket.io

      11:27

    • 31.

      Getting columns

      9:14

    • 32.

      Create column with websockets

      12:14

    • 33.

      Getting columns

      11:36

    • 34.

      Create column form

      15:57

    • 35.

      Creating a basic task

      9:35

    • 36.

      Getting tasks

      11:42

    • 37.

      Create task form

      8:24

    • 38.

      Update board name

      15:27

    • 39.

      Delete board

      8:18

    • 40.

      Delete column

      10:09

    • 41.

      Update column

      8:54

    • 42.

      Unsubscribe

      6:54

    • 43.

      Task module and basic component

      15:54

    • 44.

      Get task and columns

      13:57

    • 45.

      Update task

      14:42

    • 46.

      Delete task

      7:30

    • 47.

      Deployment

      31:29

    • 48.

      Homework

      2:02

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

Community Generated

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

135

Students

--

Project

About This Class

In this course we will build a Trello clone API using Angular, Typescript, NodeJS, Express, MongoDB and Socket IO . This course is fully focused on fast and deep dive into creation of fullstack application with this tools. We will start from scratch and step by step you will get close to finished real application. You will deeply understand how to structure your application, build reusable and understandable modules and services and split code into smaller chunks of code. We will write code together in efficient way to make it pure and avoid data complexity. We will do real time communication by implementing WebSocket with Socket IO.

Our code will be written with Typescript on the backend and on the client.

We will deploy our application to the real production server at the end of the course.

For each lesson you'll get source code of the lesson, so it's easy to see the progress and get a working app on any lesson you want. 

What you will learn in this course:

  • Structure and configure project

  • Write high quality code with Typescript on real project

  • Create reusable modules, controllers and services

  • Implementing authentication both in http and in websockets

  • Deeply understand Angular & Express design patterns

No prior knowledge except of Javascript is needed (because I will teach you everything from basics) but if you have experience with any of this  (Angular/Express/Typescript/MongoDB/Socket io) it will be easier for you to go through this course.

If you are feeling like you learned web but you still still missing knowledge of how to build your own real application this course is what you need. 

Meet Your Teacher

I am a full-stack developer with a passion for learning and teaching what I know. I have been programming for around 10 years and teaching for almost 6 years.

I believe in learning through doing and this philosophy is present in every course that I teach. I love exploring new web & mobile technologies and my courses focus on giving you the edge in our fast-moving industry.

See full profile

Level: All Levels

Class Ratings

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

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

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

Transcripts

1. Introduction: Welcome to my full stack course where we're building rail project from scratch. It's so great to have you here in this course, we will implement a real project starting from the empty folder and to the finished fully functional production application which will be deployed on the rail server, we will implement a feature that typical project needs, like for example, authentication, working with the Pi, managing and creating reactive state, working with forms and much, much more. In this course, we will use lots of different tools on our client. We will use Angular, which is the best solution for big scalable production applications. On backend we will use now chess was expressed to create our API to store our data. We will use MongoDB, which is a really popular solution to store data in your project. And also people use Socket Layer to create real-time updates inside our application. Obviously, we will write the best possible code which will be dry, scalable, and easy to understand. By the end of this course, you will be able to create your own projects of any complexity using these tools. Who am I? My name is Alexander cohesion and I'm a web developer with more than ten years of experience, as well as the professional instructor with various courses regarding web technologies. I did my best to put all my knowledge inside this course and they want to say it with you. So welcome on board, and let's get started. 2. What technologies do we use?: In this video, I want to talk about technologies that we will use inside this course. And just from the beginning I want to set realistic expectations. We will use quite a lot of technologies here. It will be Angular, Node.js Express, MongoDB, TypeScript and socket IO. And this is a lot of stuff to learn. And then this course, I won't teach you all the stuff from start to the end. It is simply not possible. The amount of knowledge in every single tool here is enormous. This is why this course is focused. Building real project from start to the end. Yes, sure you will understand and learn all these technologies on some level. But here, in some technologies you might require basic understanding what we're talking about at all. With that being said, let's jump into the list. And the first one in our list is Angular. If you don't know, Angular is one of three most popular front-end frameworks, and we will use it to build front and side of our application. Angular is a really strict framework which fits huge companies. And we have that TypeScript out of the box, which means by using Angular, we can build bigger applications, make them safe because of typings and scale them if we need to. If you don't know Angular tall, I highly recommend you to look at list on the basics of Angular, how components are working, how to create modules, how to add routing, and so on. After understanding this stuff, it will be much easier for you to jump in the course. The next in the list we have known chess and actually NodeJS we will use on the backend with Framework which is called Express. And if it does not express it, the most popular framework for Node.js, it is super small, it is not strict, it is really flexible and we will use it as a really popular solution to build back-end. And in this project, we must build not only a but also managed socket connections. The back-end, this is where expresses a real nice choice here, but it is not all inside expressed by default, we have JavaScript. Of course it is not the best approach. We really want to use TypeScript because we will use TypeScript on the client with angular. This is when the back-end with Express. We also want to use TypeScript. Why is that? Because actually TypeScript brings to JavaScript static tightens. This makes our code much safer and we see all our problems, not in runtime, but in the transpiler and time. Obviously now a project we must store our data somewhere, which actually means for our back-end we need a database. And the most popular solution here is MongoDB. This is really the most popular database in the world where we can store data and it fits really nice in our stack with Angular on the client and NodeJS was expressed on the backend. And last but not least in the list is Socket IO. We want in our application to implement WebSockets to notify other users when we create task or credit column when we change part, all users inside this parts must be notified. And the most popular solution for WebSockets inside known just word is called socket IO. It is the library which helps us to manage WebSockets on the backend and simultaneously on the client. This is why it is really a good choice. Once again, if you are not familiar with some tools here, it is totally fine. We will start from scratch, but we will focus learning of all these tools just on everyday needs. Which actually means we will learn basic stuff, correct stuff, and stuff which is needed to implement this rail project. 3. Downloadable resources: In this video, I want to remind you about source code, because actually inside this course, in every single lecture where we code something, you can find attached code of this specific lecture, which actually means every single lecture has a source code inside. And if you just want to grab the source code of the lecture, you can certainly do it. Just grow under the video and check the archive that is attached to the video. And diversely as always, if you have some problems with your code, something is not compiling or you just have a question regarding the video or the course in general, you can just write your comments on that video, and I will certainly answer them. 4. Installing Node & Angular: In this video, we will install NodeJS Angular on your machine. As you can see here, I am on the official website, Node js.org, where you can download now chess on your machine. If you don't have it installed, you can check if it installed on your machine. If you just write node minus version inside your console, if you are getting the version like 16, it is totally fine if you have something older, I highly recommend you to update your Node version. But here's the important point, is you can see we have two versions. First of all, 16 LTS and 17 current. And you might think, okay, I need to install current. And they can't recommend you to install current because long-term support version is typically much more stable. This is why for all my projects, especially if they're shipping on production, I'm using LTS node version, which actually means if you're jumping to this website and you see like LTS version may be 17 or 18. I still recommend you to download of Ts and not current and it doesn't matter on what operational system you are working. No, this work in everywhere. You simply download it here, you install it on your machine, and then you check inside console with node minus version that is successfully installed Node on your machine. You can also type here and Pm minus version to check that npm is also available for you. Our next step is to install angular and actually to work with then globe, we're using tool which is called Angular CLI, which actually means this is the tool which helps us first of all to create an Angular project, then generate different modules or components and do a lot of stuff with Angular. So how we can install Angular CLI on your machine, as you can see here, I'm on the official website, Angular slash CLI, and here is the first step installing angular CLI. And we can simply copy this command which will install globally Angular CLI on your machine. And as you can see for this, we're using npm, which will have after installation of known chairs. This is where here I can simply throw in payments tau minus g Angular CLI. And I'm installing globally Angular CLI on my machine. Now we must check if our Angular CLI was successfully installed. This we can just write in G minus version and here is some important information. First of all, we can see that Angular CLI is version 13, which actually means we installed angular 13 here on our machine. Secondly, this is our node version which is activated on your machine. This is npm and this is operational system. And some versions of the Angular that you can see here. If you see such output, it means that you successfully installed Angular CLI on your machine. The next step is to generate front and part of our application. As you can see here, I am inside him be folded. And they didn't create our project here, which actually means we rarely create everything from scratch. So what I want to do here, I can just try it MK deal and then the name of our project, L Trello. And actually in this project we're implementing the clone of trailer. This is y. Here is just a name with a nice prefix and WSSE, you can create a folder not from the terminal bud, just in your file manager. Now, I want to jump inside our ultra law folder. And here we must create two different folders because we want to separate our backend from our front-end. And you might ask, why is that? And actually for different reasons. First of all, it is easier to split your front-end and back-end if you want for some reasons to put them later in different repositories or maybe even different teams. Secondly, if we separate them to different folders, then it is not a monolith, which actually means we will for sure not inject some stuff from the backend inside front-end folder, and vice a versa. They are really isolated and separate it as they need to be in the real application. This is why here I want to create two folders. First of all, it will be client, and secondly it will be server and insight client. We will have our angular application and then says server. We will have our known gs with Express, which will be our back-end application. Now we can generate our angular application, as you can see here in the documentation, we simply run in gene hue and the name of the folder. Then we just jumping the folder and we start our server. But here we have a problem because we're directly created our client folder and we can jump now insert client folder, which actually means we can't create our angular application with engine you because folder already exists. For this, we can use a real nice command in gene you. And then here we must provide application name directory, and here is dot slash, which actually means this command will create for you in you application of angular in your existing directory. As you can see here, I am inside client where exactly we want to generate our angular application. And they can paste this command here in gene Hue app name, directory dot slash. And obviously we don't want to name our application app name. This is where here we can provide ELL Trello, just like we named our project after the same hidden Enter. And we started our process of generating new Angular project. And here we get some questions from Angular CLI. Do we need Angular routing? Of course, yes, this is why I'm hitting yes, here, what style sheet we must use. And here I will choose a CSS. After this, our project will be generated. As you can see here, all packages were successful installed, but afterwards we're getting message which might be confusing for you. Here we are getting the message that now was created the branch master as our default git branch. And they might change the name to name later, but it is not there yet. And actually doesn't matter what branch was generated for you, master or main, it will work in any case. So you can just ignore this warning. And the last step that we need to do is we need to start our client application. And as you can see here in the documentation, it is in G serve. So we simply insert client must try it and just serve without specifying anything. As you can see here, we're getting green output. The message that now angular live development server is listening on local host for 1200. So now we can simply open localhost 4,200. And here we see the default angular page and now insert console. Our web server must be running all time while we're developing the application. Now, let's have a look on the files that were generated fast. As you can see here, I opened my editor, I'm in folder L Trello, and we have here two folders, server and client and insight client. All these files were generated with Angular CLI. And the most interesting part for us is this source folder. And inside AB, we have our app component. This is exactly what we see here on the screen. This is default component of angular. This is where here first of all, I want to remove app component, SCSS, app components spec. And here we have just these four files. Now we can jump inside App component HTML, and we really want to remove everything except of this last line, router outlet. This is extremely important fast. So I will remove everything from this file and just live here drought the outlet. And on the top we can just try it. Hello l Trello. So we know that it is working. After this, we must jump inside our app component, change it. Because actually here we're using style URLs from the file, which will alter the removed. This is where we can simply remove this line and we just use here a template. And we don't even need this title L trailer because we're not using it. We simply have our app component and it is an empty component. Now when I will jump to the page inside browser, I can see that everything is removed. Our page is completely cleaned and now we have just hello little trailer message, which actually means we successfully prepare the client part of our application that goodwill implement later. 5. Configuring server: In this video, I want to prepare our back-end part of our project to start implementation. As you can see here, it is completely empty. So what we will create here, actually what we must do, we must initialize package JSON file with known. So here we can write npm in need and it will create for us a package JSON file. Here, we must answer some questions. I typically just hit Enter on all of them. It doesn't matter for us. And at the end we simply hit Yes, and we're ready. Now we can jump and said editor and go outside of our client to our server. Now here we have just a simple file, Beckett Jason with name, version description, main script, where we don't have anything in the empty author and the license. Now, we must install two packages which will help us to create our back-end project. So here we can write impairments style. And after this non demon minus d, What does it mean? First of all, what is no demon? That this is a special package which will help us to reload every single time when we change some file, our back-end application. And this is exactly what Angular is doing fast in the client. But inside our back-end project with don't have some web server which is doing this fast. This is why when Stalin and a demon, and as you can see here, I used minus d option, which actually means in our package Jason, no demon was installed inside the dev dependencies. And dev dependencies are dependencies which we are using when we're developing a project. We don't need no demon on production. This is just for development. And our next package is called Ts node, and it is also only for development. This is where here we're writing npm install Ts node minus t, which means this is a dev dependency. So what is node is doing? This is just a process which will transpire our TypeScript code inside JavaScript code on the fly, executed just like normal JavaScript code inside node. This is extremely efficient because we want to write TypeScript code. This is why we must transform it first from TypeScript to JavaScript. And this package helps to do it in a really easy way. Now let's jump and said Beckett json and check what we have. We have here to dev dependencies. And here I want to create a new script, but don't need the script test. We want here to start our web server. This is y, here is a script style, and here we can call a demon the path to our file. And here I want to write source slash server.js. And as you can see here, we have the server.js, which we will create in a second. So this is the TypeScript file and the most interesting part here that we didn't specify that we're using here Ts node inside no daemon. Daemon does it automatically out of the box if we installed tier snowed and specified here not JavaScript file but TypeScript file. And the last thing that we must do is create ts config file, which is a configuration file for TypeScript. This is way here inside of a service folder. I want to create a new file, ts config dot json. Here I will paste such conflict and this is super typical conflict for Node.js application with TypeScript. So here we're setting compiler options. This is exactly how TypeScript will transpire our code from TypeScript to JavaScript. So module CommonJS means that we're writing our TypeScript on the backend inside noun chest. And our target is atmospheric optics, because node can easily read at my script six code. So our mode resolution is node because we're writing inside noun chairs, move on source maps. This is where source map through. Our deal is directory. Output will be generated. Here we have a dist folder, it will be created automatically. We also have here strict true NDS module inter pop, and we need this option yes module inter Pope to convert correctly are TypeScript inputs to require inside known jazz. So we successfully created our TypeScript config, and now we can create our source folder and inside this file, because as you can see here, our server will live inside source server Ts. So I'm jumping in such source and I'm creating a file server dot ts. And don't forget Ts NodeJS. Now we can jump inside and simply write console log server just to test if it is working. Now, I will jump inside console and here inside server folder, I can write npm start, as you can see here, we've got an output from no demon, which is totally fine. It is washing TypeScript files here and here. No demon started our Ts node source server test, which actually means it simply uses Ts node inside, but it restart our server. And this is the output server that we wrote inside this file. And now Demon Bull restart our server every single time when we make some changes. 6. Installing database: In this video, we will talk about in styling database on your machine. And there's another dimension we will use MongoDB here. So what did the idea? We must install on our local machine database so we can save there and read from there some data that we will use in our application. This data will be available for us on live locally. At the moment when we want to deploy our project to production, we must set up the database on production and we will do it at the end of this course. So now the question is how we can install MongoDB on your specific machine and you can work in different operational systems. So we want something that will work everywhere without hassle. Actually installing the database can always have some difficulties. Here as you can see, I already opened the official MongoDB website with install MongoDB section. This is the URL so you can check it if you are interested, and it looks really easy. We simply choose here an operational system. So here I'm clicking on the link MongoDB Download Center. And I am now here on this webpage. And at this point it is already not really clear what MongoDB we must install. There are different versions of it. There are free versions that we want to use and the rub paid solutions that we don't need. And actually here we must crawl a little bit and see here MongoDB community server. Actually this MongoDB community is the name of the free version of MongoDB that we want to use. So here on the right we can choose the version current is totally fine. Now here is your platform, maybe Windows, and now you simply download it and install. So we're just double-click in here and installing it. But after this, there are some additional steps. We must set up the data directory. Here is you can see they're doing it inside command line like this. And then like this, this is why you can install MongoDB like this. This is totally fine. This is the official way, but actually my students had a lot of problems while using databases with official installation. Why is that? Because actually in every single operational system, you can have some problems. Additionally, you must create a folder, then you must specify the path and so on. It is more difficult. This is why I highly recommend you to look on the second possibility, how you can install database on your machine. And then talking here about DACA and about Docker Desktop. So what is Docker? This is a specific additional tool which you should not learn, but you can simply use it. The main idea is that Docker packs everything inside the container. It is completely isolated and it doesn't have anything to do with your operational system. Docker works on all operational systems and it is free, which actually means the idea here that we're installing Docker, first of all on your machine. And secondly, we use Mongo official image from Docker. As you can see here, the link for Mongo, which is supported by MongoDB itself. So this is not some third-party tool. This is super official and the main idea is that this mongo is packed inside container, so it is completely isolated on your machine and you simply get from the container, the port where you can connect and write data to this container. And this is how it will look like when you start in it. As you can see here on the left, it must be green. And at this point, you know, okay, my Docker is running and for you probably the list here will be empty. This is totally fine. The main idea is that first of all, you start Docker on your machine. After this, we simply jump to the console and we must run such command as you can see here I wrote docker run and after you install Docker desktop on your machine, you can write Docker inside the console. This is the known name, and here we're writing docker run then minus d, which means this must be a detached process, which actually means we don't want to run it here inside this terminal. We want just to detach it from the terminal. Here we specify ports and after this we are specifying name mongodb. And here, Mongo, this name, mongodb is the name of container on my machine. And here what we want to download, this is exactly the image that we will use. Here we're using Mongo 404. You can also use later version here you can check it on the official website of the Mongo or here inside Docker. As you can see, you can click here tags, scroll a little bit. For example, you can use latest or just check the version, as you can see here, the latest version is 507. At this moment, I installed on my machine for 0 for, but that doesn't make that huge difference. Things that we will try it inside MongoDB are the same on all these versions. Now I'm hitting here and, and Docker will download this image on my machine. As you can see, I didn't get any output at all except of one hash. And this is because MongoDB is already downloaded by Docker on my machine. So this is not a problem, and this line simply started Mongo DB again on my machine. And actually if I'm opening now the Docker tool, you can see here contain a MongoDB and it is green because it is running at the moment and we can speak to it. This is why, as you can see, you don't need to create additional files. You don't need to care about some permissions or folders. It simply works. And this is a single line which are used for a lot of projects. Now the question is obviously how we can jump inside the console of MongoDB when it is inside the container. And for this we have a special command, docker exec, which means execute IT. And here is the name of our container. In our case it was MongoDB. And after this we're writing our command and we want to come and Mongo here because this is what is installed inside container. Inside container can be installed whatever. In our case, this Mongo image simply has Mongo inside. This is why we're hitting Enter. We're getting here lots of messages from MongoDB. And as you can see after this, I am now here in the terminal of Mongo inside container, and they can write here some Mongo commands. For example, show databases, semicolon, I'm hitting Enter, and you can see what databases I have here inside. Now, you might say, okay, but I didn't use Docker, installed MongoDB just with the official way, what should they do? And actually you must do just a single thing. If you installed it the official way, then you have two different commands in your console. First of all, it will be one God command, and this will start exactly the same like we did with docker run MongoDB process on your machine, which actually means the database will be as a process running on your machine. And the second command that you want to use is Mongo. This command will jump directly insert console, just like we did with torque. It will be exactly the same. The most important in this course that your database Mongo must be running directly on your machine during the development of the project. Which actually means you have really three things. First of all, you have a standard database. Secondly, have started web server for the back-end. And the last one is the static web server for the frontend. 7. Do you use a good editor?: We are almost finished with subtyping all our tools. And the last question that I want to ask you, do you really use the correct editor? Because actually we will write a lot of TypeScript inside your editor. And the editor doesn't support TypeScript that well, then you might think about using another editor. As you can see here, I'm inside my editor, this is Vim, but I'm not suggesting it to you. I just want to show what I'm talking about. As you can see here where insert component inside Angular and here we have input of our component. Typically when we're writing the code with don't write inverts with just write something like add component or maybe just add than comp. And then we have an auto-complete. And this you can see here we can choose a lot of stuff. We want actually to input component from Angular. He didn't just tend to here. And first of all, it was autocomplete it to the end. And secondly, I got this outer input component from Angular com. And it is extremely important that your editor can do this. You really need support of this outer inputs when you're writing code. Because every single time you must write an input, if you will really do it by hands like input component from, and you don't really remember from what package you must input it. This is not efficient. You simply spend time that you can write code on Ron things. We really need this feature of outer input. And second feature is obviously you want to have a support of TypeScript inside your editor, which actually means when we're writing something not correct. For example, not select here, but just select where getting directly here, a message argument of type select does not exist on type component, which actually means but don't spend time debugging some magic. We simply see our typo there directly inside editor. You can use here any editor that has support of TypeScript. But if you don't know what editor to use, I highly recommend you to look on VS Code. This is completely free editor, which works on every single operational system. You simply install it. You are getting such editor with built-in support of TypeScript out of the box, which actually means you are getting all this features inside your editor. And in this case, it is much smoother for you to write code. 8. Setting up socket with Express: In this video, we're starting with developing our project. And actually the goal of this video is to setup our back-end server with express, MongoDB and socket IO. So let's start. Here. We must install several new packages. First of all, we want to express this is a framework. This is why I want to jump inside console. And as you can see where inside root folder this is drawn, we don't want to install here packages because we first must jump inside our server folder here boop want to install packages. This is where I am right in npm install express. In this case, we're installing this framework as a dependency. Here you can see now we have a new dependency, express this as our framework. The next thing that we want to install is mongoose. And if you don't know what is Mongoose, this is the most popular package to work with MongoDB inside known chairs. Why it is most popular, because you can simply set up your connection to the MongoDB with it, you can create your models and work with MongoDB in more correct way by working with models. So you typically have something like a RAM and we will learn Mongoose steeper in the next lectures. And the last thing that we want to install here is Socket IO. This is why npm install socket dot ion. And this is exactly our library to work with WebSockets inside known chairs. So as you can see, all our dependencies are installed and now we can jump in set source, server Ts, and we don't have anything here. And we can start with configuring our syrup. But actually here is the question. It is really easy to just write your code for Stratton express. Her entity is really easy to create a web server for Socket IO, but actually it is not that easy to configure together MongoDB Express and socket IO. Because what we want from expressed, we want normal rounds, just like in normal application, but we also want to bind to its socket IO so we can work with WebSockets. And additionally to all this, we need somehow to start our MongoDB. So as I said, it is not easy, but this is the production away because actually nobody needs just a single package. We really want the full-blown production ready application. So first of all here I will input our Express. Express. And actually at this moment you probably think, okay, what he's doing. He's tried to an inverse inside noun chairs. And actually this is totally fine because we're not right in here. Javascript, where right in here, TypeScript. And it is transpired with our config. And just to remind you here we have our ts config. This transpired to ECMO scriptSig, which can be readable by now Jess. But most importantly, more resolution is CommonJS and node. This is where it will be converted to require and it will work like a charm inside now jazz. But for us it is extremely comfortable because using inputs is much better than right-hand require. And here we have a next problem. As you can see here, I have an error. Cannot find the declaration file for module expressed. What does it have a mean? Typescript tries to help us with inverse. He can't do it out of the box because TypeScript doesn't know anything about express package. And here is a solution we must install with npm install save-dev, types express. So we can additional install typings for express package and then type script can help us small. And this is exactly what we want to do. We need to jump and set console and right and payments tau. And here is at types slash Express, and here is important minus the option to just install it as a dev dependency. We don't need this library on the production. And as you can see after installation, this error is gone. And now TypeScript can help us with Express. So here we successfully imported our express package and now we can create our application. So I can simply write here const ab equals, and here we're calling Express. And as you can see now, if I'm halite and express, you can see all types of expressed from this specific package. For example, we can read here that it creates an express application and this is extremely helpful for development purposes. The second thing that we want to do, we must create an HTTP server and you will see why in a second. So here I want to destructure, create server from, and here will be http. As you can see, we're getting ATP out of the box and also create server because this is the default node package. But it might happen that you are missing typings for known chairs. This is where we can jump directly in the console and write npm install types node minus t. And in this case we're installing for sure all typings which are needed for noun chairs. So here we imported create server from http. Now we must use it. So after app, we can create our HTTP server. And here we want to call our create server and provide inside our app. And just to remind you, app, this is an instance of our Express. This is our express server. We're creating here are HTTP server. Additionally, the next thing that we want to input here is socket. This is y here, where important Server with big S from socket IO package. And now after this we can directly create our socket server. So here const ion, and here we're calling us server. And inside we're providing our HTTP server. This is exactly why we created this HTTP server first and before are expressed. So now in this file we have three different things. First of all, we have our app, so we can work directly with Express. Secondly, we have our HTTP server, which we can start with some port. The third is our IR, so we can make some WebSockets requests. And just to check that everything is working, I want to use here our app and just try it apt-get slash. So we want to create our new route on slash. And here we don't need anything, but I just want to respond with some string. This is why here we can write request and response. And here inside rest dot send API is up. If you're not familiar with Express, this is how we create just playing routes inside our backend server. So here we're saying, okay, we're creating now get route for slash, which means for homepage. And here is our Kohlberg. Inside of our Kohlberg were getting request and response. And here we can use dot send to send the string to this specific round. The last thing that we must do here is start our server. So here we can write HTTP server. Don't listen and hear. We're providing some port, for example, for 1001. After this, we have a callback. The tower web server is successful as talented. So we can write inside some console log, for example, that our API is listening on port. And here will be our part. And actually it would have been isolated to put the sport in additional config file, but for now it will also go. So let's check if it's working. I have here a tab with open API server. And as you can see here, no demon restarted this web server again and again. And at some point now we're getting our console log API is listening on port 4,001, which actually means even browser, we will open local host for 1001. You can see here our message API is up, but it is not tolerable. Also want to check if our socket layer connection is working. This is why here after EB, we can write ir dot and here we have on. And as you can see, first of all, we're getting all typings out of the box with Socket Layer. We don't need to install any additional package. Secondly, you can see that on the listener function to our socket IO, which actually means we can write here on, and we're providing here as the first parameter connection. And actually this is the default action that can happen inside socket IO. And here we have our callback. We don't want anything for now here, but we can simply write console.log connected. And we can't really see that socket layer is working for us because we just set it a tab on the back-end, but not on the client. But this is a way how we will write our Socket Layer code on the backend and we are fully prepared for it. So here we zap, we're working with Express with a yard, we're working with Socket Layer and HTTP server we're using to start the server. And the last thing that we must do here is setup our Mongoose. And just to remind you, mongooses the package to work with MongoDB. So here on the top I want to input one goes from mongoose. And now here is a really important point. You never want to start your web servers before you started connection to the database. The main idea is that inside you've observer, you will do some requests to the database, and database is not ready yet, then we can do this request, which actually means every single time we want to be sure that MongoDB is, their connection is established. And only after this we're starting our web server. This is y here what I want to write after our socket IO, we can write here Mongoose dot and we have here a method connect. And actually inside we want to provide our mongodb URL. So what I want to paste here is this year, it is MongoDB colon two slashes, local host 27017 port slash l Trello. And actually this part on the left is the default path of MongoDB. And it doesn't really matter how you installed Mongo DB with the official way or with Docker container, it will work exactly the same. Either you have a running MongoDB process on your machine, on the sport, or you have a running MongoDB inside the container with the sport, which is available outside on our local machine. Here after slash, this is just the name of how a database you can write here, any name and it will be created. I just wrote here l trailer, like the name of our project. So this line is actually a promise. This is why here we can write dot. Then after we connected successfully to our MongoDB database, then will be triggered. And now inside we can first of all write that we successfully connected to our database. So I can write here connected to MongoDB. And also I want to move this HTTP listener inside. In this case, first of all, our connection to MongoDB is established. And after this, we're starting our server. Now I want to jump inside our web server and check if it's working. As you can see now, I'm getting message connected to MongoDB and after the semester that our API was successful, the standard, which actually means this is exactly our goal. First of all, MongoDB. Secondly, our web server. Actually, at this moment, you might get some Azure regarding connection here. And the most popular problem that you might have, you didn't start your MongoDB process on your machine. If it is not started, then we can't connect to a MongoDB database. Then here you will probably get some error, like cannot connect to Mongo DB or connection failed. But if you see on your screen connected to MongoDB and the pay is started, this means that you configured everything successfully. And we started our web server on the backend with MongoDB and socket IO. 9. Creating Mongoose user model: In this video, we will talk about creating our user model. Actually now application boot will registered users. So current user, we can login with the user, which means we need somehow to handle our users on the front-end, on the backend and inside database. So in this video, we will focus on mongoose and database. Once again, what is mongoose were already installed this package in R package JSON. You can see Mongoose here, but what it essentially does, this is the official website of Mongoose. You can see here the example. So we inject human goods and we make Mongoose dot connect. And here is a MongoDB database. After this we can write mongoose module cat, and we define that our cat has named string, which actually means cat is our entity. And now we can create this entity just inside JavaScript. This is where here we're right in UK ed, and we provide inside the name. So here we created a kitty, which is just an object. But now inside Katie we have a save method. And this method returns as a promise, which actually means that this is how we will save the record inside MongoDB. Now you might ask, okay, why do we need mongoose? Why we can't simply use official MongoDB driver like mongodb dot save and throw inside some object that we want to save. This is not comfortable to work in the huge project, even in the medium project, it is not that comfortable because you don't have any abstraction. You are writing super low-level code, how you need to save data to database, or how you will read them. Actually, this is why we prefer to use ramps inside our backend projects. What are Ram Dass fast, we define something like models, which are our entities inside our project. For example, we have a user that we have maybe tasks or you have boards if we're talking about trail application and so on. And then we can define which relations between these models. And then all these relations are done in much easier way. We can do it ourselves with MongoDB, which actually means we simply write less code. This is why in this video, we want to focus on our user model. And the first thing that I want to do inside source, I want to create types folder. And actually we're right in here TypeScript, which means we must leverage it. And this is super-important to invest more time in TypeScript then in writing your code. In this case, it will be easier for you to develop your application. This is where here in source types I want to create user interface dot ts. And as you can see here, I have this notation where we have a postfix of what exactly it is. The inside, I want to create our new interface user. And if you don't know TypeScript really well, this is just a definition of the object which we can use everywhere. In this case here we're using Word interface, which is a reserved word inside TypeScript. And here we define an interface user and we can define what fields we have inside our user. First of all, we must create an email, because email is what we're using in the application to register user, validate this user, then send e-mail to the user. Also, we need here a username and it will be streamed and password will be also needed. And obviously we must hash of a password and never stop passwords just as a plane strain. And last but not least here will be created at, we don't need to use this field, but it is really nice to have it, first of all for debugging purposes. And secondly, we can get it from Mongoose just out of the box and it will be date. So this is how a user interface is looking like. Now in our whole application, in our back-end side, we can use this user interface. Now on the right, I want to create a model for this user. This is why in source we can create new folder which is called models. And inside we can register user dot ts, and this is our model. This is exactly something for Mongoose. So what I want to write here is our user schema. And what it means here we define a schema of our model. And for this we're using new schema. And as you can see, I don't have any auto-complete. So let's try to import here schema. And as you can see, I don't have a correct input here. I have another input from inspector, and this is not correct. So I will type here input schema from mongoose. Let's check if we have an error. We don't have an error, which means this was just a problem of my editor. Here I can inspect the schema, which means it is really available with TypeScript inside. Here we're right in your schema. And now inside round brackets, we can define our object, but schema is not what we will use inside the application. It should be a model. This is why here we can write that then export default model. And this model also comes from Mongoose. So let's put here comma model. And here model is a function where we provide our string. It will be user with big hue. And there's a second argument. We provide here a user schema. This is how we define a model inside Mongoose. So here we can export default model we provide here and name and our schema. And here we must define our schema. But we're right in TypeScript. And actually it is not the best way to create new schema. Why is that? Here we highlight our schema and you can see a lot of n is here and this is bad. Why is that? Because we didn't define any type of our schema. This is why what we want to do. We want create a definition of the schema for a user. So I want to jump here on the left and create here expert interface. So it is a new interface for user document. Here is a huge different, we have here an interface for the user. This is just user with the fields and this is use a document. This is what we're using just for mongoose. And here I want to write x tans. And if you don't know what is extends with, simply take all fields from our user here. So I want to write here extends User comma document. And actually this document must be loaded from Mongoose. So here on the top, I need to write input document from mongoose. And actually for now we don't need to provide anything inside. And you might ask now, okay, but doesn't make any sense What did was out here. We created an interface user document. Here we are simply extended user and document. And yes, it makes sense because first of all, we have our interface user. We can use it everywhere. This is our part, but we're also mix it with the document. And document is coming from Mongoose. This is the definition of the document and fast important part is, for example, this AD, because every single document inside mongodb has NAD. And in this case here, we don't need to specify the user has AD, it is coming from the document of mongoose. And now we can jump here on the right and often use schema. We can provide in tanks a user document that we just created. And now I can now to input it here on the top. So it is from our types user interface. In this case here we're saying that our user document is what we need to provide inside our users schema. And exactly the same we can do with our model here we can provide our user document. And if you don't know what this part is meaning, this is actually a generic, which actually means here we're providing generic type. It can be whatever by default it was any. But if we now inspect our schema, you can see that it is not any anymore. Here we have our user document, and this is extremely important for us and for TypeScript validation. Because actually here, now inside what I want to do, I want to throw something which does not exist inside user. For example, let's say that we have inside user property form. And here inside we want to provide the type is string. And I'm saving this and then get in here and narrow that argument of type foo is not assignable to parameter of type. And here we can see our e-mail username, password created add underscore ID, which is coming from document and here to underscore version. Which actually means if we don't try this user document here with don't get any validation of TypeScript. This is extremely important that we are getting it. Now inside the mask provide all fields. Chairman d'etre for our user. And let's start with the e-mail. So here our field is email and then said, We must provide the type, it is a string. Secondly, here we can say required property and as you can see, TypeScript helps us and shows what properties we can provide insight Mongoose. So actually inside required, but can provide an array with some valid data and message. Because actually we want to show on the front-end and nice message when our e-mail is not valid. So it is not just a string. This is invalid email. And for this we can input here on the top validator. So here I want to input valid data for John validator. And as you can see, we're getting an error module. Validator is not installed, so we must jump inside our server. Here I'm stopping web server and they will write here impairments tau valid data, but this is not tolerable. Also want to get types for this package. This is y here at types slash valid data, but it must be installed on in development mode. So here, don't forget, minus t. We can now open on the right, are packaged JSON and as you can see here in dev dependencies I have types validator and independencies validated. Now here we don't have any error for the valid data, so we can specify it inside required. And actually here, I'm a little bit wrong. This is not a field required because instead required with simply provide if it is required or not. In our case, e-mail is required. Here as the second parameter, we can provide an error message if it is empty. And here we can provide e-mail is required. And after this we have our validation. This is where here we have a property validate, and this is exactly where we want to use our validator. So here I can write validator dot and we're getting a nice auto-complete because of the types. And here I will write is e-mail. So here we have lots of validations. And where I get an e-mail validation out of the box. And there's a second argument we can provide here, the invalid email. Last but not least, I want to create indexes. And actually if you don't know what is indexes, These are things which can make your database requests faster. And secondly, it can make, for example, email field unique. In this case, I want to write create indexes. And here as an object, I am providing insight, unique, true what it does, it read our email is unique index in this case, but can't save two people with the same email. So once again, inside mongoose schema, we're providing all fields which we need for our user. And the first field was an email here, but must provide a type inside. And this is exactly the onload line that we need by default. But actually we can provide here required which we can set in true or false here we can provide some validators and we can create indexes. And actually we can do all this stuff just like this inside plane MongoDB driver. This is why I prefer to use Mongoose because it is in a realm where we're getting all this things out of the box. Our next field is our username. So here we can provide our username and it will be easier. First of all, the type will be string, and secondly, required must be true. And here I also want to provide the validation error. This is why we will use the same notation with the array. Here is true and username is required. Now we can copy paste this user because it will be the same. And the last one, what we have here is our password and our password is type string, and it is also required, but here password is required. And the last thing that we want to do is select false. And actually what select false is doing, it will never select this field when we're doing some request. For example, we want to get a user by ID from the database. We won't get this field back. And this is extremely important because it makes our application save. It doesn't matter what queries we're writing. We're always know we won't get a password back, which means we are by default on the safe side. Last but not least, what they want to provide here is timestamps. So we can provide here inside an object and we can write here timestamps, and here we're setting it to true. In this case, our createdAt property will be directly generated by mongoose. But as you can see here, there's a typo. We don't need to provide the subject here. It is a second argument after our object, which actually means in the new schema as a function we're providing first of all, this object with all our fields, and secondly, the object with timestamps true. So this is the second document of how new schema. So we're ready with the first part of our model. But we have a really huge problem here if we will just try to use our user like this. For example, here we can write new user and were provided inside an object with e-mail username password. And after this we will call safe, then our user will directly save this password as plain string. This is forbidden, this is wrong and we should never do this. This is why we must fix this issue. What we can do about it, we must hash our password before we will store it in the database. And for this, we can use a real nice library, which is called the crypt. And this is the most popular solution. Hash the password. This is where we must jump inside console and install this package. So npm installed be crypt jazz and we also want to install typings. So here at types slash be crypt jazz, but obviously it must be width minus t. So let's check the sound. I'm jumping to package JSON. And here I see Types be Christians in dev dependencies and be crypt independencies. This is completely correct. Now what we can do here, we can define user schema dot prayer. And this is the possibility to run some function before something. Here we're interested to provide safe, which actually means we will run our function directly before safe. So here I want to write a sinc function and they will say Why I'm using here function and not arrow function in a second. It is really important to write it like this. And here we're getting Next. And now here we have a brackets and we can do something inside. The main idea is that we can do whatever we want here with our object. And after this, when we change the subject, for example, we must call next and then mongoose will proceed with saving of our data. And pre-sales means that this function will be called, first of all after Create and secondly after update. And this is exactly what we want. For example, we want not just create a password for the user, but also updated later in update form. And the first condition that I want to write here is like this. If not, this dot is modified. And as you can see, we have a function is modified and we can provide insight word, password, and then we want just to not do anything and return next. So what we're doing here, we're checking if our password field was modified. It is not the case was created because there we will have a password, but it is the case with update if suggestions user and we didn't change the password, then it doesn't make any sense to apply this function. This is way here where chicken, okay, if password field is not modified, then we simply say for Mongoose, go ahead. Now as you can see here, we wrote a sinc function and not an error function. And it is important here because we want to use here this property. And to have a correct this reference, we must write it as a function and not an arrow function because another case, this will be run and also we use here a sinc function because the crypt operation will be a synchronous. So after this, I want to write try-catch. And actually if we will get some error, will be crypt, then we're coming inside cage. Here, we're getting our error and we want to return this Sarah inside next. Here we're throwing inside Azure as error. And you might ask, okay, but why is this strange notation error as era? Actually, if you will try to just write like this, we will get an error. Argument of type unknown is not assignable to parameter of type callback error or undefined, which actually means inside a cage, every Azure is unknown, which is obvious because this is sketch and we don't know whatever happened. This is why we're writing catch, but actually we can't use arrow like this and we can provide it inside next, this is why we must convert a type of our era to something meaningful. In this case, I'm using S arrow and we can provide errors inside next function. This is exactly what we're doing here. Now we must try it our logic to hash the password. And for this I want on the top to input our big ripped js module. So I'm inputting be crypt jazz from Big Rip jazz. And now inside our try, we can first of all get a salt. And if you don't know For be crypt where generate and first salt and then we provided in decrypt function to hash the password. This is way here, we need to get a salt. And for this we're Colin be crimped js dot gen salt. As you can see, this is a function which are synchronously generates fast salt. And here we can provide ten, for example. And this is an asynchronous function. This is where here we must try to wait, so it will get fast salt. And now here we must update our password. And actually this function is called before we saved this record, which actually means with this, we have a reference to all fields that we're trying to save. And here I will write this dot password to change our field that we're trying to save. Here we want to assign a weight B creep chess dot hash and actually hash, as you can see here, we'll have our password and inside we first of all must provide our password, this password. And secondly salt, in this case, our password will be hashed and we will just store a hash inside our database. In this case, after we will call next and we must do it for sure, this password will be updated and we will save the clean record. This is why inside we want to write return next and we simply call it, this will trigger the saving for a record to database. And most important part that redraw this logic inside modal sold this logic with saving is completely isolated inside model. And when we will write some code which is related to the user, we won't even know about this logic. It is all inside the model. It doesn't have anything to do with finding a user or saving the user. It is what is happening inside model. The last thing that we need for future is the function validate password. Why do we need it? Because actually when we will try to login the user, we want to compare not only e-mail, but also provided password. And we have a really nice thing which is called methods inside Mongoose. So here we can write user schema methods, and here we want to create a new method, for example, validate password. And actually it is working in exactly the same way, like for example, methods inside classes. So we can call on our instance of our user. This method validate password. And here we must provide the function. And again, I'm not writing here arrow function but just a function here insight by getting password as a parameter. Because actually when we want to compare a password, we will provide something that we want to compare. This is y here password is a string, and here inside we want to compare the provided password with our password inside our instance. So here we can simply return be grip js dot compare. And this is a function to compare, first of all, a plane password which is provided from outside. And secondly, our string, and this is this dot password that we're storing as a hash inside our record. So our latest usage will look like this, where right in here, for example, that we have a user and we want to save it. So here we have a new user. We must provide inside our email. Then we must provide here a username, and then we will provide here a password. After this, we will try to save a user. So here we will call use. It does save. And actually after Colin this thin, our press Save will be called and we will store correct password. But after this line, we can also write a user dot validate password. And here we can provide any password that we want to compare. This function will return for us true or false depending of the correctness of the password. And this is fully correct to do all this stuff inside User model and not inside some controllers where we simply work with users. Because in this case our logic is completely isolated inside user. And now we're missing just a single line here inside our types user interface with defined user document. But actually we must specify inside this user document that we wrote here a new method, validate password. This is why what I want to do here, I want to create a new method inside validate password. And we know that inside we're getting some parameter, we can just name it param1, and this is a string, and we know that back we're getting a string. In this case, I will use a document is completely correctly typed and we can use it later inside TypeScript to call this validate password method and get autocomplete. 10. Adding registration: In previous video, we successfully created our user model. And they can understand that previous video was really dry because we just created a model and you didn't see how we use this model in a real application. This is why the goal of this video is to create our register method, which means we will register user, and this is exactly how we will use our user model. So let's look in our code. For now we have just a model inside source models. And what we want to build is MVC architecture. What does it have a mean actually inside expressed as a framework. Don't have any architecture in expressed with simply defined some routes start web server and we're good to go. We don't have a lot of rules which are defined inside expressed. This is why we must do something on our own. And the really popular architecture which use nicely our back-end project is MVC, which actually means model view and controller. And actually 90 per cent of the cases, we will just use models and controllers. We won't use any views just because we're working and creating an EPI and we don't need to render views there. We just respond with the chasten and this is it. This is why my idea is to create a new folder which is called controllers. The main idea is that here instead sorority S will register all our routes. For example, here we have a route for the homepage. The main idea is that we're not writing the logic of this route here directly as a callback, we will write it in site-specific controller, which actually means all our requests we want to split in different controllers. For example, we have a user controller and there were riots in all our actions regarding registration, login in, getting user login out, and so on. Then we have a board controller where we will write inside everything which is related to board. The most important part is that inside model would define how we're working with the database. So we create our entity like user, but inside controller way using this entity. And we're building some responses of our API, which actually means we're separating our logic. Everything was database is going to models, but we're using models in such controllers. So this was the theory. Now let's create our first controller. And for this I want to register here in your route, and it will be a route for registration. This is why here we have app post and the URL will be slushy pie slash users. Here will be our users controller dot register. So our first rule here is that all our URLs, we'll start with slash api, because actually it is really nice to have a namespace for our API. Secondly, as you can see where not important, something like register where inputs in here the whole user's controlling and we need to have some good naming. The typical name and for controllers is always with asset than for example, a user's controller and not user controller. Now let's import star as users control it. And if you don't know what this is doing, the main idea is that inside we will have a bunch of functions. And this time as groups, all these functions inside this object. And then we can write something like users controller dot register. So here we want to import it from, and here we have our controllers slash, and here we will create file users. And as you can see, it doesn't make any sense to name this file users controllers, because this file is situated directly inside controllers. This is way here, Let's jump in so it controllers. And here is users.js. And this is our file which is a controller. And then say it was right, all actions which are related to the user entity. Now on the right, I want to open our server Ts. And As you can see, actually this part that you can see here is what we're writing inside controller. So this is our callback. And as you can see, this is just a plain function with the request response. And the third parameter here can be next. This is why what I want to do here, I want to create a function which is called register. And this is an asynchronous function. Why we need here in a synchronous function, because we will work with database and those requests for our database or as synchronous. And here we're getting as an argument is first of all request, secondly response, and the last one is next. And this is just a function. So this is exactly the same what we're paste in here directly, but we just moved it outside, inside our controller. But this code is bad. Why is that? Because actually here we didn't type our request response. And next, so here I can write colon, and here we have our request. And this is the most important part. Here we have request which is coming from Fetch API. We don't need it, but we need is request which is coming from expressed. This is y here, import request from express. And as you can see now we have completely different definition. We have here inside dress, body, request body. And this is exactly what we need. Also, we need here not only request but response, and I'm in Britain here also response. Type in here response as a response. And the last one is not next, but next function. Here, our two input is correct. It is from expressed. So this is how we typically will create a new action of the controller. Doesn't matter if it is user controller or it is some article controller, it will be always the same. Now, directly inside they want to write try-catch. Why is that? Because actually we will write a synchronous code with async await inside this function. And we want to handle all errors. And the easiest way was expressed to handle an error is by using next, and we're already used it previously inside our model. Here it is working exactly the same. So we can write here, try and we have cage and we're getting some error. What we want to do, the one to call here next and throw inside the error. This is it actually, this is a single line which will propagate our error to express, and then express will show the Sarah on the screen. Now inside we want to create a user because actually this is the registration and registration means simply creating a user. This is why here I want to import the user model from. And here we have our models slash user model that we created previously. And as you can see here, I didn't name it user with capital U, but use the model. This is just to be crystal clear inside of our code that we're working with model. And now we can use this model inside. So we can write here const, and here is new user, because here we want to register a new user and we're right in here in hue user model. And now inside we must pass some data. In our case, we must pass here in male than username and password. So here we want to write that. We want to set an email, and this is request dot body dot email. Then we want to set here username, and this is request dot, dot username. And the last one is password, and it is request dot body dot password. But here we have a huge problem. By default, express can't work with boiling and by default express won't pass it a tau. This is why what we must do, we must install additional package for this. And this package is called bodyParser. This is why I will jump inside the console and be aware here I'm inside server. I will write npm install. And here we want to install bodyParser. I'm hitting Enter and the package is installed. Now we can start our server again and jump back. So the main idea is that here instead sorority S, I will import my body parser. So here let's name it bodyParser with camelCase and we're importing it from package bodyParser. Now somewhere here before we're doing our routes, we can write ab use and inside we want to try it bodyParser dot json. And actually here you can directly check what bodyParser Jason is doing and it returns a middleware, the tone lip parses JSON and this is exactly what we want. We want to pass our JSON, but it is not only this, but also want one more IPOs body parser. And here will be dot URL encoded. And inside we're providing extended through what these two lines are doing. First-line will just look for content type application json and then parents of a body in the JSON. So we can work with our body as an object and this is extremely easy. The next line we'll do exactly the same but for URL encoded strings. And then we will also get our body. So with this configuration in every project, you can work normally with the API where you have body as adjacent. And this is exactly what we're doing here. We're reading body from request. Now I want to console log here our new user so we can check how it looks like. And after this, I want to try and save the user. So here we can try it saved user, and here we can call a weight in your user dot save. This single line will create France new user inside database. This is why here I want to console log saved user, coma, saved user. Now I want to use such tool which is called Postman to make request. And if you don't have postman on your machine, you can simply jump to Postman. Don't load it here. It is completely free. It has paid tiers, but we don't need them for our course. Here, it looks like. And actually what we want to do, we want to make a post request to our URL. And here we have our local host for 1001 slash slash users. Now here we must jump to body and select here wrong. And on the right we can say that this is adjacent. Now what we want to pass inside is an object with three fields. First of all, we have here email, for example, foo at gmail.com. Then we have our username field, for example foo, and we have our password field, for example, 123. Now let's send a request and check if it's working. As you can see, the request hangs. And this is completely normal because actually here but didn't call rest Jason for example. This is why it is handgun. But now we can jump inside console and this is our output. First of all, here we can see our new user. This is before saving. So this is what we have after Colin, new user model, which actually means we're throwing inside these three fields and we're getting user from one Goose. And as you can see, the main difference of our object is that we have here NAD, which is a MongoDB AD, and it was automatically generated fast. And actually after this, we can use this new user and save it, for example, to database with dot save method, which is extremely easy. And the most important part is here saved user. This is our saved user, which comes from the database. How we can tell that it is already saved. First of all, here we see our password and actually our password here. We gave like 123, but here we didn't save it like 123. It is a hashed password. Why it is happening? Because actually we define the model and here we have a method press Save. And just to remind you, here we generated a hash from our password and we save this hash with the crypt instead of password. And this is extremely important pattern. We don't want to write here any logic regarding changing the password to the hash. It doesn't make any sense because we want to define model with some logic. And then it happens magically because it is defined. In this case here we save, we just changed our password and hash and inside of our controller with don't know anything regarding it. The same goals about this fields created at and updated at. These two fields were added for us because here we defined timestamps true. So our user was successfully saved to MongoDB. But actually we can't just throw the saved user as a response. Is that first of all, we don't need all fields and for sure, we should never give this password outside. And actually just to remind you here, inside our models user, we said that password is not selected, it is selected false. But actually after we saved user here, this password is given fast back. And actually if we're doing some fine, we won't get the password field. But after saving the user will obviously is getting it. This is why we must create a nice response which fits our needs. This is why here I want to create additional function, normalize user. And here we're getting user and we know that this is user document. And as you can see our user document, we can input from types user interface. Just to remind you, use a document is just how a user object with ID and validate password method. And as you can see here, we can inspect new user and we can see that this is use a document and the property, this is exactly what we're passing here and here inside this function, we want to return the normalized for API user. So first of all, here we will have an e-mail, this is user dot email. Then we want our username. It will be used username, and the last one is 80, it is user dot ID. And just to remind you, in MongoDB or ladies are stored with underscore ID. But actually here inside Mongoose, we can use them in both ways, like underscore ID and like dot AD. This method already exists and it's simply as references underscore id. So I'll normalize use a function is completely ready and now we can call here eat when we respond with this saved user. So I can simply write here as sand and inside we're passing normalized user and here is our saved user. Let's check if it's working. We don't have any errors here in web server. I will open here Postman and hit Send again. And as you can see with successful in normalized our user and we didn't get here, for example, password back, which is extremely important. But here is something that I don't like about our responses. Actually, we did some validation inside of a model. But if I remove here username and hit Send, we're getting here 500. And this is actually HTML page with some validation here. This is not what we want, what we can do here, we can use the sketch and read messages from our era. But the main problem is that our error is not always validation error. It can be, for example, 500, but we can also get validation errors. And the most correct way to check it inside TypeScript is like this, where right in here that are Azure is instance of Azure DOD validation error. But here it is important to input error correctly because we want to import this error from Mongoose. So here I am inputting our era from Mongoose. In this case, it will be treated correctly because actually here, era that validation error is a class of mongoose. And if we got any validation errors of Mongoose, we can work with them here. Now let's just try it inside console log and check what we're getting here. I will hit Send again. And as you can see inside the console, we're getting here errors. And this is an object. Which actually means we can read messages from the subject and show them on the screen. Here I want to create a property messages. And here we can write object dot values, which will read off values from our object. And inside we're throwing error errors. This is exactly what we're getting from mongoose and we want to go through every single field. And here we're getting error and we just need error message. So this will be an array of strings. Now we can simply write return risk status, for example, four to two, which means unprocessable entity. And here dot JSON messages, which actually means here when we're getting any validation messages were answering with this status and we're showing this error messages, we don't have any errors in the console. So let's try again. I'm hitting here sand and we're getting a nice error messages. Username is required by this happening because here we checked inside cage, for instance, of the class, we normalized our messages here and we responded with them. And actually it makes a lot of sense to move this function later to some helper because we will do exactly the same stuff again and again, where we have one goes validation. And here is the last step that we want to do. We actually need for our client to provide a token, which actually means when our user is logger tin, we generate a unique token to make a DVT authentication. What does it mean? We have a special string token which were throwing on the client. And then client can attach this to be t to the header. And later we will check if the request is authenticated and diffuser is allowed to do some changes. But in this video, we simply need to throw inside our response, the GBT token that we will generate. And for this we must install additional package. Here I will write npm install JSON web token. And it is not only it will also want to get typing. So here will be at types slash JSON web token. So we installed two packages and then restarted my web server. Now let's jump back in. Here we want to import now our JSON Web Token, or just DVT. So let's try it here in productivity from JSON web token. And now what we want to do here inside normalize, and this is the best place to do it, because here we have the whole user and we're building something which is not related to the database. So we want to generate here our target. And for this we're just Colin, GBT dots sign the inside. We're must provide a payload and some secret key. So what do we show insight payload here? First of all, we want to get an AD and this is user dot ID and then an email. It is user.email. Actually it is enough for us to provide just an ID so we can find later use it by ID. But email is also nice to have for some validation and understanding with Susan and what is secret here. It is just some random string which will help us to decode and then call tokens. So what we want to do actually want here inside those services to create a new file. For example, config dot ds. Here we will store all such needed properties like for example, secret. So here I just want to export, const, our secret property and they will name it secretes, obviously for production reasons you want to have here something more secure. Maybe some long hash like 12 symbols are. So now we can use the secret here just by inverting our secret for John. And here we have our config file. Now, instead of this secret or private key, I will just write a secret. So what this line does, it generates a token which is just a string. And now we need to add here to our response, that token. Let's check if it's working, but don't have any errors. Let's jump inside. Postman, hit Send. As you can see here, I must provide my username. So for example, for, let's check this out. Here we get all our fields and also talking. And as you can see, our token is just a unique string that we will attach to all of your requests on the client and decode back on the backend, which we will do in our next videos. So we successfully implemented our registration method also with validation and with normalization for our API. 11. Implementing login: In previous videos, but fully implemented our register method in this video, we want to implement the beginning of our user, but actually I want you to try and do it yourself because it will be super similar to registration and we're already prepared everything. So what do you need to do a toe? First of all, insights server.js, you want to create a new route. And actually here we already have our route for registration. Now we must create one for login. For example, we can create a string slash api slash users slash login. Now here in such controllable must create new method login. The question is obviously what we will get there and what this method must do. And actually insert Postman, we can just try to use it. So here you will have slash login and instead of e-mail, username, password, we simply throw to our request email and password. We don't have username because this is login and email is unique. And here you have two possible variance, how you can implement it. First variant is easier. You simply want to read an email from the body. You want to try and find the user inside database and return this user back. And actually don't forget to use normalized user because we need that talk. And also, if you want more difficult approach, then you can also try and validate not only e-mail but also password for this validate method inside our model. But even if you try to do the first step on your own, this is totally fine. If you want to implement one of them, just pause the video now, and now, let's do it together. So our first step will be to jump inside or sororities. Here we want to create a new route. So we have here a post because this is a post request following Guinean. And here we have the CPI slash users slash login. And here is our users controller dot login method, which we will create in a second. Now I will jump in save controllers user and they won't copy paste anything because we want to try and write it from scratch. So here we have our login method and we know that this is an asynchronous method where we get our request, which is request exactly like on the top inside registration. Secondly, we have here our response, which is type response. The last one is next, this is next function. And now here inside of our function, we want to write, try and catch. So inside cage here we will get our era and they just want to propagate it to next era. Why is that? Because actually here we won't have any validation rules, but we'll just check, oh, validation inside our try and not inside catch. What do we need to do inside? Here we're getting our request body with email and password inside. And our first step is trying to get this user inside the database. Here we can write a K. We need our user and retry with a weight user model dot find one. And as you can see here we have find by ID, find and find one. So actually using model.fit find tries to find all documents as an array by some predicate. For example, here we can find a list by is active field. Here, find one. We'll do the same but fine, just a single record. This is what we want to use and sometimes we will need to find an element by ID. Here we have a nice fined by the method. And as you can see here, we also have lots of other methods, like for example, find one and delete and update and so on. But for now we will use find one and then said We must give a predicate as an object. And here we have our email and this is request body e-mail. So actually this single liner will try to find our record inside user's collection by this email. Here as you can see where getting user document. But actually this is not true because we can get here now and not a document because maybe the female does not exist. This is way here. I want to check if we don't get a user, then we want to throw an error. And for this we can simply return our response dot status. Here we have photo to status just like previously. And here we want to throw some JSON back. And actually here with don't have a different validations. In any case, we simply throw invalid login or password. This is way here on the top. I can create and save to the object our errors. So here I want to create errors. This is an object with field, email or password, for example. And here the value is incorrect email or password. So the main point is that we have exactly the same structure of our errors, just like we have in all other places. Here, we're just returning our errors back inside of JSON. If we don't have a user. After this, we can respond with our users. So here is sand and here we can call our normalized user and were provided insert user that we found. And actually, if you wrote this code even without this error, check your golden, because you tried to do something by yourself. Now let's check if this code is working. So we don't have any errors here inside web server. Let's open our postman and hit Send. And as you can see here, actually it is already working. Here is our slash api slash users slash login. This is post request with our two fields. Here we're getting bank the correct user with the Tonkin. And actually if here, our email does not exist, hidden send and we're getting an object with email and password, incorrect email or password, which actually means we successfully implemented our lung Kenyan of the user. But here we're missing just one small thing, and this is validated of the password, but this is extremely easy to use Just because we already prepared everything inside our model. And just to remind you inside our user model here on the bottom, we have this validate password method and we're using here be crypt compare, where we're comparing the password of the user with some string. This is exactly what we want to do here. We can just create a variable is same password. Here we want to call user dot validate password. And as you can see, we have here our autocomplete of the TypeScript. And actually we are getting this autocomplete just because inside our user interface document, we wrote this line. If you didn't write this line here, then you won't get these auto-complete. So here we have our validate password and inside we want to provide a string to check if it is correct. And this is request body password. And actually if this passwords are equal, then we will get here Boolean. But as you can see, we're getting a string, which means something is wrong. Let's check our interface. Validate password returns a string, it is wrong, it should be Boolean here. Now is same password returns false boolean. And here we can write some condition. For example, if naught is same password, then we want to throw exactly the same error. So I will copy paste here. Since status for the two JSON errors, Let's check this out. I'm sitting here sand and we're getting this nice user. But what will happen if we will throw here incorrect password? I'm hitting here send and we're getting an error. So let's look inside console. Here we're getting quite a strange message, illegal argument, string undefined it. And as you can see here in our stack trace, it is coming from our controller and hear from our source Model Ts line for default. So let's jump inside our model Ts line 44. As you can see, this is our big crypt compare. The question is, what is the problem? This is why what we can write here is validate password. And here we have first of all, our password and this password. And actually I just want to see here this, to know that we are on the safe side. Our server is restarted. So let's check the sound. I'm hitting send endless look inside console. And as you can see here, the finer we see, first of all, validate password. This is a string and here is our object. But as you can see in this subject, with don't have password, this is why we can't compare object with the password because we don't have a password. Why we don't have it? Because actually here on the top, we said for the password, select false, which is completely correct. In 99 per cent of the cases, we don't want to select a password because this is safe. But actually in this specific case, in this login method, we can't work without password because we need to compare our password of the user. This is why what we can do, we must assume this find one. So it also gets a password. And for this we can write dot select. Here is a string inside we're writing plus password. And actually this is a really nice notation because we can use here plus password, minus biography and so on. If we want to remove or add specific fields, in this case, just for this specific request, we're getting not only the whole user, but also password field. And now if we will try again, I'm hitting sand. We can check and said console. And now we're getting our user with password, which is hash, and then we don't have any error, but it is not working correctly because here I have a wrong password and we still are getting user, why it is happening. And actually, if here we will look on our validate password method we're using here big crypt compare. The question is what we're getting back in here, we can see in the Taipings were getting promise Boolean. And this is extremely important. This is an asynchronous operation. It is not synchronous. This is way here we must jump back inside our types user interface. And here we can say that we are getting the Boolean. It is actually Rami's of the Boolean. And now it is completely correct because now if we will jump inside our controller here we have used the validate password. We see that we're getting back promise Boolean Now is same password is promised Boolean, which is not what we want. This is where here we can write a weight and this will resolve our promise. And here we will get our Boolean. As you can see, TypeScript really helps us a lot in understanding correct typings. And we can always check what type we have. Here. We're getting the same password and now it should work. Let's check this out inside Boltzmann. I'm hitting sand and we're getting a message, email a password or not correct. Here with the correct password, 123, we're getting back our user and this is exactly are implemented login request. 12. Creating auth middleware: In this video, I want to talk about middlewares. So what is Middleware? Typically when we're making a request from the client to the backend, we simply throw this request inside our route. And then inside controller, this is exactly what we did here inside our source server. So here we have two post request, register and login, and we simply jump inside our controller, which actually means here insert controller, we're getting request and response. Middleware is something which can be called before we're getting here, which actually means middleware is being applied on the back-end, but before our request is colon inside our controller or inside our route, Kohlberg, by doing it middlewares at all. If you need to do something with request before this request is get into the controller, this is exactly when you need a middleware. Middleware, do we need in our project? This is the authentication middleware. Why do we need it? Just imagine that every single time when we need to do something with Strategist at user, we need to check his token, which actually means in every single method, like for example here register, we're getting the token of the user. We must pass this token. We must validate this token, and we must find current user with this token. And it doesn't make any sense to write this code in every single controller action. This is why we must create a middleware which we will reuse everywhere. This is why I want to jump here inside source folder and create here a new folder, which is called middle. Whereas here we can store all our middlewares. And the first middleware that we're must create is owls dot ts. And actually, what is Middleware? This is just a function. This is why here I want to export default and the synchronous function. And you might ask, okay, But why it is a synchronous? We simply get here our request and within do something with it. Because actually here we want to also work with the database. If we have a token, this token is valid. We want to read an idea of the user from this token and get this user from the database. So we can use this user that will be prepared inside our controller later. This is why it is an asynchronous function. Here we're getting a request response. And next, exactly like we did previously, here, Let's type our request, then we have our response. The last one here will be our next function, which will be next function from R expressed. And here I will invert on the top our request and response. And this function does not return anything. This is why it is a void function. And inside this function we want to read the token from our request, but I won't directly to wrap all our code with try catch. Why is that? Because we will try to make some asynchronous request to our database and it might fail. This is why here it is a good approach to write try-catch where we're getting our arrow and then side catch. We just want to make risks and status and here will be 401. You might ask, okay, but why we didn't show an error here? Because actually we don't care. This is a middleware to check our authentication. If for some reason we can't parse the talk and talk and listen, valid. We couldn't find this user in any case, it means that our user is not logged in. This is where here we're directly our 401 status. Now here we must read our status. So here I want to create our header and we can get our header from request dot headers, dot authorization. Actually this means that we will store our token inside our authorization header. And actually a typical approach, hope we implement our duty authorization is we have here authorization key, this is our header and the value here will be Bearer space token. So here we will have some unique stream. This is why we must split our token accordingly. But first of all, here we read our header and it might be that it is not set. In this case, we simply can say for 01, this is y here. If we don't have our, our header, we simply can copy paste this line with rests and status for 01. After this, we really need to parse our token. So here we will get our talking and this is our header split, and this is just a string which was split by space. So we're getting array with two elements. As you can see here. In the first position, we will have better. And on the second position it will be our string. What we want to get, this is where here I will take the second element of the array and it will be our token. But as you can see here, we're getting the message from the TypeScript. That object is possibly undefined. And this is why I like TypeScript so much. It helps a lot during development. What does the problem? Actually here we have our IV and dress and status, which actually means we won't come here. But TypeScript understands that we will come here because actually we didn't try it here, return. And this is why this code is invalid because in this case here, our header can be strain or undefined it. But after this correct check with return, it can be only a valid string. So the next step that we need to do is verify our token. By using GBT, this is way here, I want to import DVT from JSON Web Token. And just to remind you, this is a library which we used to generate a token on the backend, and now we need to validate it. This is why here we can just try it that we are getting some data from our token. And here will be GBT verifying the inside. Well Python, first of all, a token. Secondly, our secret key. And just to remind you here inside our config, we have our secret. This is why here I will just try it secret and it will be out to inputted from our config. And we don't need to provide hear any additional options. But if we will check here our data strain or DVT PE lot, but actually we know that this is not correct, this is not what we're starting inside. If we will look here, inside our controller users, here we generated our token and inside we have ID and email, which actually means it is valid here to say after derivative verify as. And here we can say that we are getting back an object with a D string and also our e-mail, which is a string, in this case here now in data we're getting correct database. This is an object with a D and D mail. So we're getting here the idea of the user and now we can try and fetch it from the database. But for this we need to use our model. This is way here on the top. We can import our user model from our models. So here we can jump back inside our models slash, and here we have our user. Now after our data, we can make a request to get a user back. And actually here we're using a weight. Here we will have used a model dot. And here we want to find user by AD, and we have this function by default inside mongoose. And here instead of a div, we can write data dot AD, and this user will be there, or it might be now, this is where we'll also need to check it. If we don't have a user back, then we want to also say that user is not logged in. But if everything is fine, then we want to set inside request our user. So actually the main idea is that this request will be updated by us here. And then later when we're calling next, this request will get to our controller and then we will have direct access to this user. This is way here, I want to write request user equals user. And this is this user that we got from the database. And after this romance, just call next. And this line is saying that we're ready with our middleware and our request can proceed to our controller. But here we have a problem, as you can see here, where I getting an error property user does not exist on type request and actually it is completely valid. This request is coming from express and inside expressed there is no field user. So what we can do here, the Ron approach will be to write here any and I highly recommend you to avoid using any in your projects because then TypeScript can't really help you. You simply have your code with holes of plain JavaScript. This is y here, Ras as any, will be a super bad approach. Why is that? Because here we simply say, we don't care what is about requests. We simply say it is any dot user and it is working. This is the beginner approach. We're not writing code like this. Here. Request user is totally fine, but this request should not be requests from express. We must extend it. And actually here inside types, we can create a new type and let's name it express request dot interface, dot ds. Now inside I can create this new interface. And let's name it express request interface and actually it must extend. So here is extend request. And actually this request will come directly from expressed. So here on the top I can write import request from expressed. So what we're doing here, actually we simply created an interface and we extended everything that we had inside request to our interface. And now here we can simply say that we have a field, the user, which might be undefined it, and this is our user document. Here you might task or k, But why user can be undefined it here we don't have a case where inside request user is undefined it and you are totally right, but we're not using middleware with every single request. Sometimes we won't have user inside our request because not every single request must be authorized. And now we can just copy paste this express request interface and jumping set our middleware and put it here instead of request. So now I need to import express request middleware. We're not using requests from express anymore. We're using the regular are extended version. And now we don't have any errors. And what we're getting here is complete request from express plus our user field. And this is exactly the correct approach to use TypeScript. So we successfully created our middleware. Now we need to use it. And for this I want to create a new route. Well, we will get current user by talking. So let's jump back and say source server. And here we have two posterior rails here. Now I want to create apt-get and we have here slash API slash user. This is the route to fetch current user. Now after this with comma, I want to write out middleware. And actually in this file we didn't declare what is our middleware. So we need to input here our middleware from our middlewares. So here we have middlewares hours. And this is exactly what we will do. If you are writing like this, then you will apply this middleware before we're colon here controller. And here we will get our users controller dot, for example, current user action, which actually means first of all, in this route, this owls middleware will be executed if we will get a user request is go into the controller, then where champion here. And as you can see with express, it, quite easy to read and understand. Now I want to jump inside or users controller and create this new method. So let's on the bottom, create our new function, which will be a current user. And here we know that we are getting request and response, but important, but here we're not using requests from express, we're using our extended version. So here I will write that way I get an express request interface. And the next parameter here will be raised response. It is staying the same like previously. And here inside of our function we must apply some logic. What we want to do here, actually inside current user, we can directly get this user from the request. Here we can say dress dots and normalize user, just like we did on the top. And here we'll request that user. And actually it will work mostly because what we're doing here, we're using our user from the request with throw it inside normalized user. And just to remind you, we have normalized user here on the top. And this is just a normal user document. And we generate here talking our response and we send it back. But actually here we have TypeScript. What does it mean? Here we're getting an error argument of type user document or undefined it. He is not assignable to use a document. And this is completely valid because we said that inside our request with don't always have a user. And actually the point is that this logic will never happen because inside our server here, we'll roll this middleware, which actually means if we don't have user, then this house middleware will return for 01. But TypeScript doesn't care about our middleware because it simply reads our function. And if I'm just looking on our function without our middleware, then our code is invalid by that, because here we're trying to throw undefined it inside normalized user. And to handle this for TypeScript, we must try it here. With don't have a user, then we want to throw 401. So here we can write return, res, send status, and here inside for 01. In this case, it is completely valid for TypeScript because here in request user, it can't be undefined it with did this check here? And actually this code is much better because in this case here we have this single function and we can completely tested in isolation, but don't care in this function, what we did outside with additional functions, middleware over terror with simpler note that this function will work correctly in every single case, because we covered all cases here, our function must be correctly implemented. Let's check if it's working. I'm jumping to the server and we have some error. Let's check what we have. And actually here you can see that it was the era of TypeScript and the last compiling was successfully. We started the observer connected to MongoDB and here is our API. So we can jump directly to Postman and try to make a GET request. But inside our request, we must provide a token. This is way here. I will copy paste to talk in because we must use it. And for this I will create here GET request. And this is slash api slash user. I'm just hitting here sent. And as you can see, we're getting here unauthorized. Why is that? Because inside authorization with didn't provide a valid token. But if instead of this string, I will paste our talking so Birra than space. And then we have our string, I'm hitting here send, and it magically worked. And here we're getting our normal user with the Tonkin. But most importantly is that we didn't try it. All this logic with getting current user here inside this method, it is written inside middleware. And now we can use our middleware in every single place where we want to check for current user or if we need the current user information inside our controller. 13. Creating auth module: In previous videos will always be prepared some requests of Pi for our registered user and gating current user. So now it wouldn't be nice to start implementing something on the front-end. This is why here I want to jump inside our client. And here I want to start with our user module. And what we will have in our user module is two pages logging in and registering. But it is not enough to just have two pages for registering and logging in inside of our module, we'll also need a service to work with current user. For example, we need to register user, login user, get current user, and so on and up this loop, we need an interface for our current user also, this is where in this video, let's focus on creating basics of our authentication module. For this, I want to jump inside our source app folder. And here I want to create a new folder. Here we want to isolate everything, which is speaking about authentication, registration are beginning. Our first step here is to create a module. And if you're not that familiar with Angular, just two words about modules inside Angular, inside the other frameworks like for example, react, we simply use imports and exports, Bot Insight angular, we have much more, we have dependency injections, which actually means the whole application is splitted in different modules. For example, in our case, we're defining here and now module. Now we can create different things inside this module and they will be isolated inside this module. And we can define what we want to expose to use outside. And if we didn't expose anything for using outside, then we can't just use the stuff from this module. And this is really a nice approach for huge applications. Let's create first of all, our, our module. For this, we need to export our class, our module. Now on the top of this class we want to provide an NG module decorator. And inside we will pass different things, but for now we don't need to register anything here yet. What I want to do now I want to jump back inside our app module, because actually we must register this module inside our app module. In another case, this module is not bind it to our application because we're just loading a module and we must lot all children modules also inside it. This is where here inside in birds, we can simply write our module. And with this line where get an auto input here on the top. And now we're sure our module is loaded. Our next step here is to create a current user interface. And from my point of view, it is completely unrelated to the owls module. So here we can create a new folder types and register here, current user interface dot ts. And inside our Express project, we didn't have any rules about file naming because there we had just expressed and everything that we're writing, we simply write with our own guidelines in say the angular, it is highly recommended to name all our filenames, Start and then postfix of the entity. For example, here we wrote out dot module because it is announced module. In this case we're right in here, dot interface because it will be an interface and exactly the same goes about classes. Here we're not writing class owls, but our module. And here inside currentUser, we're right in here, expert interface, and here we have our current user interface. Now the question is what we will get inside? And it is easy to answer that we just need to look inside our Postman. So here we're getting back for our current user, e-mail, username, ID, and token. So we can simply write here that we get a DStream. We have our token, which is string. We have our user's name. It is also string, and the last one is our email. And with this we're successful with defined our current user entity on our client. And now in every single place where we're talking about current user, we can use this interface. Our next step here is to create a class, because actually before we will start with creating components for registering and leukemia, but must create a service which will communicate with our API. And the service for sure belongs inside our module. This is why here I will create a new folder, services, and I want to create here out dot services.js. Actually it is really a nice naming if you don't know how to name your service. If you just want to pack some methods inside your service inside module and you don't really know what this Methods II about. You can simply name the service like a module. In our case, we have here our module and our service. But if you are service at some point will be too big. You can always split. It may be in login service, register, service, Current User Service, whatever you prefer. For now, our service is completely fine. Here I want to export new class hours service. Now, it is super important to not forget to write on the top injectable. Because if you want, try this single line, it will be super difficult to debug a problem. Your inputs will work, but you will get some magic occurs in the console. This is why never forget injectable if we're talking about services, now we must register the service inside of a module. And this is exactly, it's going in the direction of dependency injections and modules inside Angular. So what we want to do here, we want to create a new field which is called providers. And here it is an array and we're writing inside our, our service. So this is exactly the correct way to register all services inside our module. Now we want to create our first method here and it will be getting of the current user. Well, here we can simply write that we want to create, get current user function and it will return fast observable of current user. And at this point, you might have questions if you don't know Angular that deep, and if you don't know what our observables at all and this thin with generic here might be confusing for you. So what is observable? This is just a representation of the stream. So what is stream? This is something which has changed over time, which actually means we can subscribe to the stream. And when the change is happening in the stream, then we will get new value. Then say the angular, everything is working on love with streams when not using promises. That which actually means streams and observables, is a specific pattern, how we will write our code. So what we're saying here that we're getting back an observable. And here we're providing what datatype we're getting back. And in our case, we are saying here that this function must return an observable of type current user interface. Current user interface is exactly our current user object. Now inside we want to fetch some data, and for this inside Angular we have HTTP. This is why here I will write constructor and inside private, http equals HTTP client. So what this line is doing the top, this notation with constructor, then private some variable equals some class is how we're injecting some dependencies inside a service. And it is totally fine if it is a little bit scary for you to see such code, we will write exactly the same code again and again in every single video. For now, you just need to understand that we must use HTTP here inside our service. This is where here we must inject this HTTP client. And now here in our methods, we can use this dot HTTP and dynamic is here we want to use GET method to get our user. So what I want to do now I want to create a URL. And actually here we can just paste http localhost 4,001 slash api slash user, and we simply throw here our URL. And now we need to return this HTTP GET URL. But here we're getting an error. Object type observable is not assignable to type observable current user interface, why it is happening? Because they actually HTTP GET returning by default observable off object because our HTTP GET Cantril and know what data we're getting back when no, it only ourselves in our application, but we can do here, we must specify what we're getting back. And in this case here we're saying, okay, this specific HTTP GET by this URL will return false current user interface and not just some random object. This is why in this case when not getting any error, because this single line is returning fast observable of current user interface. And you just must remember that all this HTTP will return for us always observable of something. Now, the next thing which is really bad is this line. Why is that? First of all, here we directly road base here. This is super bad approach. Why is that? Because this line will break on production. It is suitable only for development. And we need to write exactly the same code again and again in every single method, this is bad. For this, we have environment variables inside Angular. We can jump back inside source environments and here environment, yes, this is exactly where we must define all our constants based on specific environment. So what we must do here, we can create new property API URL, and we can just paste our stream here. So local host for 1001 slash API. And this is totally fine because here in our development environment where set in API URL will also have here environment for production. And we can define different API URL there. This is the most correct way to do it. Now we can just use here environment, and as you can see, we're getting an outer input dot API URL plus. And here we simply need to use slash user and nothing more. In this case, we're reusing this environment URL and it is completely isolated inside the environment variable, our services fully ready. But what we want to do, we want to get this user every single time when we load our angular application. Why is that? Because they actually were stolen. Our current user normally in memory and after logging in or registration, we're simply talking inside local storage. This is why every single time when we're jumping inside our application, we need to get current user. For this, I want to jump back inside our app component. And this is exactly the component which will be loaded on any page. Here we can write implement on init. And if you don't know what isn't in it, this is a special method which will be called on initialising of our component. Here I'm right in engineering in it. And then said we can use our service, but in order to use it, we must inject it here. And here we're writing exactly the same stuff like we wrote inside or service. Private, not HTTP like we did in the service, but ours service that we just created. And here we must input are our service, which is inside our module. And now we can use it here directly inside the engine in it. So this our service and we have here get current user method. But what is most importantly these returns for us and observable. And typically we want to do something to listen to the changes of the observable. This is why here we will try dot subscribe. And now inside subscribe here we will get some information. So here I will just write rads and console log Ras so we can check if it's working. I will jump to the browser and reload the page. And just to remind you, your client web server must also be started. Here we're getting an error. Http client service, no provider for HTTP client. What does it mean? It means that we use the HTTP client in our application, but we didn't inject a module of HTTP client inside our application. This is way to fix it. We must jump inside of a module, and here we must import HTTP client module. In this case, our error will be fixed. Let's reload the page. As you can see now, it is working, but here we're now getting an error about cross origin request. And actually this is totally correct because we didn't configure properly our Express back-end application to work with cross-origin requests. This is why we can simply jump back inside our server. And here open source server tiers, our next step will be to install additional package. This is why I will jump inside our server. And right here, npm install course and course is the most popular package to solve course problem with Express application. I will just jump back inside or sorority S. And here I can write on the top input course, drum corps. And now the only thing that we must do here is before our body parser, for example, we can write a pews and we're providing insight course as a function. As you can see, we don't have any errors now inside backend and we can reload our front-end page. As you can see now with don't have discourse era and we're just getting unauthorized. Let's check what we have inside network. We have this request for user, and if I will make it a little bit smaller, we can see what we're getting inside response headers and we're getting here access control allow origin star. And actually this is why it is working. Our back-end, set it correctly. These allow access origin. This is why we're not getting an error from the browser. But as you can see here, we're getting 401 unauthorized. And actually this is completely normal. We're not logged in, in our application. We simply fetched current user and we got an error. This is totally fine. What is not fine with didn't react in any way for this authorized request. So what we can do, we can jump back inside our app component where we wrote this code. And we can also handle an error. And for this we can write inside Subscribe, not a function but an object. Here inside the object we can have two fields. First of all, next, this is exactly our success. And as you can see here, I'm leaving this function as it is. But after next we can create an error. And in this case, this is what will happen if we have an error. So here we can simply write console log error and maybe we want to see the Sarah, let's check what we're getting. I'm reloading the page and we're getting our error, HTTP error response. And here we have unauthorized and we can react on this era. So what I want to do now, I want to create set current user function. And actually it doesn't make a lot of sense because we're not lucky tin, but we still need to save information inside our application that the user is not locked-in. In this case, the whole application, every single component can check, are we locked in now and then our component knows how to react to this. This is why we must jump back inside our, our service. And here I want to create new method set current user. Here inside we're getting current user, which is our current user interface. And it will return a void because actually we will just change data inside and not return anything. And actually it is not completely correct. Here is current user interface or null if we don't have a current user. Because actually, if we're not locked in Poupon to set current user to now. Now the question is what were getting inside? Typically what you will see in lots of applications. People simply define a local property inside hours, like user. And then here you can simply write this user equals user. This is not the best approach with Angular. And inside the Angular, it is super comfortable and efficient to work with streams because it is much easier to react on streams and combine them. This is why we must use more difficult approach, but it is most suitable for big applications. It is correct. This is where I want to write that we're getting here, current user stream. Here. I want to create new behavior a subject, and it said behavior a subject. I'm saying that we are getting here current user interface or now, or undefined it. And after this round brackets, and here we're saying undefined it by default. So what I wrote here at all and how we will use it. Actually, what is behavior subject? This is just a representation of streams. This is just a stream which has a default value. In this case, our default value is undefined it, and we can also set inside the stream such types as current user interface now or undefined. And now inside set current user, we can change the stream. We can write here this dot current user. And to change the stream we're using dot next and we're providing you value. In this case here we're providing current user and it is completely valid because current user interface is a valid type. The main point is here that a lot of components inside our application can subscribe to this current user stream, and they will be automatic looters ended at this moment here, when we're changing the value inside current user stream. And don't worry, if you're not getting it completely, you will see how we're using it in later lectures. So we successfully created our set current user. Now here inside our app component, at least in error, we can do something. We can set our current user two. Now, here I will write this dot our service dot set current user. And here inside I will right now. So what is happening here on Initialize of our application, we are getting here current user. If we didn't get current user, then we're setting it to null. And now you want for sure to ask me why I wrote here now and define it and current user, it makes some sense to set here current user and now, but not undefined it. Additionally, they did it with the purpose because actually we must handle three different states. First of all, by default, we have undefined it, which actually means for us, we didn't fetch current user yet. It is not ready if we're sitting here now, it means that we fetched current user, but it was unsuccessful. We're not locked in. So now here means we're not locked in. And current user interface obviously means that we are locked in. So we successfully created our module, our service, current user interface, and some basic functions which we will need in next lectures. 14. Register page - Markup + Form: In previous video, we prepared lots of staff regarding current user. In this video, I want to focus on creating our register page because the pie for registration will already implemented. And for this, we first of all must create a new component. This is why here I am inside App hours in here we must create a new folder which is called components. The first component that we can implement is registering. And here is one important word. Actually later we will implement two components, registration and login. The differences between these two components are not that significant. We have in registration, additional field, username and login with, don't have this field. Then we have different The tire rubber. This is it. All. Other stuff is staying the same. This is why we have two possibilities. We could create a single component and just manage it between login and registration. Or we can create two different components. I prefer to create two different components just because it is easier to maintain later, even when we duplicate code a little bit. So here let's create a new folder and call it register. Now inside this folder, we must create ts file, an HTML file. And here we will have registered dot component dot ts and also registered dot component dot HTML. Now inside our component, we must expert our new class register component and then say this component we must first of all provide a selector. Here you have an important decision. You can name all your selectors starting with the name of your application. For example, you make some prefix which is valid inside the application. For example, in our case, we can name it L Trello or just L. And then you have a difference between all libraries that you use and components from our project. Because actually if we're jumping inside the HTML, here we have L register, then we know that this is component of our project. If you have here, for example, prefix empty and then a button, you understand the k. This is a material library and it is not our project. This is the first approach which is possible. I prefer another approach where I prefix every single component inside module, which actually means now we're inside our module. This is where here the selector will be out there registered. It is much easier because we won't use libraries. And in this case we can see from what module we're getting this component. The next thing that we must provide inside our component is our template URL. And this is the URL for our register component HTML. Now, we should not forget to register our components inside of our module. Here we're jumping inside our module Ts, and we create here a field declarations. And inside we can now write register component and delta E imported from components registered, registered. So our component is there. Now we can write some markup for our component inside our register component, yes, and actually here I missed letter S in the word register. Now let's run it a marker for our register page. And the first-class that we have here is div with class login page. And it might be confusing for you, but this is just because of our styles were written for login page and it is exactly the same like Register page. So here we have our div login page, and now inside we will have a link on the top. Here we have a router link and here is slash. So this route is going to our homepage. Inside of our router link, we want an image. So here will be image source slash acids, slash Trello, logo dot SVG. And after this class, thread law, main logo. And at this moment you want For sure to say, okay, we don't have any images. This is by especially for you prepared all the images and put them inside this folder, inside assets. And you can take all this images from the archive of this specific lesson in the description box below, as you can see here, inside source, inside assets, I have quite a lot of images, so don't forget to take them for our project. Now let's jump back inside our app, our components register, register HTML, and after our a tag here on the top, we want to create div with class firm container, and it will be our container for our form. Now, inside the container, we want to first of all write def class login header. And again, we have the class from the login, but it is not a big deal. And here we're writing register to Trello. After this, we will write a class for errors of validations. And actually for now, we won't put any errors inside it, but we will use it later. This is y here, just div class errors were closing it. It is completely empty and nothing is rendered there yet. Now after this we have our form. So let's open and close the form tag. And inside from we have specific fields. So first of all, here we have an email, so input type e-mail. And here we want to place holder email. And the last one will be class login input. Now I want to copy paste this line two times because we need not only e-mail, but we also need here our user's name. So here we don't need Type. Placeholder will be username and class. We'll be looking input. And after this type password and place holder password. After this, we can create our button to register user. Here we'll be button type, submit, class, login, submit button. And inside this button, let's try it for a register. After our form, we want to render our links. So here we will have div class bottom form links. Let's close this div and inside just create a single link to our sign-in page. So here will be a router link. Again. Here we will have slash login page and class Register link. Here inside our a tag, we will simply run the sign in. Let's check if anything is rendered. Actually, we want to jump to slash register page and see our page, but it doesn't work because we didn't register our route. Registered. For this, we must jump back inside our module, our module. And here we must register all routes which we want to create inside this specific module. This is where here on the top we can create routes array and we can say that this is rounds, and in this case it won't be just array. We will have inside the validation of every round. So here we need to add one object with our path which will be registered and our component which we just created. And it is register component. In this case, it will work after we will add this routes to our inputs. This is where here we must straight in birds and use hear route module dot for child. And it is important to use here for child and not furrowed because we want to create the Strauss inside or a child module, not inside the app module. This is where here for child routes and routes for this specific module. Now let's check this out. I will reload the page and jump to slash register. And as you can see in this case, it was rendered. We can see our phone without any CSS, and here is our SVG file that we provide it on the top. So now your question is for sure, whereas is our CSS and this is the point. I also prepared the whole CSS for our project. So we will be fully focused only on Angular and write in business logic. This is why you must take the source code of our project under the video. And then inside source folder, inside styles.css, you must copy this lines. And as you can see here, these are all in parts of New Folder styles, which you also must copy. So you need to copy two things, source styles folder and source styles, CSS, you must override this file. So inside our source styles, we have lots of different styles. As you can see here. For example, create task. We have everything regarding creating task. And all these styles are global and we will use oldest styles just to be fully focused on the Angular application. Also, I want to remind you that our global file, source styles, CSS, is automatically used by Angular, which means if you wrote this symbols here, it will work out of the box. And now if we will reload the page, we have here, our markup. So we have here trello icon, and this is actually a link to the homepage. And we have our register form with e-mail, username and password. The only problem is here, hello l Trello that we can see in the corner. This is just some leftovers inside our source app, app component HTML. Here we can remove this line and just live here router outlet. So here we successfully created our markup for register page. Now move on to bind somehow this form together with Angular. And actually inside the Angular, we have reactive forms. And this is an additional Angular module to work with forms in this week's chess way. This is y. Let's jump back inside are our components, register, register component ts. And here first of all, I want to put inside our form, new attribute form group. And here I will try it equals form. And here also we need NG Submit for submitting the form. And here we will create on Submit. Now the question is what is this form group? And actually inside reactive forms, we can create a form group inside a component. And it will be a representation of our HTML form. And it will be fully binded to our HTML elements and it will work out of the box. What we want to do here inside our class, we want to create our form. And this is actually this dot if b dot group. And we don't have B inside of our component at all. This is why we must insert constructor injected. So here I will write private if b, and this is form builder. And as you can see, it was imported from angular forms. Now here on the top we have access to this big group and here is our form. So what fields do we have? First of all, we have an e-mail and actually here we can say as an array our validators, so initial value here is empty and here we can write validators dot required, in this case reactive forms. We'll check by default this field for emptiness. Now we can copy paste this line because we have exactly the same. We have here our username, also empty field and validation required, and here is our password. It is also empty field by default and it is required so our firm is successful already. And this line here for Firm Group form is binding this specific form to our HTML, but it is not all. We also must bind every single field. Here everywhere we have this input. And actually what I want to do here, I want to put a form control name attribute. Here we will bind specific field for every input. So the first one here will be our e-mail. The second one is our username, and the last one is password. In this case, when we're changing this inputs, they will be updated inside our form group here. And the last thing that we must create is on Submit method. So we're already created it inside our HTML. Here we can simply add on submit and it returns void. And now inside I want just console log on Submit comma, this form dot values. Let's check if it's working. I will reload the patient we're getting an error cannot bind to form group since it is not known element of the form. Why it is happening? Because we didn't inject reactive forms module inside our module. So let's jump back inside or out module. And here inside the inputs we must write reactive forums module. And after this input, we should not get the Sarah. Let's reload the page. As you can see, we don't have any errors. Now I can provide something inside and just hit Register. And as you can see here inside console where getting onsubmit, e-mail, username and password, which actually means all our fields were successfully binded to our angular component. 15. Register page - service + validation: In previous videos, we created market for register page and also the firm, but we're still missing our API call, which we must implement in this video. This is why First of all, I want to jump back inside our, our services, our service, because actually here we will write all our API calls and we have already here get current user, which we will polish later. But for now I want to create register API coal. This is why here we can simply write register. And the question is, what we're getting here? We're getting actually our form, but we didn't type it yet at all. This is why it is not comfortable to use. And we don't want to write here that we are getting any because it doesn't make a lot of sense what this method wants, it wants to know what were provided inside. This is why I wanted to jump back inside our types and create here a new type. And we can name this type register request interface. And you might ask, okay, But why such strange name? And actually it is not strange. The main idea is the time post fixing everything that we're writing regarding request and response with specific postfix in this case here I know. Okay. This is a register request. So this is the body of the request. If we're talking about response of our register if when needed, then it would be registered response interface test. In this case, it is easier to understand what you are using this interface for. Now Let's create this interface. So here I want to export our new interface and it will be register request interface. What we will have inside exactly all our fields that we wrote inside of a form. So here we will have our e-mail, it a string, our username, it will be also string. And the last one is our password. And the password is also string. And actually it is not only about the form. If we will look inside our server source controllers, users were already created here a register method. And inside our register method, this is what we're looking for inside the body. So request body e-mail, username, password, and this is exactly what we're sending from the client. So our registered requested that we can jump back inside of our services, our service tiers. Here inside register, what we're getting as a parameter, it is our register request and our type is registered request interface that we just created. Now the question is, what do I get in back after registration, we're getting back our current user. This is way here we can write exactly like can get current user observable of current user interface. We already have it. In this case, everything inside our method is correctly typed. Now we need to create a URL property. So here URL and we're using again environment dot a payer realm because it is the same slash users, because they were registered request is just to post for slash users. And here now I want to return this HTTP and we have access here to HTTP post and inside we're providing festival URL. And secondly body, and our body is our register request. But again, we're getting here an error because our type is observable of the object and not observable of current user interface. Because obviously by default, HTTP post doesn't know what we want to provide insight. This is where inside our HTTP post, we must provide what we are getting back. And it is current user interface, but it is not all, will also must create an additional method to set the token inside local storage. What does it mean? Actually when we're registering a user or getting the user, we are getting also at token field that we prepared on the backend. And we should not do anything with this field on the client, but we must just save it and said local storage and attach to every single request. In this case, our backend can understand when the request is authorized and that we provided the correct token. This is where here I want to add an additional method set token. And actually inside we will provide the current user because either we will call this method after getting a current user or after registration or Guinean. So here current user is current user interface and now it will return void because inside we simply want to use local storage. And here I will write local storage dot set item. And inside I want to provide field talking and we're writing inside current user dot token. So this method simplest stores inside localStorage our token of current user, and now we're fully ready to adjust our component. So let's jump back inside our components register component. And here we have on submit, and obviously this firm value is drawn here. We want to use our service. This is why here I want to inject our service. So we're writing again private and we have our service, which is our auth service class. And here now inside on submit, we can write this out service dot register. And as you can see, we are provided inside a register request, but inside of our component we just have this dot form, dot value. And actually this firm value, as you can see here, the type of it is any, this is why it will work for us and we can't really type it in any way. So what registered returns fast? It is an observable. This is why here we can again write Subscribe with so object inside into fields which will be next if it is correct or it will be an error. So inside next, but we'll get current user bag. And here we will do some logic. And if we will have an error here, then we must specify an airfield. And here is a function with Era. And inside we can simply console log and narrow. So first of all here I want to write error, error here inside next console log our current user, coma, current user. Now let's check if it's working. I will provide some email which does not exist inside username and password and hit Register. And as you can see here is our network. We're getting here to request. First of all, we are getting options request. And this is completely normal because we used course. And we have a request between two different hosts because we're hosting our applications on different parts. So you will see these options every single time. It is completely normal. But we're interested in our post request, which is slushy pathless users post. And here is our payload. The payload is completely correct and here is our response. As you can see, we're getting back our e-mail ID token and username, which actually means everything is working fine. And here we're getting our current user. But as you can see before, we're getting error, HTTP error response. And it should not bother you because this is the error of this unauthorized request and we will fix it in the later video. It doesn't do anything to our register component. So as you can see here in the console, we're getting our current user, which means our code here is completely correct. So what we can do now, we can write this dot and here we have our service and we can call here a method set token and provide insert current user. Then this line, because we have here current user will save our token of currentUser to local storage, but it is not hold. We also want to save a user for the whole application, and we're already prepared before for the same method dot set currentUser. Inside. We can simply provide our currentUser and listen this method. It will just set this current user in current users stream. You will see how using current user stream in later videos. Most importantly, that now after registration, we set it at Target and we sat at a currentUser inside our application. And the last thing that we want to implement is our validation. Because actually if we will get an error, we want to show it. This is why here. First of all, I want to type our error because we know what is it. It is an HTTP error response. And here we're getting our error and we can write here dot Azure at least. And yes, this arrow will be any, but still it is better than nothing. But we want to do now we want to save our error here. Now the question is, in what format we will get our errors. And for this second open again, our controllers, users. And as you can see here is our catch. And what we're doing in this line, we're mapping through our errors and we're getting messages as an array of strings, which actually means we are sure that if we're getting an error, it is always an array of strings. This is why what we can do in our client inside register component, we can generate an error message and show it here. This is y. What I want to do here, I want to create just a single error and it will be of type string on now. And by default it will be now because we don't have any error. Now here inside our error, we can write this dot era. We know that here we're getting our error inside as an array. This is why here we can simply create Azure dot dot join in here will become a space, which actually means we want to join all our errors with comma and space, and it will be just a single field. Now, I want to jump inside a register component HTML here where we have div class errors. I want to write and GE and show this field only when we have an error and inside they can simply render our error. Now let's check if it's working. But as you can see here, we're getting an error cannot bind to G if it is not known property of div. And it is happening when we didn't inject a common module inside our module. This is where here inside the imports we must input common module from Angular. Now as you can see, we're not getting any errors. And what I want to do, I want to provide invalid data. For example, inside email, I will provide data and not incorrect format. Now let's clean everything and hit Register. And as you can see here, we're getting our error. And this is an array with invalid email. And we're rendering this invalid email here on the top, which actually means we correctly is reacted azure and Don success of registering of our user. Now, let's check if we really safe talking after registration. This is where it Let's reload the page and provide correct e-mail, username, password, and hit here register. As you can see, we've got our user, which actually means we started in memory. But here when I'm champion inside application local storage, you can see our token and here is a value, which actually means we successfully implemented registration of the user and we stored the token inside localStorage. 16. Login page: In previous video, we successfully finished our register page. In this video, we must implement login page. And I think this is an awesome idea that you try to implement it on your own. So what do we need to implement on this page? Actually login page is simply URL slash login and we see exactly the same form like register, but login form. So actually we have just an email and password and we don't have username. Obviously all texts are different, but essentially this is it. Also we will use the another request follow gaming on slushy pie slash users slash login. And here I have three levels of complexity for you. First of all, you can pause this video right now and try to implement it yourself. Second level is you're getting some guidance from me before you start to implement. So what do we need to do at all? First of all, as you can see here, inside out components, we have a register component. And as I said earlier, with don't want to share component between registration and login, which actually means we can implement the new component login with exactly the same markup, but without our username and our ts file will be super similar. We need a form, we need onsubmit and so on. But the main difference there will be in a service, we won't use our service that register, but we must create a method login, which actually means we must in our service here, create a login request, which will make an API call. And actually it will be super similar to our register. But here we're must create not registered request interface, but login request interface. And then inside we must provide a correct URL if you want to try it yourself. Now, just pause the video here. And if you don't want to try it on your own, Let's do it together. And our first step will be to create the interface for our service. So here we have our register request interface. And actually as you can see, we have three fields here, so we can't reuse it inside login. But I want to do here, I want to create a new interface, login request interface. Let's jump inside this file and we can copy paste completely our register request interface, just because it will be super similar and they don't want to type a lot. So here we must create our interface, login request interface. And we have inside email and password, and we don't have our username. So we successfully created our interface. Now we can jump back inside our service and we can copy paste register method fully because I will login method will be super similar. Let's name our method login. And here we don't get registered request, but our login request, here we need another interface that we just created. It is login request interface. And back we're getting our user, which means it is correct, observable current user interface. Now here is URL. We have here API URL slash users slash login. And this API we're already implemented inside our backend. Login is for sure a post request, which means here we must provide a post with body login request that we set as a parameter and our login in service is fully implemented. Our next step will be to create a component here and actually has this set register component is super similar to our login component. It doesn't make any sense to retype everything on your own. This is why I want to copy the whole folder and paste it here and rename the folder login. Now we have login component. We must rename here pages. So it will be login dot component dot HTML. And here login dot component dot ts. Nova must jump inside our HTML and change it a little bit and it won't be that different. First of all, here, instead of registered to Trello, we can write log in to trailer. Now we're leaving here error, just like we had them. There were also need form submit and here we have e-mail, username. We don't need the tall, we can remove it. We have our password. And now here is submit button, not with register, but we sign in, for example, last but not least is router link here on the bottom, it should go to a registration page. This is where here is slash register. And instead of this text, we can write inside sign up for an account. So we successfully changed our HTML. Now let's jump to our TypeScript file. First of all, we must change our selector. It is not registered, but our login and template is login component HTML. Now className also is different. It is login component Live era as it is. And here is our form. We need e-mail and password, but not a username. So let's just remove username here. Our constructor stays the same. Our onsubmit stays almost the same. But here we won't use register method. We created a login method where inside where providing the whole form. And here we have subscribe and if we're successful login, then here we console log and current user where set in talking and we're set in current user, which actually means it is 99% exactly the same code like inside registration. And our last step here will be to register our components. So we must jump inside our module tears. Here inside declarations, we must say that we have a new component and it is login component. And we're also must create here a new route. So I will copy paste the register route and that path login and component will be login component. Let's check if it's working. We don't have any arrows here inside of observer. I will reload the page and try to jump here on the bottom, for example, in sign-in page. And as you can see where on slash login. And here is our form and we can reload the page where stain on this page, everything is fine. Now let's try if we can login at all. So here, first of all, I want to write something incorrect. Here is some email which does not exist. And then some password. I'm hitting here saying in, and we're getting an error, as you can see here before, we're getting photo to error with validations. And inside our error where getting filled email or password, incorrect email a password. And we're doing this in this case because we don't want to notify user what exactly is not correct. We should not say something like this email is already taken. We simply say it is invalid. This is why this logic inside login component of bone work. And just to remind you here we copy pasted on submit and here inside an error with joined our errors, because in the case on Register page we had here an array of strings. Here we don't have it with directly see an arrow, email, a password, which actually means here instead of the join, we can write era Dodd email or password. In this case, we will apply it correctly area inside. Let's check the sound. I'm reloading the page. Let's type here some email which does not exist, some password sign-in and we're getting incorrect email a password, which means our validation is working correctly. Now let's try to login with correct credentials. So here I have full at gmail.com and here is our password 123. I'm hitting here, say mean, and we're getting current user. But the main problem is we're staying on this page. And secondly, we didn't remove this area at all. And actually we can do both things simultaneously. First of all, what I want to do here on submit, we can remove the Sarah. So here, this dollar error we can write inside now. And actually I can say now that era name is not the best one because actually error is super generic and they would like to change this name in here from era to era message for example, in this case, we need to change it here inside next and here inside era. And after this, we must jump to the template and change it there also. So here we have Angie if error, it should be error message. Here we're rendering our era. And I think that this approach is much cleaner because it gives us understanding what we're rendering here. It is not some generic error. This is really an error message. Now we must apply exactly the same inside our register. So let's jump back inside our register. And here first of all, I want to write error message. Here is also error message and then say ts file, I want to change arrow two error message here, right error message inside era, and we want to set it in now in our success. So here this error message equals now, the last thing that we want to do, we want to redirect the user to another page. It doesn't make any sense that we're staying in this page and it lists, we want to jump to the homepage after login in a user. In order to do that, we must inject here our router. This is my insert constructor. I can write private router equals router. And as you can see, this router is coming from angular-ui-router. And now here inside success, on the last line, we can write this dot, dot navigate by URL. And we're providing here URL, for example, just slash. And now we must do exactly the same inside our login page. So I'm jumping inside login component in here. First of all, I want to inject private Zhao router. And after this, I can paste this line, this route navigate by URL slash, which actually means in both cases, with registration and login, we want to reject our user to the homepage. Let's check if it's working. I'm here on login page I'm writing here f2 at gmail.com, here 123. I'm hitting sign-in and then champion to the homepage, which actually means we successfully implemented our login page. 17. Home page: In previous videos, we finished our login page. In this video, we will implement our homepage for the project. And the main point is that this page will be just markup and no logic at all. Why is that? Because actually this page is only for anonymous user if we're locked in but never see this page because we're directly redirected insight boards page. So first of all, let's implement in your module. And for this inside the app, I want to create a new module which is called Home, which actually means this is completely separate module. It doesn't have anything to do with hours, and there is just a homepage component inside which is isolated inside this module. So let's jump inside this folder and create new file Home module Ts. And a lot of students are asking me really often why they don't use generators together with Angular. And actually there is a reason for it. I find that it takes more time to use a generator then to just copy paste the module if we need to do so, and also for the educational process, so you remember it better. I am writing it from scratch. This is y. Let's create a home module once again from scratch. And every next module we will just copy paste. This is what we want to do here. We want to create a new class and let's name it home module. After this, we must inject here a decorator in GI module. And inside we must provide our dependencies, at least here inside the inputs, we must provide common module because we need it inside every single module. For example, for loops like in G4, offering G If now, let's create our home component for this biomass, create a new directory components. And inside we want to create a new folder home. And yes, I understand that we have just a single component here and it doesn't make a lot of sense to create slash components than Home folder inside. But nevertheless, it is a good structure. And if you didn't need to split this homepage in different components, you can for sure do it. So let's jump inside home and create here home component dot HTML and home component dot ds. Now let's jump inside of HTML page and just ride home here, but don't need anything, just something for testing. Now let's jump inside our ts file. And here we want to create our class and it is home component. After this, we must register our components. So here we want to inject our component and inside we must first of all provide a selector. So here I will simply use a home selector because it doesn't make a lot of sense to prefix our home component with module name like home, home, it's simply not needed after our selective we must provide here at template URL and then say template URL, we will have home component HTML. And our last step here is to add our component to our declaration. So inside home module here, we want to create declarations and put inside our home component. Everything is looking fine here, but we didn't create a route. This is why here I want to create a property routes. And we can say that this is type routes and this is an array with just a single key. And here will be our path. This is empty string, it means homepage, and here is our component, and our component will be home component. After this, we can register this route inside inputs. So here will be route module dot for child routes. And now we should not forget to register our home module inside our app module. This is why I want to jump back inside our app module. Here, insider in birds, we can add our home module. Everything is looking fine. I don't see any errors inside of observer. So let's open a browser and here is our homepage. As you can see, the word home is rendered here, which actually means we successfully created our whole module and empty component. And now we simply must try to markup for the whole page. This is my, let's jump back inside the home components, home, home component HTML. Here, start to write our markup. Nothing special here, just lots of DOM elements. So here we have header with glass home header. And now let's close this header. Then side we want to create a link to our homepage. So here will be a router link slash. And here we have class home had a home link. Let's close the sale and inside the double bond to show an image. So here we will have image source slash, etc, slash Trello, the logo, the white dot SVG. And let's close this image. As you can see in browser, it is applied. And here we see our header and link to our homepage. Now we must provide links to login and register page. This is why after a, we can write div. And inside div we can write two links. First of all, here, inside div will have a router link to our slash login that we just created with class WHO had a login, I will close the sale. And right inside login, now we can copy paste this link and here we have slash register. Here is class home header register, and the text inside will be also registered. Let's check if it's working, as you can see in browser here on the right, we have login link and register link. Now, let's say the first block of our page. So here will be div, class home hero. Let's close this div and inside we want to add a div class home container. Let's close this div. And inside home container we have a div. And inside this div will be H1 tag. And here we have class home Desh title. Let's close this H1 and inside each one I want to paste. Although the prepared text helps teams to work more collaboratively and get more done after each one we have p tag. This is our description. Here should be glass home description. And inside this p I will paste the description about Trello boards, lists, and current. After the first div, we will have a second div. Let's close it. Inside. It should be an image. So here will be image source slash acids slash hero dot SVG. And let's close this image and check if it's working. We're jumping inside browser. And as you can see here, we have a first section of our homepage. Here on the left we have text and nice image on the right. I think that you get an idea how work rate and blogs for the homepage. As you can see, we simply have such blog title, description and image, which actually means that you want to speed up the process of creating homepage because this is just an HTML without any logic. So here I want to paste the second blog home team. If you want, you can simply pause the video, retype everything, or you can simply take the HTML of the homepage from the source code under the video. So what we have here, we have home team, home container team container inside. We have worked with any team, some description and an image. Let's check how it looks like. Here. After our first element, we have the second with text and now the image. Let's create now one more block here. I'm pasting home information. Same stuff here we have classes in image than H1 and p. Let's check this out. I'm reloading the page and we have here on the bottom one more block with an image and texts. And now let's paste our last block. As you can see, it is a little bit bigger. We have here something about workflow and automation. Here we have H1 description and also the bullet list. And on the right we have an image as always, as you can see here on the right we have an image and on the left we have first of all a title description and then a bullet list, which actually means we successfully created our homepage. It was not something special, just a marker for not logged in user. 18. Auth interceptor: In previous video, we successfully created our homepage, but now we have just a single problem. We're actually implemented getting of the user after page a lot in just to remind you, inside our client insight app, app component ts, we're calling our service get current user. And actually now we're always getting an error here and unauthorized. And actually if I will jump to register page and just create some account that didn't exist previously. As you can see after registration where there's reacted to the homepage. And inside of local storage, we have this token. This is what we set it from the back-end to authenticate our client. But afterwards reload the page. This token is not used and we're getting here unauthorized. And the idea is basically the tower client must on every single request, apply this token from the local storage if we have it, in this case, our backend knows when were authorized, but just imagine if we rarely need to go inside every single method, like for example, get current user and that he has some hair from local storage. This is not deficient, time-consuming, and we really want to just add this token on every single request. For this inside of the Angular, we have middlewares. This is why now we will create a now middleware. So what is Middleware? This is something in the middle between start off our request and, and, and actually here we have, for example, the HTTP GET and we will create a middleware. It means that after this request is started, but it was not sent here. We want to apply middleware, so we want to do something. For example, it takes a header there. This is why I want to jump inside our house services and create here in your service hours, interceptor, DOD service dot ts. And it will be just a class, just like normal injectable service. Here we have experts, class hours, interceptor, and here we must say implements http interceptor. So the main idea is that this middleware in Angular is called interceptive because it intercepts our request. And here we're writing implements http interceptor to get a narrow class house interceptor incorrectly implements interface and property intercept is missing, and this is exactly what we must create in order to implement this middleware. This is why here we will create a new method which is called intercept. And as you can see here, my autocomplete already got request and next, and it returns observable office HTTP event, which actually means we have a full access to or request here inside request property. And we will call next when we're ready and we finished everything that we need to do here. This is why first of all, what we want to do inside is get a token from our local storage. So let's write here that we have a target and this is local storage get item. And inside we're providing token. After this here I want to write request equals request clone. And here inside we're providing an object with field set headers. The insights that headers it is an object we're providing authorization equals talking or empty string. And after this we're calling return next door handle and were provided inside our request. So what this code is doing at all, first of all, here we got a token from Google Search. So it is either an undefined it or it is a valid token. Now here we're doing request clone. Why we're doing it? Because request is immutable, we can't really change it. This is where we must cologne it in order to set something. Here we're using properties set header to set a header. The header is called authorization and inside we're providing our token. So if we don't have a token, we're saying here an empty string. And after this we're calling next handle, which essentially means we must continue our request and we're providing updated request inside. So this is how we're creating middlewares or interceptors inside Angular. But now we must inject this out interceptor inside our application. But the main thing but we want to do for one to inject out interceptor, not inside out module, but inside app module because we want to do it on a global level to inject interceptor, we're using providers here. So what we want to do inside this provides an object with field provide, and here we're using HTTP interceptors. It is coming from Angular also were right in here use class. And this is our class, our interceptor, which we just created. And the last one is moved to true. And this is exactly how we must provide http interceptors inside Angular. So here we're saying that we must register and you provided and it is an http interceptor and we must use our class hours interceptor. Now let's check if it's working. I'm reloading the page and let's check inside network, our request user. Actually here I want to scroll to the bottom. Here we can see authorization and our token, which actually means our intercept, is working correctly. And we directly applied this authorization header to every single request, for example, to get a current user. But we're still getting back our 401 error and they actually know what is the problem. If we will look inside local storage, we can see that token simply a target, this is just a value. But if we will jump back inside our backend here, inside source, middlewares, owls. And this is where we're checking a token here as you can see where making split by a space. Because as I said previously were right in beer and then space talking. If we're using a DVT authentication, this is not our case here. We don't have here a word, beer, and this is exactly our problem. We didn't implement it, and we must do it when we're returning a token to the client. So here inside servants source controllers, users, when we generate torque in here, inside normalized users, we must write here space. Here we have justice train, where inside, where right, and beer. And here we're injecting our token that we generated. Let's check if it's working. So our token is invalid, they will simply remove it and it will jump to register page. Now I want just to put some credentials here and hit register. And now when we're checking our local storage, you can see that we have beer than space and are talking. This is why when I reload the page with don't get for 01 error anymore, we're getting here our response. And actually here you can see that our request user is 200 and our response is exactly what we expected, how it is working. Once again, we're registering, for example, or login in and we're setting a token inside local storage. So Birra space and the token then every single time when we're making a request out interceptor inside Angular, it attaches inside header, this authorization token. And here we have bear and then our token and our back-end checks this user and gives us a response here. This is why every single time when we reload the page, we're getting back our current user. And this is exactly what we wanted to achieve. Now here inside our clients source AB, AB component, yes, I want to make a small improvement because actually here we have announced service, but we don't use this Ras and actually now we're getting a user so we can write here not trans, but this is current user. And instead of console log, we want to set it with the method that we're already prepared. So here we have this, our service dot set current user, and inside we're providing our current user. So now our user is successfully logged inside our application. 19. Auth guard: In this video, I want to talk about Gvd in our URLs, which actually means, for example, we should not allow user to jump to the homepage. If he's already locked in, he must jump directly to the board. For example, if we're not locked in and we're trying to jump to the board's page, then when not allowed inside and we must be redirected to the homepage. So there are different approaches to this problem. But for any use case, I highly recommend you to start by creating an observable of Islamic tin. Let's do this now. So actually I want to jump inside our app, our services, our service here will be created current users stream. And as they said, this is trimmed that we can use from any place of our application. And just to remind you, we're using here set current user to change the stream. So essentially what we can do now for example, inside our app component somewhere here after in June in it, we can write this dot, our service dot current user here we're right and subscribe board, and we're getting here our response. And now I just want to write here console log. So you see what I'm talking about? So here we subscribed to the stream from our service. And now every single time when we change our stream, we're getting this data back inside that component. Let's check in browser now. And we're getting here two console logs. First of all race and define it, and then Ras and the information about our user, why it is happening like this at the beginning of the stream is undefined it because we didn't fishy user yet. But after some time when our currentUser call is finished and it is successful, we're setting this currentUser inside this stream. This is why every single place where we subscribe to this current user can get this information. And this is exactly this information. But we can make it even better because essentially we want to check if locked in or not. This is why typically you want to take this response and you want to convert it to Boolean and check for true. In this case, we're locked in, but we don't want to write this code in every single place. This is where we can inside our, our service create additional stream based on our first stream. So here is our Stream current user. But now I want to create a new stream, which is called is logger tin. And now inside our application at any place we can use, new stream is log team. So what did they there? Here we're using this current user and this is already a stream. We simply want to transform it to another value. This is where I am right in DOD pipe, then Site Map function. And if you don't know this is Rix JS code. So essentially we're using looks chess and say to Angular to transform our streams. And we're using it in this way. We're always writing dot pipe and then the list of our transformations. This is where you will see that pipe everywhere and here inside where using map to map our data. So we know that inside our map we can get three different states, undefined it, false and true. But the main point is that our application does not care about undefined. It were relevant to check is login. If we have this information, if we don't have this information yet, then we just want to wait for this information. This is way before I want to skip this undefined as property. This is where here we can use filter before our map. And filter is also a function. So essentially, first of all, we're using filter inside pipe and then a map. So what we're getting insight filter inside filter by getting our current user, and actually this current user can be undefined it now or our current user. And here we don't want to come to the map if it is undefined it, this is why here we can write current user does not equal undefined it. Then in this case, we will come here and here is our map. So what we want to do inset map, where I get in here, current user. Here we want simply to convert it to booleans so we can write here boolean and then current user. In this case, this logic will bring us back true or false, and we will skip this, undefined it that we don't need and won't use inside of our application. But we can simplify this code even more. Instead of flight and this logic can set map, we can simply write here Boolean, and it will do exactly the same. So R is look at tin is a new stream based on the current user, which will return for us true or false. Let's check if it's working. I will jump back in setup component. And here I want to write this dot or service dot is locked in. Here we can also write Subscribe and our heads and our rest will be is locked in. So let's check this out. We can even name it to be more understandable, is logged in. And here let's console log is log of tin, coma is login property. Let's save this and check and browser. I'm reloading the page and here we don't see Islam getting undefined. It. We simply see here is low getting through because this is the first state where we have true or false. And this is exactly the way how we can use in any place of our application, this stream to know if the user is logged in or not. So now I want to remove this code because we don't need it here. It was just for testing. And now I want to show you the easiest solution, how you can redirect user to another page. And we can simply start with our home component, because essentially here we want to redirect the user to the board's page if he's already locked-in, how we can do it. First of all, here, we must inject inside constructor our, our service. So here private hours service is announced, service that we already have. Now here we want to write implements on needed, so we have initialized. Now here we will use engineering in it. And inside now we can write exactly this logic Lake Road inside our app component. So here will be this dot, our service dot. Here we have is locked in. So after this we can write Subscribe and we can get here is log it in property here inside this subscribe either get true or we get false. And if it gets in here true, we want to redirect the user to the board's page. This is where we can just try it. Eve is like a tin. Then we want to redirect the user. And to try to redirect, we can use as we used previously, router. So here let's create a new private property router. And this router, now inside our if condition, we can write this dot, dot navigate by URL. And here we can just provide slash boards. And actually we didn't implement this slash boards yet, but it doesn't matter. We simply make it as an example, how you can restrict access into the URLs. Let's check this out. And actually here we already get an error, cannot match a new routes. And here is boards. And essentially we can check it, for example, with slash register. To understand that it is working, I will reload the page and as you can see where on slash register, why it is happening where jumping to the homepage, I'm hitting Enter and we didn't even see our homepage where they directly inside register. So this is the easiest way how you can implement in say, the angular redirect into another route. But here is a problem we used here, subscribe from an exchange. You must be really cautious with it. Because if we're using subscribe, we must also write unsubscribe. If we didn't try unsubscribe, then it means that we have a handgun subscription inside our application. Actually, our home component pathology destroyed because we're inside register page, but this subscribe is still there because we didn't unsubscribe from it. This is where we must always remember to unsubscribe from our subscriptions. To do this, we simply must create a subscription here on the top, for example, is log it in subscription, and the type is subscription. Now here inside our engine in it, we can assign this is logged in subscription. The result of Subscribe will be our subscription. Now here on the top we can add on destroy. So when this component will be destroyed, but wanted to create in G on destroy method. And inside we can simply write this is like getting subscription, DOD, unsubscribe. I'm saving this but we're getting an error. We don't have initializer here because there's low get in by default is not set, it is undefined it, and it is true. This is why here we can write or undefined it, because it is not set by default and we simply set it in engineering in it. But this is my code here, is invalid because this object can be undefined. It, this is why here we must put a question mark. So this line won't do anything if this is an undefined it. But if we have a subscription, we will be successful the unsubscribed when the component is destroyed. But now I want to show you the second possible variant inside and color to make redirects or to guard your routes. And this is exactly the feature which is called quadrants inside Angular. And the idea is exactly the same like with interceptors, were doing something before work set the component. So essentially we want to do some check, then return true or false. This is way here inside our module hours. I want to create insights service and you file, and it will be our word dot service. So here I want to export our new class hours word service. And here we're writing implements can activate. And this is exactly the same thing like we did with our interceptors. As you can see here, we must define, can activate to make this R-squared working. This is why here we can write, can activate, and here we're getting lots of stuff inside. We actually don't need all this stuff. We can remove it and this return is too verbose. We want to return here. We want to return back an observable of Boolean, which actually means we're returning true or false. But as the stream, now inside here we want to use our, our service. This is why here we must define the constructor and inject here inside our service of our hours service. And the idea is that inside this method, we must return an observable of Boolean. This is way here directly. I can write this. Our service. Dot is log tin. Here I want to write pipe because we need to do some stuff inside. This is my insight. I also will add MAB and we're getting here as an argument is login property. Now here inside they want simply to check if we have is login, so it is true, then they directly want to return true. But if we have false, I want to redirect the user to another page. This is where here we're also need a router. So we can inject here private router, and this is our router, and we can use it here. So we're writing this dot router dot navigate by URL. For example, with the detector, use the to the homepage. If they are not locked in. After this, we must return false. It is mandatory because essentially this is an observable of Boolean and we must not only do something here, but also return false. And here I want to navigate by URL, not empty string, but just a slash. And you might say, but why we didn't return, simply hear this, because this locked-in is a stream with true or false. Because here we want to also use route and navigate by URL, and we can do it if we simply return true or false. So now our gouache is ready, but we must registered correctly. This is my inside our module. Here inside providers, we must put our owls wire service that we just created. Now we must check on some route, our route quadrant, this is where here we can, it can activate. And inside we're providing an array with our auth service, which actually means when we are jumping to login, our outward service will check if we're locked in a node with usage of our stream. And if it returns false, then we will be redirected to the homepage. Let's check this out. I'm reloading the page and we're getting an error. The class, our square service cannot be created because it doesn't have angular decorator. And actually here inside-out squared, I forgot to write injectable. Don't forget it. This is way here. Let's put injectable and round brackets. Let's reload the page, but don't have any error. Now I want to try and jump to our same mean. I'm hitting same mean. And as you can see, I can access login page because here we wrote can activate our squad. Which actually means if here we are getting through, then we can access this page. Which actually means if here inside our application, I will remove our token and they will reload the page login. I will be redirected to the homepage because they don't have access to this specific page because of can activate, which actually means we successfully implemented are accessing of the pages in two different ways. First of all, by using component and secondly by using Angular feature which can activate. But actually we created this owl squared, not for login or register, but for future boards and the port pages because there were making a lot of requests only for logged in user. This is where here I will remove, can activate. And they also want to change our code back inside home components home, because here we should not redirect to slash register, but instead slash boards, which we will implement in our next video. 20. Gettings boards: In previous videos, we finished implementing our homepage and now we're starting a new section. And this is a page boards. So what this page is about, this is a page where we can get the list of boards of the user, ran them on the screen and create a new board. Here you for sure want to ask, okay, but we have socket IO. Will we use sockets that you're on exactly this page? And my answer is no because we don't need to use socket or your everywhere we have for this is to TP yesterday, a lot of cases where we need socket IO, but for sure not for this page. Why not? Because actually this is the page where we, for current user simpler random list of words. We don't have any other users who need access to this specific page. This is where it doesn't make any sense to use here socket IO, but don't worry, we will use socket ion a lot later on the single board page. And in this video we will focus on creating our board on the backend and getting the list of boards from the API. This is why Let's jump back out of our client to our server. Here inside our source folder, inside types, we want to create a new interface and let's name it board, dot interface and dot ts. So board is our new entity. Inside we will register our board interface which we will use in different pages. For example, in the page with the list of boards and on the single board page. So here we want to export our new interface and this board. And the question is, what we will have inside, exactly like we did inside our user. We will have here interface for the board like this. And we will have here board document, which will extend the document to get at least an ID. So we don't need NAD here, but we need at least a title. So each port must have a title. Secondly, we will have here created it, it is date, and it will also be date. And actually here on the right-hand side, user, as you can see, we didn't create updated head, but it is there because of Mongoose, so we can write it here also. The last field that we need here inside our board. Our board must belong to some user. This is where here we must save MAD of the user who created this board. And for this we can write here user ID, and we're not writing here string, but Schema dot types, dot object ID. Now we must import here on the top schema from Mongoose. As you can see here, we have this special notation, schema types, dot object ID. And this is exactly how we're creating a d's inside Mongoose. So inside this is not just an idea, this is an object ID, but at the moment when we will build our API, this user ID will be simply a string fast, so we can understand what user-created this specific part. Our next step here is to create our document for the board. This is where here I want to expert interface and here we have Word document, exactly like we had on the right. Here we want to use extents document and this document is coming to us from Mongoose, so we should not forget to add it here on the top because another case it won't work. Here, we simply put brackets and nothing more. So we don't have here validate password or something similar because we simply extend the document and with daunted anything new. So we successfully created our board interface. Now it is time to create our model. So inside models we're creating new file board dot ts. And again, just like we did in the user, we will create our board schema. So here on the right, I will open our user so we can have a look. First of all, here on the top, I will import schema and model. And now we want to create our board schema just like we did for our user. And here we're seeing new schema and this is mongoose schema. And inside we're providing our board document that we just created. After this, we have a round brackets and inside we must provide all fields of our board document. The first field here will be titled. So what is title? It is a string. So let's say here that our type is string. And secondly, it is required because we can't create our board without a title. This is why we put here required through. As you can see here, we're getting an error. So argument of type title is not assignable to parameter, which actually means we did something wrong with our board document. And see our problem because here were extended from the document, but we didn't extend from our Board, which actually means all these properties were not available fast, as you can see now we don't have any errors. Title is that now we just need to provide user ID. And here inside we must set our type and it will be exactly the same schema, dot types, dot object ID. And the next one is required through in this case when no, Okay. Use ray D is also mandatory. After this, we must export our model. So here will be expert default model and we are providing insight as a generic our board document here now we can open our brackets and does the first perimeter we're providing here named board. And there's a second parameter, our board schema. So as you can see, we implemented our board in exactly the same way like we did with the user. But board is much simpler because we don't have here additional methods and the additional validations. Now we must create a new board's controller. And the method to get Albert's inside. This is why what I want to do, I want to jump in such service source server tiers. Here. First of all, I want to register a new route and it will be app.get. And we have here slash api slash boards. And this is the list to get all boards of the current user. This is where here we want to use our OS middleware, because if we're not logged in, we can get boards. We must have a user. And the last one here will be our board's controller. We don't have it here and here, dot, for example, get boards. So we must create our board's controller and here get board method. This is why on the top. First of all, I want to input our star as board's controller, Rome, and here will be path controllers slash boards. And we don't have this file yet, so let's create it now. Here inside controllers, I can create boards dot ts, and here we must create a new action. Here we will do it in exactly the same way like we did inside our users Controller. So first of all, on the top we need to input our request response and next function from express. After this, we can create our new function, get boards, which will be an asynchronous function. And we're getting here first of all, our request and this is type request, then response, it is type response. And the last one is next of type, next function. And this previously we want to write here try-catch so we can handle everything correctly. Here we're getting our error and we can simply throw it inside our next here will be next era. Now, inside our tribal must try to allow logic for this. We must inject here our board model that we've already created. So here will be important Board model for Rome. And here to dance, we're jumping inside models slash board. And now we can try to find all boards by specific user ID. So here we want to get our property boards. And here we're using a weight Bohr model dot find. And if you don't know, find will find for us old records by specific predicate. So inside we can provide an object with fueled usury t equals request dot user dot ID. And as you can see here, we directly get an arrow from TypeScript that user does not exist inside request. And this is totally right. Just to remind you, we created here our own custom requests with use a field inside. Here we can write express request interface, and in this case, it will work correctly, but our request user can possibly be undefined it and then this code won't work. This is where here we must try it. If we don't have request dot user, then we want to throw here for 01. So return address, send status, and here will be 401, exactly like we did previously in now a user's controller. So here on the bottom, we did exactly the same. And now we must simply respond with our boards. So here we can write rest dot sand, and we're sending here boards. And the central, this board's list is just an array. Let's check if it's working. As you can see here, insert server, this is connected and they don't have any errors. So let's jump inside postman. Let's make here a request slushy pie slash boards. And as you can see here inside headers, or you already have an injected token because we use this request previously. I'm hitting here sand. And as you can see where I'm getting back an empty array because we don't have any boards. So now the question how we can get some boards if we still don't have any pie to create a board. And for this we can simply jump inside Mongo and create this port on our own. This is way here. Inside console I will write docker exec minus 80 MongoDB Mongo. So essentially we want to call Mongo command inside our container, MongoDB. Just to remind you if you didn't use darker here, but you just simply installed MongoDB on your machine. Then you just need to write MONGO insert console and it will work. I'm hitting here, enter them here inside the console of Mongo. Now here we need to use our database. This is why here I am writing use space ultra long. And after this they put semicolon. I'm hitting Enter. And as you can see here, we switched to dB HL trailer. Now here we can write show collections semicolon, and as you can see, these are our collections. We have here boards and we have our users. What we want to do now we want to insert a new record inside our boards. For this, we can write db dot, ports, dot insert, and here we have a function, so round brackets and inside an object. And here we must provide what we want to insert. In our case, it will be just title, for example, first board. And we must write here some user ID, but here we should not provide the string VM must provide an object ID. This is where here I want to write user id colon and then object IED. I opened here round brackets and inside I'm paste in our stream. As you can see, this is not just usury, the end of the string. We're starting here inside user ID and object ID with the string. And at the end we must put a semicolon. I'm hitting Enter and we're getting the right result inserted one. And now here we can try and get all records inside this specific collection. So db dot boards, dot find and round brackets. I'm hitting Enter and we're getting just one object with ID. And this is the idea of our board title first board and user AD is a correct object ID. This is why now we can jump back inside our postman, choose our API boards request and hit Send. As you can see now we're getting our ASHRAE with an object inside. Here we have our ID and here we see it as a string, title and user ID, which actually means we successfully created our first board from the console and we've got the list of our boards. But here I want to improve last small thin, as you can see here, we're getting our IDs from the backend with underscore. And actually typically from the API we're getting a DES. Normally without underscore. This is just the thing of MongoDB, which means this is not that comfortable to get a, this was underscore on the front-end and put don't want to do that. And inside Mongoose, there is a possibility to tune this. This is why I want to jump back inside our code, inside sororities. And here, for example, after our configuration of abuse, we can write here Mongoose dot set here as the first parameter we're providing to Jason. And as the second parameter we're providing an object. And inside first of all, we're saying we're Charles through. And secondly, transform. And here inside transformed we have two arguments. First one will be underscore and second will be converted. And this is the function. And inside this function we want to write delete converted dot underscore ID. So what we're doing here at all, here we can change to JSON method that is written inside one goes here we're providing transformation, so we're saying how we will transform it. And actually inside Mongoose, we will get back NAD and underscore ID. And here we will remove just from JSON underscore ID, which actually means inside Mongoose, we still have this underscore ID. We can safely use it, but we won't get it inside JSON, we will get a normal ID. And you might also want to know what is virtual strong and actually incitement goes inside models. We can create virtual properties and by default inside Mongoose whoop won't get them back. And actually we want to get them back. This is where here we write virtuals, true. So let's check if this code is working. I'm jumping back to the postman and I'm hitting sand. And as you can see here, we're getting exactly the same response, but we don't have underscore ID. We have just a normally d, which is a string. And this is just like we want to use it inside front-end. 21. Frontend for gettings boards: In previous video, we successfully implemented getting our boards on the back-end. Now we must start with our frontend part festival. For this, we must implement our boards module. But just to remind you here inside clients source, app, home components, home, home Ts, we have very direct on the slash boards when we're locked in. This is where we must first of all, implement our boards module and inside this route, so at least our code can work successfully. This is where here inside that we want to create new module boards. And this is separate module for a single page where we have a list of the boards and actually inside we could also create a component for a single board. But I really want to separate these two modules because they are two different. This is my inside of our boards module. We can create boards dot module.js. And here I don't want to write everything from scratch. I want to copy paste whole module completely and just change it. So what do we have here? First of all, our class will be bored module. We won't have here in declarations, home component and we need here and you round, but here we don't need path home, but we need path boards. And this component home does not exist here, so we need to change it to our new component, boards component. This is where actually what I want to do, I want inside home components to fully copy paste this home directory and paste it here inside the boards, inside components folder. So actually you can use Angular generators if you want to. I really just want to copy paste module. It is faster for me. So here I want to rename this components to boards, and this is our root component of module boards. And inside we have two files. First of all, boards component HTML. Secondly, boards component ts. Here inside the HTML we can simply remove everything and just write boards so we can check if it's working. Now, we can jump inside of our boards component. And here first of all, we can change our selector and we can write here boards and our template URL will be important component HTML. Now here inside we have our class, which is boards component, and here we must remove implements. We don't need it for now. And they will remove all code from our boards component, and we can also remove all inputs. So we successfully created our new empty board component and we can now use it inside of our boards module. Here we can write boards component and do this. Auto input it here on the top. And now here we have a route for slash boards. And here inside declarations we can define our boards component. And the last step that we should not forget is we must register this board's module inside our app module. So here inside our inputs, we must add boards module. Let's check if it's working. I don't have any arrows here inside web server. Now I want to jump to our page and reload. And as you can see where on slash words here is our text. If I will jump here on the homepage, I will be directly directly to the board because I'm locked in. Now, let's check if we will be redirected back. If we're not login. For this, for example, we can simply remove token and reload the page. And as you can see here, we're getting unauthorized, but when not redirected back to the homepage. And essential for this, we created inside our house services r squared, and we can use this R-squared now inside of our boards module. So inside boards, inside boards module Ts here on the route we can attach, can activate. And here we must provide an array with World Service that we created previously. It is totally fine to use it just like this. We don't need to register it here. As you can see here, there are no errors. So let's reload the page. As you can see now, we can't jump to our sludge sports and were redirected to the homepage. Which actually means r can activate, is working correctly. And now just with a single line here, we can define what pages are allowed only for logged in users. So we successfully created our boards module, and now I want to create a port interface. And we could create it inside boards module. But actually, I want to create here inside AB new folder and call it shared. Because actually I want to put all types which we're using everywhere inside this shared folder. For example, task column board. These are all shared entities that we can use across different modules. The same goes with the services or services which are shared, like board service, single board service, column service, task service. We could put it in a specific module, but I really want to put all this stuff where we just fetch data to the shared service. This is why here we have AB shared. And here first of all, I want to create new folder types. And now inside our app shot types, we can define a new type and it is board dot interface. Ts. And let's export here our new interface. And this will be an interface of our board and we must name it port interface. And inside we must define exactly the same fields like we created on the backend. And first of all, here is NAD, it is a string. Secondly it is title, it is also string. Also we have here created that this is strained and last one is updated. It, it is also string. And actually here additional were getting user ID, just to remind you here inside our server source models and here we have our board. We have UserID, which actually means here we will also get user ID and it is string. Our interface for single Boyd is completely ready and we can use it in any component. Now I want to create the Service to work with boards. And actually any requests like create board, get bored, get boards, delete board will go inside the service. This is where here inside shared, I want to create a new folder and name it services. And then said we will create a new service which is called Boards service dot ds. So here let's now define our new class. So here we have class Boards service, and we must write on the top of it injectable so we can use it everywhere. The first method that we want to define here is get boards. This is exactly what we're prepared already on the back-end. So here is our get boards and we don't need to provide any argument here. And we will get back an observable with a ray of our boards. This is why here we can write port interface array. This is exactly what we just defined. Now inside this get boards, we want to make sure HTP request. This is why here we must try to construct and inject. Here are HTTP and HTTP client. Now, inside of our boards, we want to get a URL exactly like we did previously for the user service. So here we have our URL and it is environment. Don't API URL to us. And here is slash board. This is exactly our child. Now here we can return this dot http.get, and we want to get our URL without any options. And as you can see here, we're obviously getting an error. Observable object is not assignable to observable board interface. This is where here, as previously, we must specify that we're getting back in array of boards, so our services completely ready and they just want to test it. This is why here I want to jump back inside of our boards boards module and we must first of all inject the service here inside providers. Here we can write that we have here Boards service, and it is available fast. Now we're allowed to jump inside of our component here injected. So first of all, I want to define our constructor and we know that here we have Boards service and this is our boards service. Now, additionally, I want to write here implements on in it. And now uninitialized, they want to fetch this list of our boards. So here we have our energy on in it and inside they can simply write this board service, get boards, subscribe so we get the result. Here is some result. Actually this is boards and they just want to console log what we're getting back. So here we're getting our boards, coma boards. Let's check if it's working. But don't have any arrows here inside front-end web server. And let's login now again because we're locked out. So here I will provide our foo at gmail.com. Now as you can see after logging in, but I get into slash boards. And here inside console we can see boards. And this is a single board while we're getting it because in the previous video were created inside the console to test the pie this point and essentially this sub boards for our current user. Why is that? Because they actually here is our back-end request. Here we're finding our boards by user ID, which means we're finding all boards of this request user ID from where we're getting this user ID from our network request. Here is our board's request, and here is our headers. And as you can see here in headers on the bottom, we have this authorization and here is our token. This is exactly the information that our backend needs in order to deliver fast correct data of the current user. So as you can see, are getting of the boards inside module works correctly. And we successfully prepared our service to get a list of boards on the client. 22. Inline form: In this video, I want to talk about an additional module that usually live want to create for our application. And I'm talking here about an inline form. Let's have a look on the fully finished project that we're implementing. As you can see here, I'm on the slash sports page and here I just created a user. So we don't have any boards at all. And here we have create board. As you can see, this is just a square with some texts. But when I'm hitting it, you can see here an input without any placeholder, we can type here, for example, foo board, and we're hitting enter. And after this, our board is directly created. Here. We see this card again, and this is essentially an example of an inline form. So we have here some square with the text. Then we're hitting here and activate an editing mode where just type in something and we're hitting Enter. So the easiest solution here would be to simply create this component and throw it inside of our boards. But then we'll jump into a single board. Here on the left, we have exactly the same. You can see here the title of our board I'm hitting here and we're getting in edit mode. Here we see the title of our board, but now we can change it so we can update it and hit Enter and web date, the title of our board, exactly the same we have here with the list. This is just some texts time hidden here and we're getting here not only an input, but also a button, at least. And as you can see, styles are different in every single case, but it doesn't make a lot of sense to create additional component for every single case, like create an onboard, updating the name of the board, then creating a task, creating a column, and so on. Because also inside our column we can add the task and this is also an inline firm. This is why I really wise approach would be to create a single component that can cover all our needs. So what cases do we have? First of all, in any case, we have some markup. Then we have an editing state when we just click on the element. But as you can see, the markup can be completely different. But what is different is not the markup, it is just style it actually, if we will check here, as you can see, this is an inline font that I created and we simply attach here Create Task form. The main idea is that all these classes are available globally and we can just change them with CSS. Inside were provided in different things. For example, we can just first of all type some text that will be shown here, like for example at the current. But we can also show here that text like the name of our board. Now we're hidden here, Edit and we might want to propagate this text in the edit form. But here with a task, we don't need to do that. But also here we have a case where we have at Cart button and not only an input. So all of these cases must be inside this single component to work smoothly. So let's try now to create this component. And this component is super shareable. This is why I want to pack it inside AB srand. And here we want to create the folder modules. Here you might ask, okay, but we're talking about component. Yes, you're totally right, but you can't use components without module. You can either register component inside some module or you can inject module and injection module is much better because you can define what components you want to allow outside and what's not. This is where it typically when we want to share a component, I highly recommend you to create a module for this. This is where here we have a modules and we can create a new folder which will be inline form. And this is exactly the form for all this cases. Now let's jump inside and create here inline form dot module.js. And inside here we must export our class, which is inline form module. Now on the top of one to inject our NG module just like we did previously. And here we want inside inputs to add our common module. The next step is to create our components. So here we will have components folder, and here inside we will have our inline form with two files. First of all, in live form dot component, dot ts, and secondly, inline form dot component dot HTML. Now let's just try it inside some texts, for example, in line form. And let's jump to our inland from here, expert, our class inline form component. Now here on the top we must define our component. The inside we can provide a selector, and those selector will be just inline form. And here we'll also need to provide a template TRL. This is inline form component HTML. So our basic component is ready when mass now registered inside module. So here first of all, our declarations, we will have here inline form component. And secondly, and it is super important is experts because here we want to allow using this component outside. This is way here we're adding inline form component inside experts array. Now let's jump back inside our component and define some inputs as earlier this set. First of all, we want to provide a title for our inline form. This is why here we have an input title and this is a string, and by default it is an empty string. But it is important to distinguish between the title of the form. This is what we want to change and just the texts that we're showing because we need different things in different cases. For example, you want to run the some default text, but when you are hidden on our phone, you want to render another text. And this is essentially title, but we also now need here at default text, this is what we're rendering when we're not activated our firm. Here, let's create default text, and this is a string. And here I want to make a really nice twist. I want to write here, not define it. And this is essentially what I recommend you to do a lot if you just start to implement something or even for production, when you are not sure that you have some data, it is much better to set not defined it than just undefined it or just empty string. In this case, people can directly see that the value is not there and it is not broken. Also have a case when we want to show a button, this is where here we must create one more input, has button and it is Boolean. And by default it will be false, which means but don't render button. If we have a button, we want to change the text on this button. This is where here will be our input with button text and it is a string. And by default they want to set it to submit because this is the most popular type of the text. After this, we'll also want sometimes to provide a place holder for our input. This is where here input with input place holder, and this is a string, and by default it will be an empty string. And the last thing that we need is an input type because we have a case where we're mass trend and not an input but a textarea. This is where here I want to write input with input type, and this is just a string. We could create an enum here, but I will leave it like a string. By default, we can write that this is just a string input. And at the moment when we want to write the text area, we will provide here a string text area. Now here we're also must define an output. This is the values that we want to propagate after submitting a form. This is by here, Let's define an output endless name it handle submit. And this is new event emitter. And here there's an important point. We must input it from angular core and not from node, and then say add new event emitter. We want to provide that type of data that we want to get back. And it will be a string because the noun form, we have just a single string that we want to give back. Also here we need the local property to handle is edited by default, we need is editing to set to false, and then we activate editing, we set it to true. This is y here is editing will be a Boolean and by default it will be false. And last but not least, here we want to create a reactive form. This is where here I want to provide insight constructor private if b and this is form group and we're already created reactive form previously for our registration. This is where here we will use exactly the same, but we'll just create here a form. And here we can write this dot FB dot group. We must provide inside our fields. And in our case we have just a title. And here we can say that this is an empty string. And actually here I made a mistake. If b is not firm group, it is actually form builder. So here we need another input. Now let's write some market so you understand the logic Beta. So here I want to jump inside of HTML and we don't need this text. Now here we first of all, I want to create a div, and this div will be our default div with some markup. This is why here we need a class which we can use them globally and over, right, for our needs. So here we can write inline form container. Once again, we're not writing any styles for our inline form container. Every single use case must create their own styles. Also here I want to create another class also for styling if in editing mode, this is where I will create in G class. And here I am providing an object, whiskey glass in line dash, dash container. So the same name, dash editing. Here we're providing the value is editing that we just created. The main idea is that we're given enough classes for other developers to use this component and to style it properly for every single state. And the last thing here is, of course a click. We want to activate our editing. So let's create here a new function, activate editing and with don't need to provide anything here. Now let's define this function. So inside our file here on the bottom, we can create activate editing and what this activated it and is doing it. First of all, set this dot is editing to true, but it is not all. We have a case where we want to see the value that we want to change. For example, we have an edit form like fun name of the board. And for this we provided inside this input title. But as you can see in our firm title is empty, which is correct. But in our case, when we're jumping to the editing, we want to set our title. This is why what we can write here if we have a title. So if we have this.title, then we want to put it inside our form. And for this we can write this dot form dot pitch value. And inside we're provided an object with title, this title. So what this line is doing, if we activate it in editing and we provide it a title inside, then we will update our value of the form with function pitch value. Now let's go back to our HTML. So inside of a div with Festival one to create a div that we will show when we're not in the editing stage. And this is just a text with some class that we can style. This is y here, div class. Here we'll be inline form text. And here we want to show this DFF only one. We're not in the editor and state this is way here, NADH is editing. Then we show this div and inside one to render our default text that we're getting in the input. And after this, we're creating our form, just like we did inside registration. So it is reactive form and well-defined our form group. So here we can provide our form group. This is our form and we'll also have here NG Submit. And we must create onsubmit function. But let's finish with this form here. First of all, we want to render this form only one bar in editing stage. This is why in GE is editing. And we'll also want to provide a class for styling and we just name it inline form. Let's jump back now inside this file and create here our onsubmit function. And here is the tricky part. We could open up a form, don't provide a value, and then just hit enter. And this is not what we want to emit. It doesn't make any sense to meet empty string. So here we want to check it. If we have this dot form, dot value, dot title, only, then we want to emit it. And for a meat, we have this dot handle submit a mid, and inside we're providing this firm value dot title, which actually means if we're submitting this form and we have an empty input, we want immediate what we want to do after we want to close our ears editing state, This is why is editing equals false. And we'll also want to reset our firm to the initial state. This is why this dot form dot reset and this functionality we're getting from the Angular out of the box. Now, let's jump back to our HTML. Here we have a form. Now we must define an input. So here let's create an input with a type text. And we're getting here inside form control name. And when in this flower reactive form, here we have our name title will also want to create here a class for styling. So here class input form input. We also want to provide here our placeholder and we're getting it from the input. So it is input place holder and we want to render this input. Only one who provided the correct type inside. Here will be NG IV with input type, where our input type equals input. And now we want to do exactly the same width textarea. So we have here at exterior and we want directly to close our text area. And now inside we want to check this NG IV. So here our input type equals textarea, then we will randy. But we're also must provide here a form control name, and this will be also a title. And also we must provide here a class. And in this case, class will be the same input form input and after how it extends over mask, create a button for submit. This is where here in button and inside we will have our text, button text that we're getting from the input. And we want to render this button only if we have a proper input. So if we have an input has button, then we will render it. Then here we want type submit, and here we want to disable it if it is invalid, this is where he is disabled and we can use form dot invalid. And after this, we'll also want to add a class to style it. And here will be inline form button. And actually with these are input form is completely ready. So what we're doing here, we have a div, we have here activate editing. We have here different classes for every single element here were rendered in our default text and here is our form with input or textarea and button if we need it. So in the next video, we will try to use our inland firm on the use case of creating the board. 23. Implementing creating a board: In previous video, we successfully prepared our inland form, but it is not clear how we will use it with just created it with all possible values inside. In this video, we'll want to use it, but we don't have anything inside of our boards page. This is the way to put inside our inland form. We must also generate our boards page. And here we have mostly online markup because we already have access to our boards, because we already created get board method and we subscribe to it to get our boards. So let's start with our markup here we can remove the sports world. And first of all, on the top, I want to write up top because actually in this video, we won't implement our top bar, but we should not forget that we need to implement it later. And here we can start our markup. So first of all, we have here boards, page container. Now let's close this div and inside we will have one more div with class home left sidebar. Here we're closing our div. And actually here we're creating our sidebar on the left and inside we will have links to our different pages. This is why here we have a router link and we want to provide here a link on slash boards. After this, we'll also need to add a class here, boards side menu option. Also here we want halite the link when it is inactive route and an Angular for this we have a special attribute which is called router link active. And actually it is a directive. And then said, we can provide what class put want to get. In our case, we want to get a class boards side menu option selected. Let's close our a here and inside. Let's try texts. It is boards also. Let's set here one more link which will be home. This is why I will copy paste completely this a router link here will be slashed. Same class router link active. Here we can write not boards but home, but also here we want to write router link active options by that, because actually here we have routed link slash and we have slashed in every single router link. This is why this router link active will always highlight this element we want to avoid this. This is why we must provide router link active options. And here inside we're providing an object with field exact true. In this case, we will highlight this lean on loop and we have full mesh on slash. And actually from our perspective, it doesn't make a lot of sense to create these two different links. Because when we're locked in but can't access our home, which means we will be directly redirected to our boards page. But this is the markup that we're getting from the project. So we simply implement what we have after our sidebar. We must create a main part with our container for the boards, this is where here will be div class Boards section container. Now let's close here div and inside we want to create one more div. Here we will have div class my boards. Let's close this div and inside of it we want to create one more class with a header. This is way here, div class, my Boards section header and inside we must create one more class. And it will be the glass boards page header, name, and inside we will try it. My boards. After our header, we want to render our list. This is way here. We will have a div board tile list because we will have here each board as a tile. Here we can close our div and inside this div, we want to render our inline form. I will end it in a second because for now I want to just finished our markup. And after we inline form group one to render all our tiles, which are boards. And for this we will write our graph here, so a router link. And here we want to provide a link to every single board. This is where here we have a dynamic parameter. So here we can provide an array with slash boards. And the second parameter we're put in here, comma board dot ID. In this case, we will generate correct router link to every single board. But in order to get access to the board here we must write and G for loop. This is way here in G4 and we're looping through our boards. So here let board of boards, and here we'll also missing our class. So here we should have board tile and let's close this a. Now inside our a link, we want to provide a div with class board tile details name. Let's close this div and just render inside the name. It will be bored tile and they'll markup is fully ready. Let's check if it's working. I actually have here an arrow because they used property not correctly. Here, we should put double brackets and not single brackets. Let's check again. We have a narrative that we don't have property boards, and this is completely valid inside our type script. We're getting our boards, but we simply have here console log with Dan, save them. And actually we must do it this way here on the top we can create boards property. It will be our board interface that we already have. This is an array and by default we will have an empty list of our boards. Now here instead of our console log, we can simply assign to this board's, our boards that we're getting from our service. Let's check again. As you can see now we don't have any error, but we have an error board. The tile does not exist. And this is why I like TypeScript so much. It was simply a typo, but we don't debug it in runtime. We simply have a validation of TypeScript. So here should be title, and now we don't have any error. You shouldn't be valid. Let's check this out. I'm reloading the page and actually it is looking somehow. We have here our app to bar. We didn't implement it yet. Here on the left we have a Boards link and home link. So links are there. And here is our main content with my boards in landforms that we will create an a second and our first board with the correct link. And as you can see here on the bottom, it is slash port, slash id, which means our URL is also working. But I have a small typo in markup. As you can see, our sidebar is not looking that great because here inside of a div class home left sidebar, I missed word container, so it should be home left side, but container, as you can see now, our sidebar is much bigger and it is looking better. So as you can see, we successfully fetched our boards with this code inside our component with our service. We save this information to our boards property and was rendered our list of boards. And actually here inside our network, we can see that we have a request on local host for 1001 slushy pathless boards. And we're getting our single board that we have. And now it is time to talk about inland firm. So how we will use it here inside our HTML. And for this, I want to open our inland form here on the right so we can understand what we have inside our component. So here we have lots of inputs. So what we should provide for this specific usage, actually here we're right in that we have our inline dash form. Let's close it here. And now first of all, inside, I want to give a class. And the main idea is that this is the parent class that we can style because we want to apply unique styles to our component. And just to remind you here we have classes like inland from container, inland from text and song. The idea is that this class plus this class will override any CSS. And this is exactly the idea. This is where here we're providing some class, for example, create board form. Now all these clusters inside will be simpler nested inside our CSS. The second thing that we need here is default text. And this is the texts that we will see on the card beforehand. And here we have our default texts, create new board. And the last thing that we must provide here is handled submit. This is what we're getting from our form. Here. We can write, for example, create board and we're getting here event. So what did this event, just to remind you here, we have a handle submit and it is a string. This is our title and we don't need here has button title, button text, placeholder, input type, just because this is the main default inland firm. Now let's check if it's working where jumping here inside console and die directly have an error. We don't have a method create board, so let's create it now here. This is a method where we're getting a string. So we can say that here we're getting a title, it is a string and back we will return void, which means nothing. And it lists here I want to consult our title, which were created inside our inland form. Now we're getting here and narrow argument of type event is not assignable to permit a string. And actually it might be super tricky for you to debug because you might think, okay, I'm providing here something differently. But the problem is not in this. The problem is that inside this module, we didn't inject inside our inland form module. This is where here inside boards module, we must import our shared module and it will be in line for module. And the main idea is that we're inverted here on a module, but inside we have an expert id component. This is why now we can use this exploited component inland form here inside our component. Let's check this out. As you can see, we don't have that error anymore. We have something different and we have here cannot bind to form group since it isn't a known property of the form, this is why what we must do. We must put reactive forms inside our inline form module. This is why I want to jump inside inline form module. And here inside the inputs, I want to write reactive forms module. Now we should not get such error. Let's check this out. As you can see, everything is green and we're ready to go. Let's check them in a browser where reloading the page and voila, this is our element. And it might be super difficult for you now to understand what is happening here because we didn't write any CSS and CSS was already prepared fast. So let's inspect this element. What do we have here? As you can see, this is a inland form and this is our class create board form. Let's check this out. What we have inside our project and our styles. We haven't said Source styles and here lots of styles and we're interested now in create board form. Let's open it, and this is our CSS. This is exactly what we see here. This is create board form. This is our parent. Most importantly that inside inland form, we have different styles. For example, here is div class inline form container and how we're styling it, we're using here our parent class that we have just here. This is create board form and then inline form container. And this is what you can see here. Always prefix here, all inland from classes with create board form, which is our parent form, just for this specific usage. So this is how we're making our inland from super flexible. It contains 0 CSS inside and we simply define all our CSS outside for every single case. This is why here we defined, okay, we have inland from container, you should have display flex, align items and justify content. Then if we need to style inline from texts, for example, in this case, we didn't stylish, but we could also just right here, create board form, inline form, text, and style this element. So this is how we created our awesome inland form, which is super shareable for every single case. Now let's check if it's really working. So we have here our default text create new board. We can click on it, and now we have our input and we can write something here. And they already see here a mistake. As you can see here, we have input with a class input form input, but this is what we're style and where styling inline form input, which actually means we made a typo there. Let's jump back inside our component, inland form component. And here we have our input and here we need to change our input form input to inline form input. And as you can see, we're getting exactly the same problem here in textarea. It should be inline form input. Let's check again. I'm reloading the page where hidden on the button, and now we have a correctly styled input. Now I can pay something like foo and then hitting Enter and our form is successfully closed. We see create new boards again. And inside console, we see our title for this is exactly our output inside board component. But what we're missing here completely is creating a board on the client and on the server. And now I want to do vice-versa. I want to start with the front-end and finished with the Pi. And then you can see how we're doing it in reversed order. So Festival here we have our Create board inside component. So the idea is that here we will use our board service. This is my inside our board service, we must create a new method. For example, let's name it create point. So what we're getting here, we simply get here at title and it is string and back we will get an observable with created Board, which means it will be bored interface. And now what we will have inside, first of all, we can copy paste the URL because it will be exactly the same. It is slash boards and we're making a post request. This is where here we can say that we're returning this HTTP and not get, but post. And inside. First of all, we must provide a URL. And secondly, we will provide here an object with field title. And actually this is our body. And for our board with just provide the title. Because on the backend with set just two things. This is title and user ID. And user ID, our backend must understand by itself because we're providing a token with our request and we are authenticated. The main problem is here that we're getting around typing. We must provide insight or a post. We're getting back our board interface. And in this case, we successfully created Create Board method. And as you can see all our API methods, I'll look in exactly the same. This is simply URL and then HTTP post get overthrow we need. Now let's use the service method inside our component. So let's jump back. And here is our Create board. And here we want to call it this word service dot. And here Create Point. And inside we're providing exactly the title that we got here from our inland form. And after this we're writing dot subscribe and here we're getting created board back. What do we want to do with this point? We simply want to change our, these boards rate. This is way here I will write this dot boards equals. And here we're spreading our thes dot boards and then they want to put our created board. So essentially we're creating here in your array, where inside we put all our fields from the old array and then are created board. So our front and this fully prepared. Now, we must jump to the backend and create everything there. On the backend. It is not that difficult because we're all created a model for the board and we can use it. We only need to jump and said sorority S. And here creating your API request. Here we can copy, paste up, get completely, and it will be up post on slash boards. Here we must use OS middleware because this is an authenticated request. And here we're using board's controller dot, for example, create board. And now we must create this method inside our controller. So let's jump back inside our board's controller. And here we want to create exactly the same, but it will be a post request to create a record. This is why I will copy paste this completely and just rename it. So here we have our Create board and we're getting here our request response. And next, and we have inside try catch here. First of all, inside where chicken for request use that this is totally fine. And after this, we want to create a new board. This is where I will remove this line. So here I will write that we're creating our new board and for this we're using you bored model and then said We must provide a valid object. Here. First of all, we're providing a title from request board, the dot title. And second is the user AD and actually use relative to mass take from our request, from our middleware. So here we will have request dot USA, dot underscore ID. And actually we can use both underscore ID or a D, doesn't matter. We have both of them available. So this line won't save anything to the database. We simply create here an instance of our model. And after this, we want to save this record to the database. This is why here we can try it saved board and we're using here a weight here, and you bought dot save. In this case, we're saving this record and we're getting our saved board back. And as you can see, this is a Word document. So after this we can respond with our saved board. So once again, we have a post request, we have a Create Board action here. We're checking that we're locked in. After this, we're using our board model to create a new board with the title that we provided and use 3D that we didn't provide. But God, from our locked-in user and we saved this new point inside database. We've got our saved board back and we're responding with this API. Let's check if it's working. I don't have any errors here inside back-end. So let's jump inside client here I want to hit create new board and I'm typing something and I'm hitting Enter. And as you can see directly here, we've got our new board. Let's check our network. And actually inside network, we have our board's request. And this is a post on slushy pie slash points. And what is more importantly here inside preview, this is our response. This is a title User ID. This is exactly what was saved inside the database, which actually means if I reload the page here, we are getting two boards now because this information is all the saved inside database. And here inside our network, we're getting our boards. And as you can see in the preview, we're getting already two boards and not one, which means we are fully finished with our boards page. First of all, be rendered here the sidebar, but we didn't do anything with it. We're also used here our inland form, which is super shareable. And we created our service, which is speaking to our API, to create a new board from this page. 24. Adding Top bar and logout: In previous video, we finished our boards page, but we forgot to implement our top bar. And actually, this is the TBA on every single page for a logged in user, which actually means not only my boards page, but a single board page also, this is why we must create it as a shareable module. So I want to jump to our client source app shared. And here we have our modules and inland firm. And actually here I want to copy paste this inline form completely and rename it to our tongue. But now inside the mass change everything. First of all, let's start from our module. So here we have a top bar module and inside with don't have any reactive form module, we simply will have some markup and the logout button. Here we can remove this input and we must change our component also. But first of all, let's change the name of the class. It should be our top bar module. Now let's jump inside our components. And here we don't have inland firm, we have our top bar and we have two files inside. First of all, it will be top bar dot component dot HTML. And here is our top bar dot component dot ts. Now let's change the markup. I want to remove everything in simpler right, top bar. Now let's jump to our ts file and remove everything from our component. Now I want to rename our selector to the top bar just to make it clear where it belongs. Actually, we have just a single Toba inside our application. We could simply write here Tampa, but as it is shareable for us, I will write here up top, but just in this single place, here we have our template URL. This is top bar and our component name is top bunk component. Now I can remove the symbols and just live here our input of component. Now let's jump back inside of a module. Now we don't have this inline form component, but we want to declare here our top bar component and expert TBA component because we want to use it outside. So our module now is fully ready. Yes, we didn't implement any logic inside, but we still cannot really bind it. And we want to jump and said boards module and inside our inputs we can add here top bar module. Now here inside our components boards, boards, HTML on the top. Instead of this text, we can simply write AP top bar and we can close it here. Let's check if it's working. We don't have any errors here. I will reload the page. And here on the top you can see texts top bar, which actually means we successfully binded our module and component to our boards page. Now let's try to market for our toolbar. This is where I'm jumping back inside our Tombow component HTML. Here, let's write it. So first of all, we have here div with class navbar boards. Let's close this div inside. We will have one more div, div, navbar, left side. Let's close this div and inside first of all, we will have a link to our home. This is why a router link. Here will be our slash, and here will be class navbar icon. Let's close our a and inside we must provide a new image. So here will be imaged source slash assets slash home dot SVG. After this, we will have one more router link. This is why I will copy paste it completely and it is going on slash boards. And it will be Naropa eigenspace, navbar boards icon. And inside we have another SVG file. It is slash assets slash boards, as you can see now, when I am reloading the page, we have two nice icons, one to the homepage link and one to our boards. But as you can see this here, rails are invalid. We don't have them at all because actually we must jump inside our top bar module. And here, import route module. Let's save this and reload the page. And as you can see now, this really links, first of all, homepage and here slash boards. Now let's continue with our markup. After our left side, we have our right side. Here. We want to provide our image with source slash acids, slash Trello logo, white dot SVG. And here is our class navbar. Longer after an image, we have a div with class navbar right side. Let's call this t. And inside we want to create a link follow gown, this is y. Here will be div class, navbar icon, nav bar, logout icon. And here inside I want to simply write log gout text. Let's check if it's working. Here we have our links on the left, we have trailer image on the center, and we have a button as the logout link on the right. But we didn't attach any logic here. So our top bar is essentially fully ready. We implemented everything, but we need now to implement our logout. Logout implementation is really simple. We just need to remove our token from local storage, clean currentUser inside our memory and redirect or use it to the homepage. This is what we want to do here. We want to attach a click event. So here let's right-click. And what we're doing, we're calling our logout method. And number must create this logout inside our component. So what do we want to do inside? Actually, I want to store our logos logic inside our service because this is related to authentication and they don't want to write this logic directly here. This is y. What we must do, we must inject our hours service, which is our service provider inside this component. And now here we can use our this dot out dot logout. And actually we don't have such method. We must create it, but it is not all, but also after this one to redirect the user to the homepage because we're not logged in anymore. And for this we must inject here router. So I can adhere router and it will be our drought. After colon are our service. We can write here this router dot navigate by URL, and we simply want to redirect the user to our homepage. So we're almost ready. We just need to implement our logout method here inside of our service class. So here on the bottom, I will write log out with don't need here anything. We simply want to remove our token. So here we can write local storage dot remove item and were provided inside the target. This is enough, but we didn't clean our memory. And actually this current users still has a valid current user. This is not good. We must set it to now. This is why this dot current user dot. Next, we're provided inside now and with this single liner, all our components will be notified that we're not locked in anymore. Let's check if it's working. I don't have any errors here. We don't need to implement anything on the backend. Now let's simply hit here logout. And as you can see, boom, I'm directly on the homepage and we can check that we're not locked in. Actually been named jump in here inside application local storage. I don't have my token. This is why when I'm reloading the page, I'm getting 401 Unauthorized, which actually means we successfully implemented our top bar and logout functionality. 25. Creating board module: In previous video, we successfully finished implementing our boards page. In this video, we're starting to implement our single board page. And we're focused here just on creating our basic module and component. This is why I want to jump inside source set. And here I want to create a new folder with new module. And actually you might say, Okay, but why we don't pack our component board inside boards module and yes, you can do that, but I want to split it because the logic inside this two modules is quite different. We still need to pay quite a lot inside our board module. This is y. Let's create here a new folder which is called board. And inside we want to create our board dot module.js. Also, let's directly create here our components folder and mu folder inside which is called board. And here we need two new files. First of all, board dot component dot ts, and secondly board dot component dot HTML. Now let's trend inside of HTML, word boiled, and let's create our component. So here we can export our new class, and it is called board component. And on the top remastered a component decorator. The inside we want to provide our selector and we can simply say here that we have selected board and we're also must provide here a template URL which is poured component HTML, our board component is fully prepared. We must know create our module. So here we want to export new class, which is called board molecule. And we want to add on the top of decorator and GI module and provide insight, at least the list of inputs. And here we will have first of all, common module also now we can create our declarations and provide insight, our board components that we just created. So we want to register here in your route. This is where here on the top we can create a new property which is called routes. And it is our shouts, which is an array. And inside we must provide a new object with field path. And here we will have the URL boards slash, and here we have colon board ID. What does this board ID means? It means that we have a dynamic parameter, which means here we have a board ID and it is different for every single board. After this, we must provide here a component, and in our case it will be our board component. Also here I want to use the word service. This is why here we can write, can activate. This is an array, and here is our required service. Why we're doing that? Because this URL is only for logged in users. If we're not logged in, we don't want to access this URL at all. And now we must register this routes inside our inputs. So here we can put route module dot for child, and here we're providing insight our routes. And last but not least, we must register this module inside our app module. So here inside our inputs we can simply write board module, and this is our new module, which is inputted here on the top. Let's check if it's working. We can jump now inside our browser, open our dev tools. Here we can click on our first board. And as you can see now we don't have any error. We see here on the top word board and then the URL we see slash boards, slash and they D of this specific board. What we need to do now is to get a single board for this specific page. Why is that? Because actually we don't jump always from the boards page to our single board. And you might say, Okay, well, on boards page we have all our boards. But then again, when we're on this single page and reload the page, we don't have any important information, which means we must get this AD from our URL and get this specific board with the CD. Also additional information later, like columns or tasks. This is why I want to open our app, shared services, boards, service tiers, and the sale will be set previously here we're writing all our requests to the dye, which are related to our boards. This is why here we can create a new method which is called get bored. And then side to get a board, we must provide a board ID, which is a string, and back we will get an observable with our board interface. Now, inside here we must prepare our URL. So here we will use environment Doherty Pi URL plus, and here we want to concatenate our boards plus AD. This is why it makes a lot of sense to use ECMO scriptSig strings here and inject inside this environment DPI URL. Then we have here slash, boards, slash, and here is an AD as an argument. And actually it is not an AD, it is born and AD. So this is the URL that we want to fetch from the backend. And now we must return our request from this dot http.get. And we're providing insider get our urine realm that we want to fetch. But again here we're getting back observable of objects and we must specify that we're getting back our board interface. Now let's try to fetch this URL. This is why we must go back inside our board module, components, board component. And here inside I want to create a new method fetch data, and this method will return void. And inside we want to use this method that we just created to fetch our board by AD. This is where here we're must provide a constructor and here will be private boards service that we have ended this Boards service. And inside our fetch data we can write this dot board service dot, get bored. We're providing insight board ID, but we don't have yet but a D in this component. And actually we must store this board ID from the URL in this, because we will use it a lot inside this component. But if we will write here board ID equals string, then we will get here a narrow board they dig has no initializer and is not defined it in the constructor. And actually, we don't want to get here undefined it because it won't be comfortable to work later. Board AD is mandatory for our component. And to get the perimeter from our URL, we must inject here route. So here will be private shroud. Here we want to use activated route. Now here inside we want to try and read this activated drought. So here I want to get board ID as a parameter and we're using here this dot shroud, dots, snapshot, dot params map get here will be board Id. And this is how you typically get parameters from the URL inside Angular. But as you can see, this is what we are getting back. We are getting strain on now, this is totally reasonable because Angular can be sure that this parameter is always there. This is why what we can write here, because we really want to save just a string. We can check and throw an error if it is not there. This is why here we can write. If we don't have our board AD, then we will throw an arrow. Here will be throw new error, for example, can't get bored AD from URL. And after this, we simply write this board ID equals board Id. And as you can see in this case where sign-in inside the string, because we checked here for TypeScript that it is not now. And if it is now, then we're throwing an error. This is actually the best wherein that we can do in order to get a string in this component. Because it won't be comfortable to check every single place that we are getting this parameter. And now here inside good board, we can provide insight. This dot board AD. After this we can write dot subscribe and we're getting back our board and we can assign it and save somewhere. But at least for now, I just want to console log our board Comma board, but we didn't call this fetch data somewhere at all. This is why here we must write implements on in it. And now after our constructor, we can in June in it and inside we can call this fetch data. And actually every single time in every component where I need to fetch some data, I prefer to create an additional method for this, which is called fetch data. And not just throw this logic inside and join in it just to make it cleaner. As you can see when we're jumping to the browser, we're making now request on our slash api slash, forward slash and this specific ID from momma parameter, which actually means we successfully implemented on the client or when you bought module and even fetched our board from the backend. Obviously we didn't implement a back-end part, and we will do it in the next video. 26. Getting a single board: In previous video, we successfully implemented the front-end part of our board component and port module. But now on the backend, we want to implement getting a single board. This is exactly the request which is broken here. And I think that we implemented a lot of stuff together and you already didn't know how to do that. This is why I highly recommend for you to implement it on your own. As always say, have three different levels for EU level number one, you just pause the video here and do it yourself. At the end, you must get here our board from the backend, level number two, let's talk about it. So what do we need to implement? First of all, I want to open here our server source server. And here we must provide in your request and it will beget on slash, api slash boards and then Boyd AD, and it must be a dynamic parameter. It must be protected drought. Inside of our boards controller, we must create a new action. Now we're jumping here inside controllers boiled, and we simply do exactly the same like we did forget boards. But here Groupon to find a single board with the d of this board from the URL. So if you want to do a level to just pause the video here, and if you just want to do it together, Let's get started. First of all, we must jump back inside our server tiers here and create a new API URL. So here we will have apt-get slushy pie slash boards and here risk colon board ID. Now we want to create a new method. This is why I will jump inside or controllers ports and here we have get bored. They want to copy them completely because they will be super similar. So here I copy pasted, get bored, and they want to name this method, get bored. And here we are getting request response and next, and we're checking if we're locked in. Now here instead of find, all boards, will want to use find one to find just a single board. And actually even better we can use here find by ID. It is also a method which is possible and inside vermis just provide an ID of this sport. This is why we can remove an object and simpler right here, request dot params dot board Id. And back here we are getting our board and we simply send this board bag inside our API. Now let's check if we use our method correctly here, and here is board's controller dot get boards. This is not correct. It should be get bored. We don't have any errors here inside our API and we successfully implemented getting off the board. Let's check this out. I'm reloading the page, but don't have an error. Here. We're getting our board by d, and here is the information from the database. We have a D title and user ID. 27. Adding board stream: In previous video, we successfully implemented gauging of our single board from the API. In this video, I want to share my idea how we will use this board and save it. And actually it might be a little bit tricky. Why is that? Because actually here inside client, we have our board component and we simply can store it in a property here. This is totally fine. We can do that. But later we will have a model and this is where things will be different. Just to mention, we have here a page with the board and then we hit on one task to open this task inside model, the main problem is when we reload the page, we want to go back to that specific task, which means we want to have in our URL slash board slash board ID slash tasks slash task ID. Then we reload the page and we fetch first of all our board, then maybe all columns, all tasks. And we want to solve this task inside model, but does it have a mean? We're saving, for example, our board here inside board component, but we can't really use this information inside our task component. Why is that? Because later we will register our task component here as the child component of this path. And we can't really access in any way some data that was stored inside this board component from the child. What is the solution for this problem? We must use a service. How we can do that? First of all, inside of a board, I want to create a new folder which is called services. And here we can create board dot service, dot ds. Here. We should not mix our board service here with our boards service, which has shared services boards. This service is just to fetch data from the backend. If we want to get our boards, we use good boards, get bored, create board and so on. But what we're doing inside the board, this is kind of state for this specific page, which actually means here we will store our board columns, tasks, everything that we have in this page, and then all components in this page can use the service to get this information through streams. This is why here we want to create our class and it will be bored service. And here on the top we should not forget to use an injectable. What I want to do now here, exactly the same what we did with our current user. Just to remind you, we had here, our service. Here on the top, we created this current user stream that we can use across our application. We want to do exactly the same. Now here, we want to create here Board was taller and this is a stream and this is in your behavior subject. And we're getting here either board interface on now. And here inside we're putting now just because by default we will have no board. We didn't fetch it yet. And then after we fetch this board, we can set it and update the stream. This is way here we must create a new method, said board. And inside womb must provide our board, which is our board interface, and this is void. And here what we want to do, good one to call this dartboard Stoller dot next because we want to update a stream and withdraw inside our board. Now we should not forget to register our board service inside of a module. So here we must create our providers and we're writing our board service inside. And now we can use it directly inside our component board. So we don't want to create here property board. We want actually to inject here inside our constructor new property. And it will be bored service from board service. And as you can see, this is the difference we have here, both services, boards service and board service. And this is a huge difference. First of all, this is service to work with eBay. Second service is more like a state. And what we can do now with fetch data after subscribe, we can write and said this board service, dot set board. And we're provided inside of our board. In this case here we're storing this inside the stream. And now we can use this information not only inside our board component, but later also inside our task component. And this is extremely flexible and the best solution that I can imagine to share data between two rounds. And just to check that it is working, I want to create here on the top stream for the board. So actually here we have a board stream and we know that this is an observable of board interface. So we're showing here we must get a board. There is no other possibility. And to avoid this type script error with no initializer, we will write this code directly in constructor. This is totally fine. So here we can write this dot board with dollar equals, and here we want to use the stored service dot. And here we have our string, which is board dollar. And you might say, Okay, why don't we use this directly? Because here inside boards stream, we can get now inside of our component with don't need null at all. We simply want to work with our component when board is not now, this is why what we can write here, we can write pipe and then filter the result. So here just filter Boolean will eliminate. Now from here, we won't get here anything if it is now, we will just update our board. If we get a board, and now we can jump inside our HTML file and render here our board stream just to test, this is why board dollar. And here we're using a single pipe to render this information. Let's check this out. I'm reloading the page and we're getting object, object because essentially we've got adjacent and we must pass it with Jason pipe. Let's check this out again. We're getting here our board, and as you can see, this is our information of our board that prefetched. This is Title, user, user ID. So essentially the idea is that this service has information inside it, but we don't need to store this information somehow inside of our board component. We simply use streams from the service and use them inside every single component where we need to, for example, we will write exactly the same code inside our task component if we need the access for our bird, for example. What is more importantly, we can map data like this, which is really convenient. 28. Creating socket service: In this video, we're starting an interesting part of our application and it is setting up our socket layer connection. And just to remind you, we already set it up. So Quetta, you're on the back-end. So here inside our code we can open service source server test. And here on the top we have IR new server, and then here we have IR on connection. And here is our console log connect, which actually means we successfully set it up. So get on the back-end, and now we must implement it on the client. And for this we will use exactly the same library we're using on the back-end. Just to remind you here we used socket. This is y here inside console, I want to jump inside our client folder. And here I want to install a new package which is called socket Datta your dash client. And this is exactly the same package from the same team, but it is for setting up our client. And this package doesn't have anything to do with angular. This is just a plain JavaScript. So what do we want to do now at all? First of all, inside our clients source app, shared Insight services, I want to create a new service and it will be our service to work with socket. This is way here. Let's name its socket, DOD service dot ts. And now inside we must create our class which is called socket service. And obviously we should not forget injectable here on the top. So what we want to create here, we want to create a function which will generate for us a new connection. This is why here we can write setTab socket connection. And here we're getting our current user. Why current use it because they actually want to send some private data through the socket connection. Why is that? Because actually we will use socket. You're on the board page, which means our user is registered. But inside soak into yogis, we don't have such system like GET, like we used for authentication. We don't have HTTP headers there and we can't attach our token to our socket. But there is a way to pass our token by using socket. This is way to make this possible. We want to set up this connection for our current user. And we can then throw the token from the currentUser inside our socket connection with every single request. So as I said here, we're getting as an argument current user and this current user interface. And back we're getting void. Now inside here we want to use our ion. And actually I must input here on the top or your drum. And here we have our socket IO client. Now here inside the ER, I can provide a URL where we want to connect. And actually here we can just try to HTTP and our port of the server. We don't want to use that because for this we have environment variables, which actually means we want to jump inside clients source environment, yes, and here like we have our API Euro, we want to create socket a URL. This is where here we can create sockets URL, and this is the http localhost. Here we have 4,001 and we don't need to put here slash eight pi because we set up our socket layer connection directly on our server. And you might say, okay, but we could reuse this API just like a single property for API URL and socket IO. Yes, We could, but I highly recommend you to split it to two different properties. In this case, it is easier to split it later if you want to move your socket layer to another web server. Now inside our socket service, we can use our environment. This is way here, environment dot, we have sockets, URL. This is exactly what we must give inside-out or your connection. And excellent. Now additionally, I want to provide the token from our current user because actually we set up socket layer connection only for login user, which means we never have a case that we don't have this token. This is way here, we can write field hours and then side we're providing talking, which is current user dot token. And actually here as the second argument, we're providing an object with our field and this outfield inside socket IO is exactly to authenticate a user. And what we're getting back is the result of our AR is this socket connection. This is where I want to write this socket equals IR. And here we must create this property, it inside the socket. And as you can see, this is our two input. This is not correct. We want to import the socket from Socket Layer client, or it is undefined it because by default we don't have a socket. And then at some point we set it up by using setup socket connection. Also additionally to our setup function, I want to create disconnect function, which actually means at some point our user will be locked out and we want to disconnect him from our socket connection. This is where here let's create an additional function disconnect. And this is really simple. What we want to call here, we want to write this dot socket. And here we have a method which is called disconnect. And as you can see here, I don't get an autocomplete because actually this socket can possibly be undefined it. And there are two possible variance how we can fix it. First of all, here I can just put question mark and I'm done. But I don't want to write the code like this. I really want to notify a developer that if we don't have socket, we have a problem. We can't really use disconnect before setting up our connection. If we don't have this dot socket, then we want to throw and narrow. So here will be throw new error. And for example here socket connection is not established. So our basic sockets Service is successfully created. Now we must at some point implement the setting up of socket connection and they really want to do it inside our app module. Why is that? Because every single time when we are authenticated and Berlin, now that we've got currentUser, would want to set up a connection. This is where we can jump inside our app component. And here we have a next. And just to remind you, here we are getting current user every single time when we start our application. And here we're setting current user and we can, before here, set up a connection. This is where here we can write private and we have a socket service, and this is our socket service. Now here before we can write that we have here these dots, socket service, dot, setup socket connection. And actually here we're getting our current user and we can give it inside. Let's save this and check if it's working, as you can see here with don't have any errors and then jump into the browser. And here it is red, we're getting an error. No provider for socket service ended this happened because we've created our socket service, but we didn't injected inside of a module. And here we're using the socket service inside our app component, which means it makes sense to inject this module inside our providers. This is why here we can write socket service and we're good to go. Let's check this out. I'm reloading the page and we're getting another error. So whatever we're getting, we're making this request on socket a yarn. You can see it here, but we're getting an error. We have a course, which means cross-origin policy. Because here with don't have access control allow origin header on the requested resource. And this is actually completely correct and we must unit inside of Serum why it is happening at all, because our server does not allow connections from other host and will for sure use here another host, this is local host for 1200. This is why we must go inside of a server source. And here we have our server tiers, and here we must configure our IIS server a little bit differently. So here as the second parameter, we can provide some options and we're looking for the option which is called cores. And inside we can set origin star and actually start means that we're allowing connections from any host. And on the rail project, you might want to write here just a host of your domain. But for our purposes, origin star is completely valid. Let's check if it's working. I'm delighted now the page and we don't have any errors. Now, we can jump inside network, and here as you can see, we have WebSocket connections. So here we're getting into hundreds. And if you can see in your browser something like this, it means that your request of the socket connection is that. And actually now we can jump inside our backend console. And here we can see connect three times because every single time when I reload the page, there is a new connection established, which actually means we successfully created a socket connection on the client. Now the only question is, what is about disconnect? We create a disconnect but could didn't use it wherever we want to use it. Actually would want to use it inside the logout. This is where we can jump inside our app, Health Services and here results service. And here we have our logout. And here we first of all remove our talking, then when null and our current user. And here we can use socket to disconnect our connection because we know how we use it is not locked-in anymore. We don't need this socket connection. This is y here inside the constructor, we can inject our new socket service, and this is our socket service. Now here on the bottom inside our logout, we can write this socket service dot disconnect, and we will disconnect our current user and close our socket connection. 29. Joining and leaving board: In this video, I want to show you how we can use sockets on the example of connecting to our board and disconnect them to the board. What does it ever mean? Actually insert socket IO. We have such thin which is called rooms, which actually means when not just notifying our backend with some socket message or another client when they define all clients which are connected to specific room. And actually when we're talking about boards inside trailer, it makes a lot of sense. We really want to notify only users who joined this specific board. Which actually means, for example, we have two different users. One user opened board, full. Second user open board form. Now the first user created a task and we must notify a second user about creating this task because he's connected to this room or this board. This is where in this video we will implement how we can join our board and leave our board. And for this, we must create a new method inside our socket service. This is why I want to open our circuit service tiers in here, create a new method which is called emmet. Why we need this method at all, actually insights socket itself. We have these dots, socket, dot and meet, and we can provide just a string like foo. It will be our emit message. And here we can provide some information, for example, Ambar string. This is how we typically can use sockets inside our application, but I want to wrap it in additional method for two reasons. First of all, we want to isolate a library and create a wrapper. In this case, we can always throw away this usage, for example, socket to your client and use some another library. Secondly, here I want to validate that were connected to socket a yarn. This is way, here is our image and we're getting here, first of all, our event name, it is just a string. And if you don't know inside socket IO, we're always emitting just with unique strings, which we're listening on other clients or inside our backend. And the second here will be a message in here I will write any waste, any, because it's a message we can provide a string and no object or any data that we like. And here we're getting a void, but we want to do inside. First of all, I will copy paste this line to check the socket connection. Because if we don't have a socket connection, we can't use a meat. After this. We can simply use this socket dot commit and were provided inside our event name comma. And here is our message. So our image function is ready and now we can use it. And actually I want to use it directly inside our app board components, board component, component ts. And here we have in June init method. And actually it is a nice place to put just here joining of the user, which actually means every single time when this component is loaded, it means that uses jumped to this specific route and we must join the user if he changed the route and we want to leave this room or this board. So with disconnect a user from that specific room. This is why what we can write here. First of all, we must inject here our socket service. This is y, here will be socket service, and this is our socket service. Now here we can use this method and write this dot socket service dot. And here we have our image and we must provide insight first of our event name and secondly some data. So essentially what we want to write here, something like boards join. And here our message will be, for example, an object with board Id. And here we're providing the board Id of this specific URL. This is this board ID. We already have this information. Why I packed this information inside the object. Because deflate, if for some reason we want to put here more information with the object, we can directly do it. If we have here, a string must reflect all these places from string to the object. And as you can see here, we can emit any strain. We can write here for. It is totally fine, but we will have a lot of different socket events and we want to organize them somehow. This is why here I prefer to use boards, which is a plural of some entity, like boards or maybe columns or tasks. And here we have what happened? For example, we have joined, this is just a start. We can later make something like joint success if it is in a synchronous process, which actually means for now, birds join is fine. What is not fine is that we're writing here a string where right in TypeScript and we must use innumerable. And actually innumerable is just some constants inside a single property. This is why here on the right, I want to open our shared folder, and here we have types in. Here. I want to create socket events dot in m dot ts. Here. Now we can export our enum, which is socket UN's ENM, and this is just an object in here we can write field boards join equals, and here we're writing boards join. So first of all, here we have some code style. Second Luba not drawn here, a string. Right in here, socket events in m dot boards chain, in this case in every single place where using the same string, but we will never write it incorrectly because we're using here Justin unum, which is a variable and not a plain string. So what this line does, it emits for our back-end in new socket IO message. Here were provided some string and some data. Why we are providing exactly this data, because we want on the backend to join our current user. So our current socket connection to the specific board. And this is enough for our backend to react for it. Now, it is time to implement it on the back-end side, this is where we must open our servers source. And here we have our server test. And here on the bottom we have our own connection. This is totally fine. Now inside we can remove this console log and we want to react with our socket dot on, on some events and actually hear what we're waiting. We're waiting Boards joint. But here we have exactly the same problem where inside backend and we don't want to write just plain strings. We want also to organize them in the enum. And actually we will duplicate exactly the whole file of our socket events in the client and in the syrup. And you might say, okay, this is useless. We can create just a single file. You could, but potentially you can split your client and server into different repositories and then you can share anything between them. This is why I really want to isolate our client and our back-end. So what we want to do here inside our types, we can create exactly the same. It will be our socket events don't enum dot ts. And now inside they will could be placed exactly the same code like we have on the client. What I want to do now here, instead of birds join, I can write socket events in m dot boards churn. And as you can see that this input is from types socket events. So this is how we subscribe to our event from the client with socket, the tongue, but from where we're getting our socket, this is our first parameter here. As you can see, this is socket and here we have socket dot on, but here we must provide two arguments. First of all, it is our event, and secondly it is our Kohlberg. So what we're getting here where typically get in some data, and this is exactly the data that we provided from the client. We could write here some logic, but we don't want to, because actually we wrote everything which is related to our boards inside control it. And it makes a lot of sense to write all our socket IO code also inside controller. We don't really care if it is Socket Layer or justice GTP. We can isolate all this code inside our controllers. This is where here we can use our board's controller dot, for example, join board. This is what we want to implement. And now inside first of all, I want to give higher than socket and then data. And we will in every single case when we're working with Socket Layer and give this information inside. This is super similar to what we're doing with our Express. Here. We're using birth control or create board. And actually this is how we directly give inside request response. And next, why we're doing that. Actually, when we're providing everything inside, we can use whatever we want. If we need a y'all, we can use a yarn when it's cycling. We can use this information if we need some data from the event, we can also use it. And now we just need to implement our joint. This is why I want to jump inside our controller sports. And here on the bottom we must create a new function. Here we have expert cones, Joan board, and we're getting here, first of all, Iowa, which is a server. Actually we have here lots of inverse. This is why you need to be cautious, but we need here we must input our server from socket IO. This is important. This is where we're getting a yarn and it is our server as a type. After this, we have our socket. And socket is also coming from socket IO. And last but not least here is our data. And actually we know that inside we're providing board ID, which is a string, and this is enough information for us. So this is how a typical function inside controller will look like when we're working with Socket Layer. And now what we want to do inside, we want to just write socket dot join. Here we're providing data dot board Id. And this is it, this is just a single line. So what this code does, so Wed shown in this current socket connection. So our current user to this board ID, and this is just a string, nothing more. But actually when we're writing join and some foo, we simply tell socket to join current socket to this room with this name, but don't have rooms in our application, we have boards, but the idea is exactly the same, where joining our users to the board and then they will receive our messages to this specific board. Now there's some who want to test that our code is working. This is why here I just want to write console log server, socket join. And here I will write comma data dot board AD in this case. But now, when we see this console log, it means that the successfully emitted our message from the client or the backend. And our backend reacted to the message and joined our user to this room. This is y here let's jump inside our backend and reload the page. And as you can see, we don't have any errors. And actually our code with this board component and this image will be triggered because our component was rendered. And now we can jump inside console and you can see service circuit or your join. And here is the d of our board. This is where we're joining our current socket. And as you can see inside the browser, this is exactly the d of our board. And now we want to do exactly the same stuff with living and board. And actually what they wanted to do, I want to create here additional method, this initialize listeners and actually all my listeners like subscriptions, for example, I always pack in this additional method. This is the same name in like for example, fetch data. In this case, they don't pack a lot of information insight in June in it. This is where I want to write, initialize listeners and subscribe here for live in a page. And actually we can do this if we're using a drought app and we have here a drought, but not a router. This is way here we must use router and it is our job. And now here we can write subscription to live in a page. And here we can write this dot router dot events. And here we have subscribed. And actually we subscribe, we will get here access to every single event which is fired by a router. And what we want to write here, if event, instance of here we have navigation start. And navigation start is the starting of change in our route. And actually if this is happening, then here I want to console log leaving a page. So once again, here we're using drought events to subscribe to all drought events. And we're getting with Subscribe access to every single event now here to check for the specific event where using instance of and we're providing here navigation stack. And here is our console log where actually we want to emit a socket message and this message will be live in a board. Then we need to disconnect a user from this specific board. Let's check this out. I'm reloading the page and we have a narrow I forgot to put a comma here on the top. So let's put it now and reload the page. And as you can see, we don't have any errors, but we can't really jump to another page where they can try to do here. I can just hit back and we're leaving the page because here we're now on slash boards page. And here is this console log, which actually means that this console log will fire every single time when we're living a page. But actually here I don't want to use sockets service summit. Instead I want to write here this board service dot leaf board. And actually you might ask, but why, why not just write in here socket amid the answer here, it is not on LinkedIn that we want to do inside of a board service when we're leaving the page. And actually here inside overboard service, we have the stream of the board and we're also must set it to now when we left the board, this is way here. Let's create our leaf board method and we just have here a void now inside. First of all, whoop, want to set this board next to now, which actually means we don't have a board anymore. And after this, we want to meet this message that will left the board. This is why we must open our shared types. And here is socket events. Here we have Boards churn. Now we can copy paste this message and name it boards live. And this is just bored. Leave. Now I will copy paste this line. And now here we can use our socket service. But for this VM must inject it here inside constructor. So here we have our socket service, and this is a socket service and we're using it exactly like we did previously. What I want to write here is this dots socket service dot m it and were provided inside our event name. And in this case it will be our socket events E and M dot boards live. And actually here we must provide what the board we must live. This is y here we're missing a board ID, which must be a string, and we must provided from our component. Here I want to put board ID. Now we must update our component. So here we have our board component, and here inside live board, I will write this dot port ID. So now we just need to implement exactly the same on the server that we did with joining, but we need to use live. This is where it Let's jump back in silos, servers, source, server it, yes. And here we have our connection and ports giant. What I need to do now, I want to update the socket events in them on the backend, and it will also be ports leave. And here I'm boards live. Now, here we can copy paste this lines completely and register one more socket on, not for boards churned, But for dot boards live guessing he has some data. And here we want to use ports controller, not join board, but leave board. And we must create now this live pod inside our controller. And actually here it will be exactly the same. This is why I will copy paste this method completely and just name it live born here we're getting our IR as previously socket as previously end inside data, we have our board ID. Now here inside console log, we can write our yard to leave. And here is data board AD and instead of socket joint, where right in here, socket dark leaf, and with this single line where we're moving our current socket from this specific room, which means we won't get any events of this board. Let's check if it's working. I'm reloading the page and we're inside. Now here I am hidden bag and we must dispatch the section for our back-end. Let's check this out as you can see here. First of all, we had here socket I adjoin and with join this specific room. And then when I hit back, we have a leaf from this room. And this is exactly how a client and begging are working together when we're using socket IO. 30. Authentication in socket.io: In this video, we must finish working on authentication now a user insights socket. But first of all, we want to fix one big problem. As you can see here, I'm logged in and I'm on the board page. But what will happen if I will log out? So I simply want to jump inside application and remove our token and reload the page. I'm now directly on the homepage. This is completely valid. But then at some point I want to authenticate again. I'm hitting here login and then paste in here f2 at gmail.com. And our password, I'm hitting here same mean. And as you can see, we don't have any error, but after the same jump into firstborn and we're getting an error, socket connection is not established why it is happening. Actually, we have our initialize socket connection inside our source app, app component ts, this code. So after page Lord, we're fetching current user and here we're setting up socket connection, but we're not locked in at the beginning. This is why we came here and we set our current user now, then we successfully locked in. And just to remind you, this is what is happening, where inside our components login. Here is our onsubmit here where subscribing to the login and we're sitting here talking and current user, this is totally fine, but we didn't update our socket. So our socket layer connection does not exist after registration or after login and don't live when we will reload the page, this socket connection will be established. Again, this is obviously not correct and we must establish this connection after login or after registration. And this is extremely easy to do. What we must do here, we can simply inject inside our constructor new property, and it will be our socket service, which is our socket service. Now here we can use this method. So for example, after certain token, we can write these dots socket service dot. And here we have setTab socket connection here well that they have access to a current user and we just throw it inside our setup socket connection. And we must do exactly the same inside our registration. So here first of all, we're injecting our socket service. So private socket service is socket service. And now after this, we can use this method inside our success. So after set token, it is these dots socket service, dot setup socket connection with current user. In this case, it will work properly. I want to remove are talking once again, jumped or login page and now try to login. So here is full at gmail.com and our password, I'm hittin say mean, and then jump into first part. And we don't have at this moment any error because we've successfully set up our socket connection right after we locked in. But we don't do anything with our authentication inside socket IO, and this is exactly what we want to do. So what is happening inside our setup socket connection? Here we're thrown inside our current user token. This is totally fine. From the front and side, we did everything that we need to. But now we must jump inside of a server and parse it accordingly. For this, boom must jump inside our server tiers. And here is your own connection. And actually before our own connection, move on to write here, dot use. Here we will have our function and it will be our middleware. And after this, we have our own connection, which actually means it is exactly the same, like how our middleware here move on to authenticate our request and know that we are locked in because our socket connection is only available to logged in user. This is where here we're writing IOUs and inside we must provide the function. And here it will be an asynchronous function just because we want to fetch our currentUser from the database. And here we're first of all getting our socket, which is socket, and we're getting, and next function, because it is a synchronous function we want to write here, try and catch. So first of all, we must straight try and where, kitchen and error and what we will happen inside catch. We simply want to write here next and throw insight new era with, for example, our authentication error. And here is a super important thing that you must remember. We don't have any errors inside socket. They are not there at all. We don't propagate any errors back to the client, which actually means if we're getting some error, for example, on the backend, we simply want to send a message to the specific client. We can send a narrow we just throw inside an object may be an error message with some error code or whatever you prefer. And it is important to remember. So Socket Layer is not working in exactly the same way, like how should it be errors? And now the first thing that we want to do inside our try is to get our talking from the request. And here we can write socket dot, handshake, dot, house, dot token. And it will be exactly what we're past. And actually here we're getting the token is any, and they don't want this, because actually here I want to get a string. This is why here I can write round brackets and just write S strain. And if we don't get this token, then I want to use here an empty string. Why I'm doing this? Because here we want to use Jason verify, to verify our token. And in this case we don't want it to be undefined. It. We can verify it when it is a string. This is way here. We can now try to parse are talking by using JSON web token. So here on the top we can import GPS from our JSON Web Token package. Now we can go back to our code in here, use it. So here we will have JWT dot, and here we have verified. And now inside we must pass first of all, our target. But just to remind you, inside of a token, we have Bearer space and then our token, this is where I want to split it by space and take the second argument. And after this, we must provide here a secret. And just to remind you of what the secret it is coming from our config. And this is what we're using to parse our JSON token. And this is what we're getting back. We're getting here a string or DVT PE lot. But here we really want to tell what we're getting back. Here. We're getting as always, our object, we say D, which is string. And secondly, we're getting an e-mail which is also string. In this case, we're getting correct data here and we can now get a user just like we did inside our Auth middleware. And for this we must input a user here on the top. So we're using now a user model exactly like we did previously. So we just use slash models slash user. And now here we can make a request. So here we want to get back our user, and here we want to make a request to the database with user dot. And here is our fine Bye. Here we can make find by ID because we have NAD insight data dot ID. And if we don't have our usable, want to throw an error. So here, if we didn't find a user, it means that we're not locked in here. We simply run return next and we're thrown inside new era authentication error, just like we did inside our catch. And after this, we want to write down this user inside our socket. Actually socket is our instance, and we can write inside the additional information just like we did previously with request. In this case, later in every single controller, we can access this current user. This is the way here, socket dot user equals user that we found. And as you can see here, we directly get an error property user does not exist on type socket and we must do exactly the same what we did with SAML request. Just to remind you, we created express request where we extended our request to put user inside. And now we want to do exactly the same but with our socket. This is way here. Let's create socket dot interface dot ds. And here inside we want to create a new interface, and it is called socket. And here we want to use extends from socket, socket. Actually here I have quite a strange name because this is not a valid input from the socket. This is way here. I want to import socket as socket or your socket. And I'm doing this from socket or just because we can't have exactly the same name. So here Gabon to export our socket and here were important socket, this is invalid. This is where we want to rename our input from socket IO and after this way extended from our socket, socket. And we want to add here our user. And it is not always done this way here there's a question mark, and this is a user document which we must also import here on the top from our user interface, Our socket interfaces there. Now we can jump back inside our server and use it instead of the simple. So just to remind you, here we have an input socket from socket IO. This is not valid anymore. Here Woburn to invert our socket from, and here is our types slash socket. Let's check if it's working. I'm scrolling here to the bottom, and we don't have here an error anymore. Socket user is completely valid and it is either user document or undefined it. Now let's check if our code is working. So I'm jumping here inside the console and we don't have any errors, so it is working. Now what I want to do, I want to jump inside our controller boards. In here we're making join board. So here instead of data board AT, I can console log here a user from mom, a socket. And actually here socket dot user is obviously invalid because here we didn't use correct interface. This is y here on the top. We don't need to use socket from socket IO, but we must import our socket interface that we just created from our types slash socket interface. Here we don't have an error. Let's jump inside console and check if it's working. And for this, we simply need to reload this page and we don't have any error. Now let's look inside the console. This you can see there is no message here, which means we forgot something. And what we forgot is inside the sayo use to write next, which actually means after this line, our code is not getting anywhere. This is y here, but must write next, and in this case it must work. Let's check again. Here I am reloading the page. We'll jump into our backend and as you can see, here is our information. So Socket Layer to join and we're getting here our user, and here we are getting two console logs because every single time when you update the page, we're getting this socket IO to join because this abuses happening. We're checking our user, we're getting it from the database. Now, it is available for us inside our controller. So with this code, we successfully got our user from the request. And now in every single action inside controller through a circuit, a yarn, we have this user available fast. 31. Getting columns: In this video, we start with implementing our columns. And I think it is a nice task that you try to implement it yourself. So what do we want to implement? A top? We have our board and we're already quoted on our client and we implemented it on the backend and on the client. Now we must implement columns. Why do we need columns? This really places inside of a board where we will store tasks and our users can create columns inside the board, which actually means column must belong to the users. So we must have inside use 3D but also board AT, because our column can't exist without a board and this is y. Here are three level of difficulties for you. First of all, if you want the most difficult level, just pause the video now and implement on the backend festival a model for the column, then at type for the column, and then a get method to get a list of the columns inside our board if you want to try it on the second level. With my guidance, here are some tips as the set inside our services types must create just like we did with board. We must create here column and we need here an interface for the column and also an interface for the column document. So it will be super similar to our board. After this, inside our server, we want to create a new route. And here we will have apt-get API boards, board AT just like here, slash columns. And it will be a GET request to get all the columns of this specific port. And we really need this quantity inside our route. In other case, we don't know for what board we must get our columns. For this we must implement in your controller, which is columns controller, and we must implement inside the method, get columns, just like we have here inside. Get bored. And they did, is that we want to get all our columns by this point AD from the database. So if you want to try it yourself, just pause the video now. And now the easiest variant, Let's implement it together. And we're starting here. First of all, from our types. Here we want to create a new type, which will be column dot interface ab.js. And actually I want to copy paste completely our board because it will be super similar. So here we have our interface and datas column. And what do we need inside our column? First of all, we need some name, which means title is completely valid, will also have here created at and updated at. And we have here UserID because it's the set. We might need information who created this specific column. And after this, we want to have a reference to our board. This is where here we have a board AT. And it is the same schema types object ID, just like we have here on the top for our user. And now here instead of our board document, we want to create our column document and we're extended here document and our column interface that we just created. And now it is time to create our model. So here we have Bohr model, now we need a column model. So here we have a board tears. Now we need to create here column Ts. And actually I will copy paste everything from our board because it is super similar. So what we have here, we're building here a column schema, and here we're using NADH board document, but instead column document that we just created here, board document on the top we can remove. Here, we know that we have our title, we have our use 3D, it is required. And the last one here will be our board ID, which is a type object ID, and it is also required, and it is our model of type column document and the name is column. And here we have our columns schema. So as you can see, it is super similar to our board. And actually lots of models that you will create in your future applications will be really looking like this. So we successfully created our type and our model. Now, we must generate and use out inside our service tiers. And here I want to copy paste this line with a Pi boards board Id. And here we have a get on exactly this route slash columns because as I said, we want to get our columns for this specific point. And here we must use our middleware because this request is only for logged in users. And here we don't need to use our board's controller would want new controller here, columns controller, and here we can name it, for example, get columns, but don't have columns controller tall. So here I want to copy paste board's controller here on the top and just name it two columns controller From slash controllers slash columns. And our last step here will be to create a new controller, which is called columns. And this is controller to manage all our actions for the columns. So here we're creating our columns dot ts. And here I want just to copy paste one method from our boards because it is super similar and it is good boards. So let's jump back inside our columns stairs and paste this method here. First of all, it is not get bored, but get columns. And we need here are expressed request interface because we want to check for current user. And here we need our next function. And also we must input here on response from express. And here as always, we're checking for currentUser. We're throwing for 01 if it is not there. But now here we must use not bored model, but instead column the model. So let's input here on the top column model that we just created from. And here we're writing slash models slash column. And now here we're waiting to make a request for column model find. But instead of finding our columns, and here we will get an array by user ID. We want to find them by our board AD. In this case, we will get unlucky columns for this specific board. And we get this information from request dot, params dot, and here we have board ID. So back here we're getting an array of our columns and we simply want to respond to the client with this array. And actually we are done. Let's check if it's working. I am jumping to the back-end. There are no errors. So now I want to make a get request, and here I have our API, but instead of slash api slash boards, I want to have here slash and then NAD. This is why from our application, I want to copy the d of our board to paste here inside postman. We're making a GET request and let's hit Send. As you can see, where I get an a message where unauthorized, which means first of all, I must login. This is my user, I am login and here I am getting a token. Let's copy paste this stalking and try once again. Here is a GET request for slushy baseless point. Here is AD and they missed here slash columns. This is a get request, and here is our header. This is beer. And then I will put my token I'm hitting now send and we're getting our answer, which is an empty array. And actually it is completely correct because we didn't create any columns inside our database. But to make it safe and clean, Let's create them from the console so we can check if it's really working for disabled jump inside console and try docker exec minus 18 MongoDB, Mongo, just like we did previously for our board. Now here we must use our L Trello database. So useful trailer and now I want to insert a record inside our columns collection. This is why here we can write db dot columns, dot insert, and here inside we want to throw first of all at title, for example, first column. So here we must provide a user ID, and here we must write the date is an object with some string inside that we must take from the request. And last here will be our board AT, and it is also an object ID and inside the string. So bore the D. We already know, we can just take it here from the postman and they will put it here. But our user AT, we can check inside our backend. As you can see here, I still have this console log with our user. And here are the D of my user with which I am locked in. Here inside our user ID, I will paste the hash of my user. Let's hit Enter. And as you can see where getting inserted one. Now we can check if it is correct. So db dot columns, dot find and just round brackets. And as you can see here is our response. So let's check now in Postman, if it is working, I'm hitting here send again, and we're getting inside the array, a single object. Here is our AD Boyd AD user ID and title, which actually means we successfully created our column model and the first request to get all columns for this specific bond. 32. Create column with websockets: In previous video, we successfully created a method to get a list of our columns for the board. In this video, we will focus on the back-end part of creating of our column. And we will do it not in the typical way because we won't use here HTTP. We will create it with socket by do we need to create columns with socket? Because actually this is the case where Woburn to notify all other people who are looking on our current board about creation of the new column. In this case, all users with this single open board will see directly our nucleated part. So how should we do that? And we're starting here inside of a source server. They actually were already know how we're doing things. We have here are your own connection and here are our socket on. Here we must reflect on in your socket. Why is that? Because actually we will trigger, create enough the column on one of the clients, which actually means inside or Angular application. In the next video, we will build a frontend pod with the form to create a column. And then we will emit an event for our socket IO. This is why here we must subscribe to this amid. Our first step will be to create here a new event. And actually here I want to create three events while that, because we have an asynchronous operation, we start creating a column, then we have success and failure. And they said we can't really get errors from the socket IO. This is why it makes a lot of sense to organize all our events as Start success and failure. And in case with board join, we don't need it. We just need a single event because essentially this is not in a synchronous operation with don't have success here, but we have it with create another column. This is way here, Let's name it columns grade. And this is a string, and we can name it columns colon, and then create this. You can see I'm using the same notation like here on the top, we have an entity and it is plural, and then our verb, what we're doing now here we can copy paste this line two times because we must create here, columns creates success and columns create failure. In here on the right we will have columns create success with camelCase and here column create failure. So our events are ready and now we can open bag our server tiers. And here we want to write one more socket on. So here we want to react on now socket events in them don't. And here we have columns grade, and there's a second parameter we're getting some data With don't even care what this data. Now here inside we want to use our columns controlling and we're also the created it, but we didn't have any socket information inside. This is where here we want to create a new method which is called Create column. And we're passing inside exactly the same what we did here inside live board for example, it is a your coma socket common data, in this case, in all places where writing the code and all parameters in the same way. This is why it is easier to understand our application. Now, it's time to create this section inside the controller. This is where let's jump back inside our controllers columns. Here we have get columns. And actually let's write here from scratch our new method. So here we have our constant and it is create column. And this is an asynchronous function and inside where getting exactly all stuff like we got previously. So first of all, it is a yarn and it is serum. Secondly, we have here our socket, the socket, and the last one is data. So the question is, what data we will get to create a column? And we need two things. First of all and name of the column. And secondly, our board ID. This is the information that we already wrote inside our model. This is why here we have body D and it is a string. And secondly, we have here title. It is also a string. And just to remind you at the moment when you are our two input in here, socket, you should know how to input it from types socket interface, not from the socket IO because we must use a user property inside that interface. And now inside we have try-catch, just like always, because we're making here an asynchronous operation and inside cage, what we want to do with don't have access to next, but we can emit hear something you, for example, here I want to write socket Datta meet and we're thrown inside our socket events E and M dot, and here is failure, so columns create failure. And secondly here I want to give a message back. But the main problem is that this sarah is unknown and this is completely normal because we're inside catch, we can't know what the Sarah is. This is why if we need to read a message from the error, we must try something like this. So here we want to read our error message and we can check that our arrow must be an instance of an era. In this case, we can read here error message. And another case we simply want to stringify our error here as the second parameter, we can provide insight our error message, which will be a string. In this case, this is the best possible parent and say TypeScript. You can work with unknown error inside catch. But here is the problem. We will write this single line in every single action when we're getting an error and we want to read a message and we will use it inside every single image inside catch. This is why I want to move this code to help her. And we don't have our helpers yet. This is why insights source. Let's create helpers dot ds and back this method inside. Here I can create a new method which is get error message. And we're getting here our error and it is unknown. So this is exactly what we're getting in catch butt back. We want to get a string. Now, I can copy paste this line fully and paste it here. Don't need here constant a message. We can simply return this single line. It, as you can see, this is how it looks like. We're getting here error unknown, where chicken instance of error and well-written either error message or string era. And now here inside our column stairs, we can import this method. This is why here we can destructure, get error message and it is from our helpers. And now here instead of this line we can write here, get error message and were provided inside our era. And now this helper is super usable fast. Now we need to write our code inside tribe. So first of all, we must check if burlington or not. We're doing it only for TypeScript because they actually were locked in here because of the IOUs and our middleware inside that we build previously. But here we must check if put don't have a socket dot user. And just to remind you of this socket interface must be our interface and not from socket ion. Here inside we can emit exactly the same stuff. So here is socket and meat and were provided inside of a socket. Events ENM columns create failing. In here inside we can just write the string user is not authorized. So what this line is doing, we're emitting a message to our socket, which actually means we have a client and this client sends a message, please create a column. And then either here inside cage, here inside the CIF will emit only to a single client that send us a message, this message back. And this client can listen for this message and do something accordingly. And after we meet, we can simply call here a return with don't want to do anything. But if we have a socket user, then we can create our column. So here let's try that we have a new column and to create it, we must use new column model. Actually column model world with the inverted here on the top. So we can use it here. So to create a column, the model, we must provide insight, first of all, a title and it is data dot title. Secondly, we want to provide here board ID and it is theta dot board AT. This is the whole information from our event. And last but not least is our user ID. It is inflammation from socket dot user dot ID. So here we successfully created a new column number, must save it in the database. This is y here. Let's get back our saved column because we want to get here NAD also. And we're waiting for our new column that were created dot save. We're waiting to save it to the database. And after this, we want to send this information not just to our socket. We want to notify all people, all our clients who are subscribed to our board. Which actually means we're sending this message, not just vector socket, we're sending this message to a lot of people. And we can write this code with socket here like this. So it is not socket dot two and k inside we're providing data dot point AD. And just to remind you here before inside boards where we wrote join code with John Boyd, wrote here, socket join, data, port ID. Here. Now we have a room with a d of our board. And now here we can meet some data to all users who are inside this room with I2. Here is our data board AT dot m meet and were provided inside our socket events ENM, and in this case, it will be success. This is y column creates success. Here we want also to provide the whole information of our saved column. And actually this is the same like using HTTP, but this information will be propagated to all our users simultaneously if they're subscribed to this specific board. Now here without any difficult client logic, I want to test that it is working at all. This is y here, for example, after our i2, I want to write console log saved column so we can check if we're coming here. Now after this, I want to jump inside our clients source, app, board, components, board HTML in here, I just want for testing to create a button was clicked. So we will click on the button, and here we have a test function. Now, when we're clicking on the button, I want to meet this event. This is way here we have our test function and inside I want to write this socket service dot and meat and were provided inside our event. And in our case it is columns create and there's a second parameter we must provide here an object with pour the tea, which will be this board ID. And secondly, title, for example, for this single line, must tell our backend that we want to create this specific column for this part. Now we can jump to the backend and check if it is working. As you can see, we don't have any errors in API. Now let's open a browser and reload the page. And we're here on our single board page. In here there's a button. And actually I forgot to write the text inside the button. So let's write here test so we can at least see a button and then clicking on the button once. Now let's jump inside, beckoned. And actually here we're getting the last message saved column, which actually means our backend got our request. And it is happening in our service tiers with this code where we're subscribed to column grade. And then side where Colin, our columns controller create column and inside this function, first of all, we're checking that we're locked in. After this, we're generating a new column with this data that we got from the event. Then we saved this column and we send the message to all our users which are subscribed to this point. We will test this code deeply in the next video. But as you can see here is my constant locked saved column. And this is exactly what we're seeing here inside console log, which actually means we successfully implemented our working between socket on the client and socket on the backend. And regarding creating of our columns. 33. Getting columns: In previous video, we successfully prepare the noun backend, create an off our column. But before we will implement inline form to create a column on the client, we must at least create our boards page because for now it is completely empty and also render our columns. This is why the first thing that I want to do is create on our client the interface for the cone, because we don't have it yet. This is why we must champion sets, source, app shared types. And here we must create column interface Ts. And let's expert here our new interface, which is a column interface. And the inside, first of all, we're getting NAD, which is a string. Secondly, at title, which is a string. And lastly created it, which is a string. And actually also we're getting here updated head, which is also a string. Our next step is to create a service with the method to get all columns for this specific board. And actually here we don't have such service. We have just Boards service, which is a stateless service just with method like getting boards, get bored, create board and so on. We must do exactly the same. But for columns, this is why here I want to create columns, service dot ts. And as you can see where in AP shared and not in the board. Now here, first of all, biomass trait injectable and second loop one to export our class, which will be our columns service. Now inside we must introduce you to the client because we will make requests to get a list of our columns. This is way here. First of all, we must write a constructor. And here we're get an HTTP, which is an HTTP client. This is enough. Nobu must create get columns method, which will deliver for us in the way of columns from the backend and on the backend we're already created that method. This is where here, first of all, we must get here a board ID. This is a unique identifier to get a list of columns for this specific board. And back we're getting an array of our columns, obviously as an observable, because it's always from HTTP where getting observables, this is where observable of column interface and don't forget it is an array. Now here inside we're doing exactly the same like we did in board. So if you don't want to retype everything, you can simply copy paste, for example, get bored, and you are good to go. The code is super similar. So here first of all, we want to create a URL, and here we want to merge first of all, our environment DOD API URL slash. Here we have our boards slash n. Here we want to inject board ID slash columns. And after this, we just need to make an HTTP GET request. This is why here I want to return this http.get and we must provide that back where getting our column interface array. And here inside we're providing our URL. And with this code we will get our columns for specific board. And now it's time to use the service inside our component. But for this, we must jump inside our app board, board molecule. And the input here inside providers are in your service and it will be our columns service. Now here we can jump inside components, board, board component, and fetch this data here. Now here inside our fetch data, we want to fetch our columns. But for this inside constructor, we must inject this service. And it was columns service, which is columns service that we just created. Now here we can jump inside our fetch data and use here this.com service get columns. This is exactly the method that we just created. And here inside we're providing now at this point, we already have this information. But here we want to do exactly the same, but don't want to save this columns directly here in the component. We're already created our board service for this. Inside, we can save all this information. This is why here we can write, Subscribe and we're getting back our columns. And what we want to do with columns we need here in your method, this board service, DOD, for example, set columns. And inside we will throw our list of columns. And now we just need to implement this method set columns. This is where here Let's open inside Boards Services, our board service. And we're doing exactly the same like we did here. We said board. So here is set columns. We're getting our array of columns, which is a column interface array. Here we're getting big void and we need here a new stream of data. This is where here I can copy, paste our boss stream and name it column stream. In this case, every single place of our application, if we are using this board, can subscribe and get the list of the columns that we have now. And actually this will be a behavior subject of column interface array. And we don't need to provide here now because by default we can simply provide here an empty array. And now inside our set columns method, we can simply call this dot columns dot next. And we're providing insight are columns that prefetched. Now let's jump back to our component and dead this stream. This is why here on the top, we already have this board, dollar, which is a stream. And now we must create columns. Dollar, which is a string for our columns, and it is an observable for column interface array. And now here we can write directly after this point, this dot columns. And here we're using this board service dot. And here we have our columns. We don't need here pipe filter Boolean because this is simply an array. It is either empty or older, the field with our columns, the main idea is that we have no streams and we can use them directly inside the HTML. But here I want to show you even better variant, because actually here we already have two streams later. We will have one more for tasks, which actually means we have three different sources of data and we want to render our page when all the sources of data are fulfilled. This is why we can rewrite this code a little bit differently. We can write here this dot data with taller. And this is a special notation which I am using. This is a super popular variant, how you can manage your data for your component. Typically you have a page with a lot of sources of data and you want to combine them in a single stream. And then you can run the whole page only when you fulfill all the streams. And we will fulfill the stream with the data when we're getting you in your data. This is where I want to write combined latest and were provided inside an array of streams and festival here we can copy this line with boards stream and just paste it here. And after this we're taking this port service columns and we're also paste it here. Obviously we must straight here comma, because these are two different streams. The main idea is that we're combining the streams. And here we want to do this with pipe and map, because actually we are getting this as an array and die want an object here, this is y. Here inside map, we can directly the structure, first of all, a board and here order is important. Secondly, we have here columns. And after this, we want to return the data in another format as an object. And here we're returning first of all aboard and secondly, our columns. So what this thing is doing for us at all. So we are getting here data, which actually means we don't need two streams here. We can now create here and use stream data. And this is the whole data for our component board. Now we're saying here that this is an observable of the object. And first of all, we have here a board, which is a board interface. And secondly, we're getting here our columns, which is a column interface array. And now we can remove board dollar and columns dollar, we don't need them anymore. The main point is that our logic was fetching data and set in this data inside word service is staying there. This is just a combination of two streams to map this data for our component. So now the question is how we will use this data inside our HTML. This is where I want to remove everything and actually also remove here test on the bottom. We don't need it at all. Now I want to write marker for our page. First of all, here we want to render our app top bar. It is already there. After this, let's run the board. So here we will have div class board, and here is a trick we're using here in GE, but we are providing insight data dollar, this is our combined latest sync as data, and this is it. The main idea is that we're not working with streams inside anymore. We're working with data as a local property. And this will create for us a local property just inside this div. Now here, first of all, we want to create our board header container. This is where here div class board header container. And let's close this div. But we will run the late Insight is an inline form for updating our board. This is where here I will simply write inline form bond, so we won't forget about it. After this, we will render our div with the class columns and inside I want to make and G for loop for every single column. This is y here, class column and then G4. And here we can write lead column of data dot columns. As you can see here with don't need any async pipes because we're resolving our data property and we're getting this data inside, and this data will be automatically updated if the stream of columns is also updated. Here, let's close our column and then side we want to render our div class column title. Now inside we will have one more fun. This is where here in line form for updating column. And after this column we will have one more in line form. So here we will have inline form for creating a column. So this is our basic markup. Actually, we didn't render a lot here, but at least we're rendering here at columns, which we're getting from our data. Let's check if it's working. I'm jumping to the console and we're getting an error. Epitope is not available for us, so we must import it inside our board module. So here inside the inputs we can simply add top bar module. As you can see now I don't have any errors, so let's reload the page. Actually it is already there. We can see our nice top bar. Here are some placeholders and actually these are already our columns. And yes, we didn't trend at the title just for testing, we can do it really fast. Let's jump back inside our board, and here will be the title for our column. So instead of inline form for updating column, we can simply render here column dot title. I'm reloading the page in here, we're getting first column and form. This is exactly these two columns that were already created. First of all, inside console of MongoDB. And secondly in the last lecture where we created with the event, our new column. And they highly recommend for you to use combined latest to combine data like this in all your applications. This is extremely efficient and scalable. 34. Create column form: In previous videos, we successful event ID columns for our board and now we can continue with Create form for our column. And just to remind you, on the back-end, we already implemented the whole logic to create a column by using socket a yarn, and now we just need to implement it on the client. And first of all, I want to start with some HTML. And actually here we're already prepared inline form for creating column. This is exactly where we want to use our inland firm and we're already have it. We just need to provide insight correct data. Here let's close our inland form instead of the message. And now what do we need to give here? First of all, we must set a class. And just to remind you, this is a parent class with styles that we're overriding for our inline form for this specific case here, our class will be create column form. After this, we want to set a default text. This is what we will see by default, and it is the text, at least also here, we must render a button to submit this form. This is why here we can write that we want his button property. And it is true after this, we want to provide our button text, and this text will be at least. So here we want to change our default placeholder. This is why here we can write input place holder, and here we can write add column name. And last but not least is of course here handle submit. And this is a callback where we will get a title of our column that we want to create. So here I want to add new method which is called Create column and then site where getting our title through event. And the last thing that we need to do, we need to create this grade column function inside our board. Here we will get a title as a strain from our inland forum. And here is void inside and they want just to console log here, create column and see a title. Let's reload the page and check how it works. And actually here we're getting a message. Inline form is not known element of our module. This is where we must jump back inside our board module. And here inside the inputs, we want to input our inline form module. As you can see in browser now we have a new button. At least we can click on this button. And we see now our input which is styled and our atleast button. And actually if you're wondering from where all the styles are coming, Just as he told you previously, we style all inline form elements with our parent and dynamic case here it was create column form. This is where here you can see the styles create column form and then inline form container editing. So this is why our form is so shareable. And now let's check that we can add a new column. Here I'm typing something, I'm hitting at least. And inside the console we can see our credit column and our title of the column, which actually means now here we can emit an event for our socket, for our back-end, but I really want to do it better. I want to specify our input. This is why here in such shared types, we have board and column, but I want to create an input. What does it mean? Just like we had inside our owls types, we had here login request and registered request, which is essentially a body of our request. Typically we want either to name it request or maybe you want a word input. This is way here in shared types, we can create our column input or you can also name it column request. So here let's say that this is column input interface Ts, and this is the data that we must provide for the back-end in order to send our event. And here we want to specify it inside an interface. So in the whole application will know how we create your column. This is way here, Let's name it Column input interface and the main differences, it is not calmly interface, it is input. This is why it is a body. And here we have our title, which is a string. This is what we must provide for our back-end. And secondly, a board ID, which is also string. And now we can use this input interface inside our board component. So here instead of console log, we can create our column input and we know that the type is here, column input and here now we're must provide all possible values. In our case it is just title. And secondly, board, AD and body. Do we have inside these dot port ID? And as you can see here, we have a correct type, and now we must throw it inside our socket IO. This is way here, this column service dot create column. And actually here we don't have create column method. This is why we must create it. I want to jump inside our shared services columns. And here we have just get column. Here we want to make create cone. But this method won't do anything with this GTP. It will use our socket IO, and this is completely normal, whereas the late, all this methods inside our services and we simply call our services. This is way here, Let's make create column method and we're getting here our column input. This is really nice that were created an interface here. This is where we can reuse it and it will be our column input interface and back we will get void. And just to remind you here with HTTP, always get back an observable. But in socket layer, it won't work like this. With socket, you have a single flow of data. This is where here the only thing that we want to do is trigger our emit. But for this, we must inject here our socket service, and this is our socket service that we created and we can now use it inside this method. So this dot, socket service dot and meet, and we must provide here a name. So let's check first, if we have such name inside our shared types, we have socket events, and here we don't have anything. And actually we can open inside back-end this enum because inside types but also have socket events. And here we have column create, success and failure, and it is exactly the same. This is why I will copy paste it completely. And now we can use it here instead of event name, we can write here socket events ENM don't end here. We want to trigger column grade and then save it as a parameter. We want to give our column input. It gives us one more benefit to write our code with socket inside the service. We isolate this code inside of a service. This is why our component doesn't know that we're using here socket layer for example, we simply call here column service dot grade column, and we're given inside our column input. Let's check if it's working here, we can try to create a new column. I'm hitting Add. And now inside our beckoned, we can see saved column. And after reload the page, you can see here are created cone, which essentially means it is working, but we don't update our page on the fly. And obviously we want to update this page, first of all to our current user, secondly to all other users also. But for this, we must improve our socket service. Why is that? Because actually what we need to do inside fronted, we must subscribe in a comfortable way to our success. And just to remind you, inside our backend here inside controller columns, we have a meet and actually these are your two amid will emit this message to all users who are subscribed to this specific room. This is why what we need to do. We want to subscribe to this specific event, which will be success of creating column, but we want to do it inefficient way. And then said socket layer, it is not efficient. We want to do it in Angular way. This is why we must open inside shared our service, socket service. And here I want to create after meet one more method and it is called Listen here. First of all, I want to write t inside. And if you don't know how to use generics, The main idea here is that we can provide whatever datatype for bond inside listen, and it will be what we will get back from the socket IO. So here we're providing t and here event name will be string. And back I want to get observable of t. And this is essentially the idea. This method will give us back an observable. It is not comfortable to work with Socket Layer inside angular. This is why we want to convert it to observable here. First of all, good one to check if we have socket IO or not. This is why I can copy this if condition here, because if we don't have socket and you are connected, then we should not do anything. After this. I want to return new observable. And here inside we must provide a function. And here we have just a single argument which is a subscriber. And now inside we can dry it. Socket on. This is just a plain code of socket ion. Here we have our event name, which means we are subscribing on the client to this event name that we passed as a parameter. Here is our second parameter here we're getting some data and what we want to do, we want to emit our subscriber dot next with the data. So what this code is doing at all? First of all, here we must try this and this, you can see we're getting an error. Object is possibly undefined it. And actually this is a TypeScript problem because here he can't understand that this code with Eve covers undefined it. What we can do instead, we can write here con socket equals the socket. And after this we're covering this socket here. And then instead of this circuit where using just socket and in this case when not get it in TypeScript theorem. So what is the idea of this function? We will use it like this. So here is listen. Then we're providing some datatype, for example, a string. And after this here withdraw and event, for example, column create or column creates success. In our case, this single line, it will give us back an observable. This is why after this we can write, for example, subscribe and here, and we will get here our data. You will see how we will use this function in a second. The main idea is that this function will create fast and observable. We will subscribe with Socket Layer to this specific event name. And when this event will be triggered, we will simply update our observable. This is really comfortable angular way to do things with Socket Layer. Now let's try to use this function. I want to jump back and say that our board component, and here we have our initialized listeners. And here is a really nice place to listen to the events. This is why here I want to write this dot socket service dot lesson. And here we must provide the type because it is mandatory. And here we won't provide that. We're getting back our column interface. This is what we are getting after creating of the column. And here is our event name and we want to subscribe here to Socrative ends in a dot column creates success because we're waiting for the success. And here, after this we can write, just subscribe and we're getting inside here a column. And here we can just console log this column. So once again, what this line is doing, it creates for us a new observable and we can simply use it as an observable. Most importantly, inside where right and socket on. So we're waiting for our emit. Let's check now if it's working here, I want to create a new column and I'm hitting at least. And Viola, as you can see inside the console, we're getting our column. And actually this is this code with the success event. And here we're getting exactly our column which has saved to database because as you can see here is an 80 of our saved column. And now we can do something on the client to update the loop is outpatient a lot our board, but it is not tall as you can see here. I opened the same tab for the same user. But the difference is that socket here is different because every single time when we're opening a new tab, but establishing a new connection with another socket ion. This is why when here we will try to add a list. And I'm just hitting here, at least we are getting here this column console log. But actually here we also get this column console log because these are two separate tabs, are two separate users, which actually means if two different clients will be connected and open this board, they will receive simultaneously our event regarding creation of new column. And this is essentially the core functionality that we want to achieve inside socket ion. Now we must somehow change a list of our columns. And actually this is way here. I want to write this dot boards service and be careful here, not poor, it's not our stateless service with functions, but our board service for the client. In here we must create a new method which is called Add Column. And we can simply throw inside our column, which essentially means our component doesn't know anything about business logic, how to work with columns on our board service knows it. This is why here we must jump inside our board service and we can create here a new function which is called ABC column. And here we're getting on your column of type, column interface and back we're getting void because we don't care about return. We simply need to update our stream. And just to remind you here on the top we have a stream of our columns. And now here we need to update this somehow. This is why what we can write here we want, first of all, to update our columns. This is y. Let's create here property updated columns. Here we need first of all, to spread what we have now. And this is this column stream. And here we have a function getValue, and it will just read the value from our stream that we currently have. And at the end we must write on your column. So this will be our new updated columns array. As you can see, the type is correct. This is array of column and interface, and now we can just update it with these columns next. And here we're throwing in site updated columns. So we simply create in your array and we'll write it inside our stream. Let's check if it's working. I'm reloading the page. Here at the end, we have at least button and actually it looks kind of broken because it is zoomed out. Now here let's create a new column. I'm hitting edit list. And as you can see directly here, we see our new column, which actually means this code updates our stream and then our component is subscribed to the stream here on the top with this combined latest, these columns is being updated. And then we'll resend this component automatically. Once again, how this all working? First of all, we are getting here our inland firm. And this inland firm produces for us just the title. After this, we'll create this object with title and Boyd AD and throw it inside our column service. Here is our credit column. Here we're meeting our event and we're throwing inside our data after this back-end receives this event creates for us the column and the means to all users in this room, in this board, the message that we successfully created our column. And after this, every single client is subscribed with this code just from the beginning to this column. Great success. And when it happens, we're getting here, our credit column, and we're colon here, but service to add a column. And this essentially will update a stream with the columns. And our component will be rear-ended on all our clients. 35. Creating a basic task: In previous video, we successfully finished with creating our columns. In this video, we're starting to work on tasks. And actually we must implement the back-end part of creating the tasks and getting a list of tasks for our board. And actually think that it is a nice possibility for you to try and implement it yourself. Because actually you already did small fissures inside this project. And now you are ready to do something bigger. And actually getting a list of tasks and creating a task is really similar to our columns, which means you can use the whole logic from there. So what do you need to do if you want to implement it yourself? First of all, here we're talking about beckoned. So we must create a new interface for our task, then the model controller method to get this tasks for the boys and method insert control it to create a task. The question is on, what fields do we need inside our task? And actually here, I just want to write what fields we need. First of all, it is a title of our task description which is not mandatory. It can be empty, then use 3D so we know who created this task column ID. So we know in which column of our board we must trend this task and the additional aboard AT. In this case, it will be easier for us to get all our tasks by specific board ID. The back-end, you need an interface and model, then register in your API to get this tasks inside the board. And the method to get this list of tasks by fallen board. Also, you must create a new create method also inside our controller. And it will be a method with socket yacht because we want to notify all of our users who are subscribed to this specific board regarding this new task. And if you want to proceed by yourself, you can just pause the video now and try it. But if you just want to follow along, Let's do it together. And there's all this said. It will be super similar to our columns. This is why I will copy paste a lot. First of all, here, I want to jump inside our server source types. And here we'll have our column interface test. And actually we can copy paste it fully and just create our Task interface Ts. Here inside the muscular it exactly fields like the plan. First of all, we have our title created at updated it. We have always, here is our user ID and board AT this is totally fine. But also we need here to create a column lady. In this case when no, wherever mastering that the specific task. And also we need here a description, but it is not mandatory. This is why I put here a question mark. So our interface is looking fine. Now let's change the document we need to create here task document, which is extending document and our task that we created. And as you can see here, I forgot to rename our column to the task. Now let's jump and create our model. Here inside models were already have column. I will also copy, paste everything and just put it in our new file, which is task dot ds. Here we must change everything. Festival Here we have another column schema, but task schema. And here not column document, but our task document that we just created here on the top, I can safely remove column document. Here we have our title. It is required. This is totally fine. After this, I will paste title again and rename it to description, but it is optional. This is where required through is not needed here. We also have here our user ID, board Id, and here I want to put new column ID. And it is also required for sure. And type is the object ID. It is looking totally fine. Now on the bottom, we must provide here our task document. And here it is a task, which is a task schema. Our model is completely ready. Now we must create a new API inside our server. This is y. Let's jump back inside Service source server tiers. Here we have our API calls. And actually our new API call will be super similar to this code. Here we're getting columns by specific board Id. Actually we want to get all our tasks for specific port. This is why I will copy, paste this line, paste it here, and just rename. It will be slushy pie slash boards. Board is dynamic parameter, and here we have our tasks and here we'll also need our middleware. And here we need a new controller, which will be tasks controller, because inside we want to manage our tasks. And here the method will get tasks, and this method must return all tasks for this specific board. Now it is time to create a controller. This is why I will jump and said controllers. And I want to copy paste the whole file columns just because it is easier to change and it will be super similar. So I'm pasting it here and renaming two tasks, dot ds. Here inside we have two methods, create column and get column. And actually here we can simply rename get columns to get tasks. And here we're leaving everything as it is, request response. Next, this is totally fine. Chicken for the user is fine here. Reschedule, everything is awesome. Now here we don't need to use column model, but instead we need to use here task model. This is where here on the top I will input task model. From models task. Now here we can change our column model to task model. Here we're doing find by border different request parameters, board Id, and this is exactly what we need and this is why we have body inside our schema. In this case, with just a single line of work finding all of our tasks for this specific board. So here back we're getting our list of tasks, and here we can simply send them back to our API. And with that, our action to get the list of tasks is fully ready. Now let's change the directly this create column. And as you can see here, we're talking about socket IO, and it will be also super similar. First of all, we have here a method create task here where getting your socket and data. So what do we need to get inside data? First of all, we are getting bored or ED, because we must notify all users inside this specific board. This is totally fine. Now we have here title string, and the last one here is column id. And column id is also string and duties mandatory. And you can say here that we don't provide a description inside. Your total is right in create, recount, change description, description we can provide only inside Update. This is why this is totally fine. So what we're doing inside here, we first of all want to have a failure for our tasks create. But for this, we must first update our socket events. This is why I will jump in such source types. And here we have our socket events, and here we already have columns grade and they want to copy paste all three actions. Here we can rename it from columns to tasks create, and here it is tasks create, then Tasks, great success and tasks create, failing our socket events is ready. We can jump back inside our tasks and change here socket events in them to dot tasks create paler and they won't directly to change here our catch, and here we can just provide dot tasks create failure. Now let's update an inner part here we have not column model, but task model, we're already inputted. Here, we're getting titled from the data. This is fine. Board Id. And here user from socket is ready. This is all totally fine, but we must also provide here alkalinity from data dot column may be. And after this here we're saving not new column, but new task. Here. Let's rename it to new task. And here we can simply call new task dot save and we're getting back saved task. Now with this line, we want to notify all our users that we created a new task. This is way here we're emitting this event and do these tasks creates success. And here we want to provide back the save task. And here we can remove this console log. We don't need it anymore and we're fully created our Create Task method. And the last thing that we must do, we must subscribe to start of creating the task from the client. This is why we must jump back inside our sorority S. And here on the bottom we have the socket on. Actually we can copy paste columns Create and just change it to our socket, even CNN dot tasks create. And here we're getting our data and we simply need to call our tasks controller create column. And here you will not be created column, but create task. And as you can see here with didn't import our tasks controlling. This is why on the top, I want to copy paste columns controller and rename it to our new file, which is tasks controller. From controllers tasks, it looks like we implemented everything. Now let's jump inside console. As you can see, we don't have any errors were getting connected to MongoDB. Api is listening. This is why actually I just want to copy paste the board Id open Postman here and try to get our list of tasks. So it is slash sports than a paste this ID slash tasks and them hidden here send. And as you can see back, I am getting an empty array, which is totally fine because we didn't create any tasks yet, which actually means our backend is fully prepared. And now we can start with implementing client side. 36. Getting tasks: In previous video, we successfully finished preparing our tasks models and getting tasks on the backend. In this video, we must do exactly the same on the client. And I highly recommend you to also do it by yourself because you already have so much knowledge. What do you need to do if you want to do it by yourself? First of all, you need to jump and said clients source, app shared. And here we have our types, we have here Boyd and column, and now we must create a new interface for our task. After this, we must create a new service to work with tasks, whether they have boards, columns. Now, we need a new server which is called task service. Here boop will get tasks in exactly the same way, like we're getting here columns for our board, but it is not all. You also must update insider board molecule in such services, board service tests. Because here we're talking about stream for board and stream for columns. And we must additionally create here stream for our tasks and additionally function which will update the stream. And after this, you must simply fetch data here inside this combined latest. And this is it. If you will implement this spot on your own, you are awesome. But if you want to implement it together, Let's do this now. So first of all, I will jump in such clients source, app, shared types. And here I want to create a new type for our Task interface Ts. And we must have exactly the same properties like we had on our back-end. This is why here we can export our new interface and it is Task interface, the inside. First of all, we have our ID, which is a string. After this we have our title, which is a string. We'll also have here description, but it is not mandatory. This is why Here is question mark. It is also a string. We also need here our column they D, which is the reference for the specific column, our parent. And we need here our board ID, and it is also a string. And actually we're getting here usury t, which is also a string. So our task interface is completely ready. Now we can jump back inside shared services and create here in your service. And actually what I want to do, I want to copy paste columns service just because it will be super similar. Let's rename columns service to Tasks, service Ts, and As you can see here is MenuService task service. What we want to do here, we want to change the name. So here we have tasks, service where living constructor as it is, we must use here http and latest. So good service. And here is a method not get columns, but get tasks. And here we want to get our tasks by board AT, because we're fetching just single time all our tasks for specific board. And here we're getting Becker observable of Task interface array. And here is our URL. It is slash slash board ID slash tasks. Here is the HTTP GET not column interface surgery but Task interface array. For now I want to remove credit column completely because we won't implement create task in this video. This is why I can remove these three inputs on the top. We don't need them for now. Now it is time to update our board service. This is why I'm going to add Board Services, Board service. And here we must create a new string. I will copy paste here column stream, and change it to Task Stream. And this is a behavior a subject of Task interface array. And by default here we have an empty array, which is totally fine fast. Now here we have a method, send boards at columns. We must create a new method which is called set tasks. And here's an argument. We're getting our tasks and it is an array, so it is Task interface array. And now here inside our stream, tasks with dollar, we want to set our new tasks so we're almost finished. Now biomass jump inside of our component, board, board component. And here is our combined latest. And just to remind you, here in say data, we're combining all our streams to fetch data for the board. This is what we must do here. Now, we must add here this board service, and here is in use stream tasks. And now inside map as the third argument, we must try to tasks and we want to return them here. In this case here inside our data dollar, we will have not only board and columns, but also tasks. And if you did everything here by yourself, you are really awesome and you're making good progress. And now the only thing that we must do here, we must render them inside the HTML. So let's open our board components HTML. And what we have here is our column for loop. And inside we have a title and we don't have anything else. And after this title, we want to render one more deep. And here we need. And, and G for loop for our tasks inside column. And actually we can't do it because we have just this stream for our tasks inside data, but we don't have tasks for this specific column and we must somehow filter this data. This is why here I want to write in G4 and it will be led task of, and here I want to create a new function. For example, get tasks by column. And then side we must provide first of all column id and secondly, all our tasks, it is data dot tasks. And just to remind you here inside data stream, where we get in our board columns and tasks. This is way here inside this function as an argument, we can simply throw data dot tasks, often G4, we must also right here a class, it will be task. And here inside we want to render task dot title. And now we just need to create this kid tasks by column function. This is y here inside OTS file. I will create this function in here. We, first of all, I get in column id, which is our string. And secondly, tasks, and it is a Task interface array. And here back we're getting our Task interface array. Why is that? Because essentially we simply want to get our array with all tasks and filter by this specific columnated. This is way here, Task interface array is totally fine. And what we want to do inside, we want to filter our tasks that were God, this is why tasks filter will get an access to every single task. And here we can check task dot colon equals our column name that we provided as an argument, which actually means we're colin for every single column that we're rendering, this function gets tasks by column and we will render here in energy for loop our tasks. Let's check the sound. Do we have any errors? Yes, we have property tasks does not exist on type board columns, which essentially means we didn't update our data property. And as you can see here on the top, we're defining that inside our observable, we have just bought and columns. But here we also have our tasks, which is a Task interface array. Now here we don't have any errors inside our web server and we can jump to page and we see all our columns, but we don't see any tasks inside why it is happening, because actually we didn't call our fetch. And actually here inside our constructor, we must inject our task service that we just created. And it is our tasks service which is shared. And now we must jump inside our fetch data, just like we did here. We can copy, paste our columns service and rename it to our tasks service. And here won't be get columns, but get tasks and the inside worth throwing our board ID, which is this part AD and back, we're getting not columns, but tasks. And here we want to call this board service not set columns, but set tasks. And inside we're throwing at tasks that we fetched. This is why with this code, we updated our stream and the stream will get new data inside our HTML. Let's check this out. I will reload the page and we're getting an error. As you can see now we're on slash boards. And when I'm jumping to first part, we're getting an error that we don't have provided for tasks service because actually yes, we must inject it inside our board module. This is where here inside providers, we must add additionally our tasks service. Let's reload the page and as you can see now, we don't have any error. And here inside network, we must have a request for our tasks. And here is a request slushy pie slash boards slash ID slash tasks. And here is preview with don't have any tasks, which is totally fine. We didn't create them yet, but obviously we want to check that our code is working. This is why what I want to do inside console. I want to open our Mongo, just like we did previously. Now, I need to select our database so we use L trailer. And here we can check what we have. For example here now we can write db dot boards, dot find. And with this we will see all boards that we have. We just have a single board. And in the same way we can write db dot, columns, dot find, and where I get in our columns. And what we want to do now, we want to insert in your task inside one of these columns. This is why here we can write db dot and we have tasks dot, insert, and inside we're throwing an object. So the first question, what do we need to provide insight? And for this, we can check our Task interface. So first of all, id will be outer generated, we must provide a title. So here is title. For example, my first task after this promise provide a description. So let's say description is my description. And after this, we must provide the column needy. And actually here on the top, I already see columns. This is where I can just take an AD or FirstColumn and they will throw it here. So it will be column id. And here is this AD. And after this, I also must provide a board AD Here. We'll also have a board AD here on the top and we can take it. And last but not least is though a user AT and actually uses 3D. I don't see here on the top, but I can take it from the back-end. And as you can see here inside our backend, we still have a console log with email of our user and object ID. This is why I will just copy paste the idea of how a user and write it here. So use re d equals this object ID. I'm hitting Enter, and here is our first record. Let's create one more, for example, my second task, and here is my description. I'm hitting Enter and we're getting one more task. Let's now reload the page and browser. As you can see here, voila, we have our two tasks. So how it is working here is our network and we have a request with PS tasks to our backend. And here we're getting all tasks filtered by this specific board Id. And then inside our code, inside our board, we have this code that we wrote to filter our data. So here we have a function get tasks by column where inside where filtering all our tasks by this specific column AD. This is where here we're rendering only tasks which are related to this column, which actually means we successfully implemented on the front-end, getting our tasks and rendering them inside our component. 37. Create task form: In this video, we can at last implementer or inland form to create a new task. And actually we're already prepared everything that we need on the backend. We just need to implement it on the client. So let's start with our forum. This is by what they want to do. I want to jump in, set our board component HTML. Here, is there a diff to render at task? And after this, at the end, we want to render our inline form. Let's trend here inline form component. And let's close it here. And now inside when must provide some values. First of all is class. This is our pattern class that overrides the whole styles and it is Create Task Form. After this, we're also must provide default text. It will be add a card, but also have a button here. So here's button must be true and we must provide a text. This is where here will be button text and it is at current. Also we want to provide here our input place holder and it is enter a title for this current and last but not least is our handle submit method that we must create. Let's name it, create task, just like we did with our column and the insight we want to first of all give any event. This will be the title of creative task, but we'll also need here our columnated, because our backend must know in what column we're creating this task. And if you want to ask why we're given here just columnated and not Boyd AD. We have a board 3D inside this inside component. This is why we don't need to do that. Now, let's create this method. I will jump to our board and actually we must do exactly the same. What we did was create column. But here is a question. We have here column input interface. This is how it looks like and we must now create our task input interface. So all our stuff is written in the same way and this is avoided that we must send in order to create a task. This is where here we can name it also task input interface Ts and what do we want to write inside? This is our interface, which is a task input interface. And the inside, first of all, boom must provide a title. It is mandatory and it is a string. Second loop we're providing here our column ID, which is also a string. And last but not least is our boiled AD, and it is also a string. And now we have a nice input and we can jump back in our board. And now I want to copy paste this create column because it will be exactly the same but for task. So here we need to rename it to create task. Here we're getting not just title, but also our column ID because we provided it from our HTML. And now here we can change the name from Column input to task input. And our interface here will be Task input interface that we just created. And as you can see where I'm missing here, our column ID. This is where here we must add it from the argument. And here we don't need to call a cone service. We must cohere our tasks service. And just to remind you that this is our stateless service where we're writing our HTTP request and our socket IO. And this method must be named create task, and we're throwing inside our task input. But this method does not exist yet. We must create it. This is why let's jump back and say it's source app shared services, and here is our task service. But what they want to do, I want to copy paste the method create column, because actually this will be exactly the same. I copy pasted create column and they want to paste it here inside task service. But this method will be called create task. And we're getting as an argument our task input and well-written know that type it will be Task input interface. Here we also want to call a socket IO because it is working in the same way. We have an asynchronous operation and we have started success and failure. So we start to create a task, will notify with the meet our back-end. Then Bacon creates facet task, and then backend notifies all people who are subscribed to our board regarding new task. This is where actually we must update our socket events in them. I want to open it here on the right, and additionally, open the enum inside of a server because we're already wrote inside our events. These three new events, tasks create success and failure. And now we can paste them here to use on the client. After this, we can jump back inside our task service and change the name here. And it will be DOD tasks create. And there's a parameter here. We're given a task input, which actually means after filling our inland form here we will send our socket, your image to our backend and our bacon is already prepared to create our task and the meat success back to all our users. Let's check this out. Is it really like so we can jump in our server source controllers, and here is our tasks controller. And as you can see, we have here create task method, and here we're creating a new task and then notifying with this line all our clients, which actually means we just must subscribe to these changes inside our client. This is where here I am jumping back inside our board component ts. And just to remind you, here we have our initialize listeners and here we have a listener for our column creates success. Now, we do exactly the same for our task, great success. So here we will have our Task interface, and here the type will be DOD. Tasks creates success. And what this task interface is doing in this way here we're getting back Task interface because it is generic. And now we specified or k, This lesson is given us back our Task interface. This is where here we must create a new method at task inside the word service. And we're providing here our task that we got from the backend. And the last thing that we want to do is add this method inside our service. Let's open our board service. And here we have at column. And as you all have done the stent, I want to copy paste it and just do exactly the same. Here we have a task method and we're getting here when you create a task, and it is a Task interface. Here we need to make an array of updated tasks. So here we are getting this than not stream of columns, but stream of tasks, then get value. And here at the end, we want to write our new task. And after this, we must update our strain again. Here is tasks stream and here is updated tasks. And with this code, we will successfully update our stream and all our components who are subscribed to this stream will be automatic letter ended. Let's check if it's working. We don't have any errors here. And now I want to open two tabs here. And they want with both clients to jump inside the same board. And as you can see here is our console log. And they want to try the cut here. So here is our inline form and let's name it, created a task feature. Now I'm hitting Enter, and as you can see directly here in this tab, this element appears. So how it is working, actually we filled our inland firm. We send it our image to the back-end. Back-end, got it, created a new task and notified all people, all our clients who are subscribed to this board regarding this change. And with this listen, we updated on declined our array of tasks and this component was rear-ended. The most interesting part is here is another tab and another user, this is another client with another socket AD. And as you can see here, we've also got our Create Task feature because now all our clients are in sync. And you might say, okay, but your destination, you need just single browser. It doesn't really matter. It is just different socket connection to your server. If you have just two computers and your project is deployed to the production, it will work in exactly the same way. For example, here I can just create a new task. For example, foo, I am hitting here at card and then getting exactly the same information without Pedro lot in another tab, which actually means our feature was creating tasks is completely finished. 38. Update board name: In this video, we will implement one more missing feature and it is an update form of our board name. And as you can see here, we have a placeholder inline form board, and here we must use our inland form. And actually this is our first video where together we will implement the whole feature backend and client in just a single video. And actually the whole logic will be exactly the same like we already did previously, because we built a nice architecture and now we can create easily new features. So what this feature is about, we will have here and then mine firm and we're getting from it a title. Most importantly, first of all, we must throw our title of the board in sign this form on our success of update, but don't want to use the GTP here. Whoop, want to use Socket IO by that, because all our clients must be notified if the ER, in this point, we changed the board name. This is where socket or your meat as always. And then on our backend, we must catch this event and update our name. And actually we can create a method to update the whole board, but we will update for now on layer title. So let's try to do this now. For this, I want to jump inside our code and start. First of all was our server. And for this boom mass register and use socket event here inside our Socrative and xenon. And we already have here boards, leaf and ports chain and actually put want exactly the same like we did with columns. And here we have columns create for example, and they want to copy paste all three of them. Because actually here for example, after boards live, we want to write boards and here will be update. This is where here we can directly change it to board update boards updates success and boards update failure. And now here on the right, we must do exactly the same. Here will be boards and update. After this board's update success and boards update failure. So our socket event is successfully created and now we must register it inside our socket IO. This is by let's jump back inside or a service, yes. And here on the bottom we have our socket on. Here we must register and use socket ton. For this, we can simply copy paste for example, task create and write here, not does create, but react on dot boards update that we just created. So we're waiting for the event boards update from our client. And here we don't want to use tasks controller, but board's controller here not create task, but update board. And actually inside we're passing or your socket data, just like we did previously. Now, let's create this update board method for these payments jump inside our controllers boards. And here we already have this method create board, but this is not what we want because this method is with a shoe TP. This is why actually we want something like live board for example. This is why I will copy paste this method because all options will be similar and we can name this method update board. And we know that here we're getting our IR socket and then our data. And the question is, what data do we need to update a board for sure we must know at title of the board that we wanted to provide. And secondly, the idea of the board that we want to update. This is where our body is totally fine. And actually here I don't want to write a title, I want to write fields. And here we will pass title string. Why do we have such notation? In this case here, we can easily add new field that we want to update inside our board. For example, if later we will have a description, we can just throw it here, but for now we have just a title. Now here we can remove this console log, we don't need it and also socket leaf. So the question is what we will write here at all? First of all, we must write here try-catch just because we can get an error. This is way here, Let's create, try and catch. And here we're getting inside, catch an error. And if we have an error, we just want to write socket and meat. And here is our socket events in a dot. And we're already created our boards update failure. And what we want to provide insight is our get error message. And just to remind you, this is our helper which will transform an arrow. This is my inside. We can simply provide our unknown error. Now let's create our trie. So Festival here we want to check if a valid user, this is y. Let's check if we don't have a socket dot user, then move on to emit exactly the same error. So here let's try socket, the socket events, ENM boards update failure. And here instead of get error message, we can simply write user is not authorized. Also, we should not forget here to write a return. In this case, we will just stop doing anything. Because after this, if we want to write our logic, this is updating of the board. And actually it is extremely easy, but we must make this method as synchronous because we want to use this in Kuwait inside. Now here inside what I want to do, I want to get back our updated board. And to update a board, we must use here a weight and we have here accessed or work model. And we can use find by ID and update. And actually this is an amazing method from Mongoose. In this case here we're just providing NAT and in our case it is data dot board Id. And here is our update. And actually update is exactly what we want to update inside our entity. This is where here we can just try the board dot fields and this is an object. And the last one is options. In here, I want to provide an option you through. This option is really important because in this case, we will get back our updated board. Also, as you can see here, I made a mistake. It is not a board dot fields, it is data dot fields. Now we don't have any errors and we can respond with this port. And for this we can simply use socket and meet. Here is our socket even seen them. And we have here success. So boards update success. We want to provide as the second parameter are updated board. In this case, all our clients will be notified about this event after this coupon to notify all our clients which are subscribed to this board about our change. This is where here we can write ir dot t2, and here we want to notify all clients inside our room. This is where here we will have data, dot board Id dot, and meet just like we wrote previously. And here inside we can use our socket events in m dot. And here we have a board update success. And there's a second parameter we want to write here, updated port. In this case, Oliver users will be notified TO board was updated and they will know what fields they need to change. Our back-end part is completely ready. Now we must implement a client part. This is where let's jump back inside our client source app. And here I want to go first of all inside Shared Services, Board service. Why is that? Because actually here we're throwing our events for the back-end. And actually before we wrote here just as GTP cat and the choosy proposed. But in our case now, we must emit a socket event. This is why what we want to create here is the method update board. We want to provide here. First of all, our board AD, this is a string and secondly, fields that we want to update. As you can see, we have parameters exactly like on the backend. Here fields is titled, which is a string, and back with don't need to get anything because we simply use here socket IO, but to use it here, but must injected inside constructor. This is y here we're getting our socket service, which is our socket service. Now inside our update board, we can use this dot socket service, dot and meat. And here we must provide our socket event. But here's the problem. We didn't register it yet inside our client. Here, we don't have such strings. This is where here on the bottom, I want to open our server socket events in them. And here I want to copy paste this pores, update success and failure. And now we just want to paste them here inside our client. So now we haven't said our client the strings and we can emit them. This is why here we can simply write socket events in m dot and here we have a board update. This is the start of our update in protest. And does the second parameter here move on to provide our board ID comma, our fields. So we have exactly the same data lake we prepared on our backend. And now from any part of our application, we can use this shared board service. Use this update board method to send out a meet. Now it is time to add our form, which we didn't create yet. This is why let's jump back inside our app. Board components, board, board components HTML. And as you can see here on the top inside board header container, we have this placeholder inline form board. And exactly here, we want to write an inline form to update our board title. This is way here, Let's write our inline dash form we want to use, and let's close it here. Now, first of all, inside womb must provide the class to get correct styling. And in this case here, it will be added board forum. After this, we'll also want to provide our default text. And here we will have our data dot board, dot title. Why is that? Because actually, just to remind you here on the top, we have our data, has a local property data, and inside we have all our columns, all our tasks, and a board. This is why here we have a direct access to data board title and we want to render it as a default text. After this, we'll also want to provide a title, and this is the value for our firm. Here we also will write data board title and last but not least, is handled submit. This is our event and we want to create a new method, for example, update board name and inside dollar event is a string to update a board. Now let's create this method. I will jump in RTS file and somewhere on the bottom we can add update board name. And we know that here we're getting our board name, which is a string. And back we want to get a void because here we want simply to use our service. And actually here we already have access to our thes dot boards service. And this is important, not bored but boards dot. And here we have our update board here inside. First of all, we must provide our board Id, and this is this dot board AT. And secondly, our fields. In our case here we have just a title, which is our board name that we got from our inland form. So we successfully created a single flow. So we created our inland from here were updated our board name, and were emitted an event for our back-end. Let's check if this part is working. I don't have any errors on the client or on the backend. And now let's open a browser. As you can see here we have now first part and I can hit here to open a form. And here we see our first board. They can write something here and hit enter. And as you can see, it was not updated because we didn't react on our changes from the backend. And actually, as you can see here inside beckoned, we don't have any errors and probably our title was already updated, but we didn't notify our client. And actually we can easily check it. We can just reload the page. And as you can see now we're getting our updated title, which actually means the whole logic is already working and our backend successful updated our board. But the main problem is we didn't notify all our clients about change. Actually, yes, we did it on the back-end, but we didn't create a subscription for this event on the client. This is y. Let's do it now. So first of all, we must jump back inside our board component. And just to remind you here on the top, we have subscriptions for different events. This is why here I want to copy paste one subscription and change it. So here we have our this socket service and we're listening for the event of updating our board, which actually means back we're getting a new board. This is where here we have a board interface and here we have socket event C num dot. And here we're listening for the success. Here we have Boards, updates, success. And inside our Subscribe Now we're getting our updated board. So what do we want to do with it? Actually would just want to call a method inside of our boards service and it will update our stream of data. This is why here we can use board service, dot update board and worth row. And inside our updated board, super successful is subscribed for our event. And we just need to create this update board function inside our board service. So let's jump inside our board service. And here on the bottom, we can create it. So here is update point, and we know that we're getting here updated board, which is actually a full board interface. And here we will get wide because we simply want to update our stream. But here we have a problem. By default, our board is now, this is way here. Typescript will scream that we can't work with. Now, this is where here I want to check if we have now inside board or not. So here I want to get a board, and this is, are these boards stream toward get value. And after this, I want to check if it is now. So if we don't have our board, then I want to throw an error. So here throw new error because actually we can't update the board if we don't have a board. Here, let's say board is not initialized after this if we can work with part and actually we just want to update our stream. So this board with dollar dot next, and here I want to merge the whole board that we have with the title because I want just update at title. So title is our updated board dot title. And you might say, okay, we could just take the whole object. Yes, we're good, but I want to stay on the safe side and just implement a feature that we need to solve. This code should successful update the stream and our component, as it is subscribed to the stream, will be notified and rear-ended. Let's check if it's working. We don't have any errors here. Let's reload the page and here we have first board. Let's just change your title and hit Enter. And as you can see here is directly my changes. Now let's duplicate this tab and try again. So here on the second tab, I will just try to tune and hit Enter. And as you can see here on the first tab, it was also updated, which actually means we successfully implemented a feature of updating a board title from start to the end. 39. Delete board: In this video, we will implement deleting of the point. And actually this feature will be super similar to our previous feature with the update enough our board, this is y. Let's implement it really fast as always. Put one to start with our server. This is y. Let's jump inside server source. And here we're interested in our socket events. And actually exactly like this update, we need three new events for deletion. This is y here, let's create three new events. It is port delete boards to its success and failure. And let's change on the right, our string two boards delete. Then boards delete success and boards delete failure. Now let's subscribe to our event for this bonus jump inside our server. And here we can copy, paste our board success and change it to our boards. Delete. Here we want to use a new method, not update board but delete port. Now let's jump to our controller and create this method inside our board's controller. And actually for this, I want to fully copy paste our update board method because of a deletion will be super similar. So first of all, let's change the name. It is delete board and it is an asynchronous method. Now, inside of our data, the only thing that we need isn't a d of our board. This is where I bought the D is enough here, but don't need to provide anything else because we simply delete our board by d. And for back-end, it is enough information. Now here inside we have try-catch as always, and we're checking for our socket user. But here, in case of an error, we want to throw another error and it will be boards delete failure. Here. Let's also change our cage. It will also be DOD boards delete failure. And now we need to change our logic whispered model, because here we did an update. Now we have Azure move and actually we don't want to get anything back, but we simply want to remove this bond by d. And for this, we can use different methods. For example, we can use find one and delete. This is totally fine. This is exactly like we did inside update. But actually you can also use directly without sugar, delete one. And this is method just for you to know inside delete one, we must provide an object with fields by which we want to find the sensitive. And actually here we can just provide underscore id equals and d Now in case it is data dot board AD, and actually doesn't matter if you are using delete one or find by the end delete, it is working exactly the same. So this line successfully removes for us our board. And after this, we want to emit our success of removing. This is where here to all our users inside this port, we want to emit boards, delete success. And actually here we don't need to provide an ID of our board because all these users are inside this specific board and they know what board was removed and they must be redirected to the homepage because they can't stay on the board that one of the clients removed. So our server logic is completely ready. Now let's return to our client and the exactly like previously. First of all, we want to start with shared and with our socket events. And I will copy paste from our socket events, three events, board delete success and failure, and paste it here on the bottom. Now we must jump inside our services, board service, because here we want to create a new method to remove a board. This is where here let's copy paste our update board and change it to delete point. And the only thing that we need is our board AT, we don't need here any fields. And here we want to emit our board delete event. So let's try it here. Bought delete and inside we will provide an object with just one field. Indeed is our board ID. Now inside our application we can call this delete board and it will throw insight Socket Layer corrective end. Now let's update our component. So I want to go back inside our board. Components bought HTML. Here we have our inline form. And after this inline form, we must create an icon which will delete board. This is where here let's say div class Delete Board. And here we will have our click event and unclick Poupon to delete our point. And actually we don't need to provide anything inside because we have NAD of our board inside our test file. So here I want to close out our div and just try it inside Delete Board code. Now we must jump inside our ts file and create this method here on the bottom. And what we want to do inside our delete board, we simply need to call our service. Well, here we know that it is a void and we want to call a service. But actually additionally, I want to write here a confirmation because we must be sure that users really want to remove a board. So let's try it here. If confirm and if you don't know what is confirmed, this is a standard Javascript popup inside the browser, which will show you a yes or no. So here we want to write something like, are you sure you want to delete the board? And if the answer is yes, then we're going inside this sieve and we will call this board service. And here we have delete point where inside we can provide our board AD. And now you might think, okay, we must update now our board service. But we don't need to do this at all because actually it is much simpler. What we want to do Poupon to subscribe here to our socket event, which will be deleted success. Let's do this now. For this we want to copy paste our socket service, listen and hear boop want to listen to void because back whoop won't get a board. We know this is just success of deleting of our board. This is where here the event will be bought, delete success, and back when not getting anything. And the question is, what we'll want to do inside and actually we simply want to redirect the user to our homepage. Why is that? Because actually we have a listener here on the top of navigation Start, which actually means at the moment when our user is going to another page, for example, to the homepage, we will handle live poured through our board service and we will remove all streams correctly. This is way here what we want to do inside our subscribe, you simply write this router dot navigate by URL. And here we have, for example, slash boards, which actually means the board does not exist. We must show for every single client list of possible available boards. Let's check if this code is working. As you can see, we don't have any errors on the client. We don't have errors on the backend. Let's open it now in browser. And as you can see, our page is still working. And now we have this delete board. But actually, I don't want to remove this part because we built quite a lot of tests in here. But I want to do, I want to jump back inside of our boards and create a new board, for example, to remove. In this case, we can test this functionality on this new empty bar. But we want to do now, we want to duplicate this tab just to check if it will work for the second user. So what I want to do now, I want to click Delete point, and as you can see, I see a confirmation. I assure you want to delete a board where hidden, okay? And where there is regularity reacted to our boards. And as you can see here, we don't have our board because it was successful or removed. And as you can see in the second tab, where all the digits directed to our slash part because all our clients inside this room were notified about successful in removing of the board and they must be rejected to our boards page. And as you can see, our architecture is so amazing that we can create new features just in a matter of minutes. 40. Delete column: In this video, we must implement deleting of our column. And actually here we have a column inside our board and the mass near the title show the icon to delete a column. And again, it must be implemented with the socket IO. So we will notify another user's about our deletion. And I think that it is a really nice feature that you can implement on your own because it will be super similar to delete in a bird. And here is some help from my side. First of all, as always, we must on the backend, implement new events and registering use socket event. After this, we must create a new controller action which is columns. For example, delete column. We must also make sense just on the client. First of all, registry and new event. Then we mustered new method inside the column service which is shareable to remove a column. After this, we must update our component to add a button on which we will remove this specific column from this point. And actually this is just a meeting of the event for the back-end. And we're also must subscribe to the success to remove this column in all our clients. And here is the markup of the button. So you know what you need to implement. As you can see here, I'm inside board component HTML. Here we have our column titles and directly after the title, we want to write here an image with source. And here we will have slash assets, slash close underscore, icon dot SVG. And here we can close our image, but we're also must provide here a class which will be column delete icon. Let's check this out. I'm reloading the page and here now we have a nice cross. And this is exactly where you will bind the event of click. But if you just want to follow along, Let's implement this together. And actually as I said, it will be super similar to deleting of the board. This is y. Let's do it fast and furious. So first of all, I want to start with our backend and biomass jump here inside our server source types. And here we have our socket events. And again we have here boards delete, I can copy paste it and just change it to columns delete. This is y here on the left we will have columns delete and on the right instead of boards will write everywhere columns. And also we must change it in success and failure. So our events are there. Now we must jump inside our server tiers that here and use socket on here instead of boards delete, I want to write columns delete, which we just created. Here. Instead of board controller, we must use our columns controller. Here we won't delete a board, but we will delete our column. And now we're mustard delete column method inside our columns controller. But I don't want to retype anything because the code is exactly the same leg deleting of the board. This is where we can copy, paste completely this delete board and paste it inside our columns controller because it will be 99% the same. So first of all, the question is, what we must get here as a parameter? Here we're already, I get in board AD and they want also to get here column they D, because we need to know what we're deleting. And you might say here, okay, But why do we need poor lady? We just need a columnated and actually not because we're must notify everybody who has subscribed to this specific board AD. This is why we must provide both values here. After this, we're checking here for our user and here we must meet a failure event. In our case it will be columns delete failure. Here this user is not authorized, and here we have our catch and we can use here the same columns delete failure with our get error message. Here. Instead of board model, we'll use our column model. Here we're deleting one record by data dot, and here will be column ID because we must delete our column not are born and after this way meeting our success. But here we will try to success for our column delete, and here will be success. And actually we're already ready with our backend. What I want to do now is copy paste this socket events because we will use it on the client. This is the way here I will copy paste columns, delete success and failure, and that the disabled Champion set clients source app. And here we have shared types and here are our socket events where inside we can paste columns, delete. Our next up will be tub Data, Service, Insight shared services columns. Because we want to implement delete column exactly here. We can write new method delete column, and we know that we are getting here our board ID, which is a string, and also our column ID, which is also a string. And we're getting big void because we just want to emit our socket event. This is why here we can write this socket service and meet, and we're using here our socket events in m dot columns delete. And we must provide as a second parameter and an object with our board AD and also column ID, which we're getting from the parameters. After this, we must update our board service. And just to remind you, bore services exactly where we're storing our stream of columns. Which actually means here we must implement delete of the column. So here on the bottom, I can create delete column method. And here we just need our columnated. We don't need here Board idea at all because we will call this method just from the component to update our stream. So here we know the column ID that we want to delete and back we're getting void, and now we want to update the list of our columns. This is way here. We can create a property updated columns. And here we can access our stream with these columns stream. Here we're getting our value. And after this we want to filter our array. And actually here we're getting access to every single column and we want to reject this specific column id. This is why here we can check that column ID does not equal our column names, which were passed as a parameter. In this case here we're getting exactly the same list of our columns, but without this one column. And after this, we must just update our stream. For this, we can write these columns next and we're throwing inside our updated columns. So actually this method will update our stream and remove a column from the stream. Next step is to update our component. And actually we're already changed our HTML. Here we now have an image, but we must attach, hear a click event. And here what I want to do, I want to delete a column. This is the way here we can provide a method delete column, and we must pass inside com dot id. And here on the top, as you can see, we have access to our column. Now we can jump inside our component and create this method. So Dalit column is getting just a single argument, which is our column ID that we want to remove and bank where getting void. And now inside we simply want to call our shared service. So here will be this column service world or the Herod. Now here we have a method delete column inside. We must provide a board AD, and actually it is these board AD and then column ID. So this line of code will emit an event to our backend to remove this column and notify all our clients. And now we just need to subscribe inside our subscription here on the top that we want to update our list of columns. This is where here actually we can copy paste something similar and welded have here columns creates success. I will copy, paste it, and paste it here on the bottom. And here we have delete and actually delete with didn't do it correctly. I want to jump back inside our controller columns. As you can see here we have i2 data board they emit, and here I just changed the name columns delete success, but it is not enough. We must provide here some data because actually all our clients must know what column we must remove. This is where here as the second parameter, I want to provide data dot column they deep. And in this case we are given enough information to all our clients regarding our column delete. Now we can jump back inside the board component and here is our listen. And actually here we're listening to our columns, delete success. And here what we're getting back is not a column, but just the string that we want to remove. This is why here we can write that this is column ID and actually this is enough information for the client to remove a column. This is why here we can now call board service dot. And here we have our delete column. And the inside, as you can see, we're providing column they D, and this is exactly what we have here from our back-end. So actually we implemented everything for our feature. Let's check if it's working. First of all, let's check the backend we have here a problem. Delete column does not exist on type and here is columns. Let's check this out. I will jump back inside our controllers, and here we have our delete board. So this is the problem. I copy pasted Delete Board method, but they didn't rename it. It should be delete column. Let check that again. I'm saving it and jump into the console. And as you can see now, we don't have any errors. Now let's check our client. Everything is looking fine. So let's jump to our board. As you can see, our pages working. And now here I can click across to remove, for example, this full column. I'm clicking it and as you can see, it is completely gone. And what is more interesting, we can duplicate the tab and try to remove this next column, F, F, d, d, and so on. I'm hitting here cross and it is removed not only here, but also in this tab. And everything is automatically updated, which actually means we successfully implemented removal of the columns inside our application. 41. Update column: In this video, we must implement one of the last features regarding our board, and this is updating of the column. And as you already can understand, it will be super similar to delete the column. The only difference is that we will have an inland from the updated, but a lot of stuff will stay exactly the same. Where a meeting, I'm a socket event where getting it on the backend and when we define all our clients, this is y. Let's implement it together now, first of all, I want to jump back inside our server source types. And here we must create inside socket events in new types and hairball to the head columns grade, I can copy paste it and rename two columns update. So here we will have columns Update, columns updates, success and failure. Here on the right. Then we can change it to update. Then a birthdate success and update failure after this lithium back inside our sorority S and here and you own event. So here I copy pasted column delete, and let's change it to our columns update that we just created. And here we're using our columns controller, but here we're getting not delete column but update column. Now we must create this action, but actually we can copy paste it from our boards because here we're already implemented update board and it will be super similar. This is why I want to copy pasted completely and paste on the bottom inside our columns controller. Here with first of all, must change the naming. So here we have our update column and actually I want to keep it exactly the same with poor lady and fields. So we have exactly the same structure. This is where here the only thing that we need is column ID, which is a string. And the only field that we're updating here is our title. Now let's change our content. Here we will have socket events in m and here were created column update failure. And let's change also our catch here will be also Column update failure. Now we must change our logic. Instead of Bohr's model, we will have here column model and we're making fined by the end update. This is totally fine. But here we want to get not a board, but column by column id. And here we have data fields. This is completely normal and backward getting updated column and not updated board. Now here we want to emit to all our clients our event, which will be column update success. And here we must provide our updated column so they can change it on the client. Our backend is successful, it changed. Now we must update our client. And first of all, I want to copy paste this three new events, which are columns update, success and failure. Now let's jump back inside our clients source app. And here we haven't said shed our types socket events. And here on the bottom I will add columns update success and failure. Now we want to change our shirts service, which is responsible to make requests to our API. Here are the services columns and here we're already implemented delete column, but we need to do now is our new method update column. Here we already know what we're getting. We're getting here our board ID, which is a string. After this we're getting our column ID, which is also a string. And last but not least is our fields, which is an object with a title, which is a string. And back we're getting void because here we simply emitting an event. This is where hear sockets service Datta meet and we want to use here socket even see them dot. And here we have our columns update action as the second parameter. We must provide everything. First of all board AT secondly column needy. And last is films. And with that, our service is completely ready. Now we must update our board service so we can change our component. This is why I will jump inside our app, board Services, Board service. And here we're already created a method update board. This is where here let's create our update column method. And we know that group want to update one single record inside of our array. And here the only thing that we want to get is a bit dated column. This is what we got from our back-end. Here. We're getting the whole column interface and back we want to get void. Now, here is our idea. We need to map through every single column and update this column by dy. This is way here we can get back our updated columns. And here we want to get first of all, the value from our stream. So here we will have our columns get value and we're mapping through this array. So here is map and we're getting access to every single column in here inside we must write our logic. So if our column ID that we're looping through equals to our updated column dot id, then we must do our magic. And if not, then we simply want to return our column without an update. Now, what do we want to do inside the loop one to update this specific column. This is why I want to merge our column with title. And here we're providing updated column dot title. In this case here we're updating just a single jacket when it matches. In other case, where simply returning our column. After this, we just need to update our stream with these columns next. We're provided inside our updated columns, so our method is completely ready. Now we just need to update our component. So let's jump back inside our board component, and here we have our column title, but instead of just a title, we must trend here are inline form, this is y here. Let's try it inline form, and let's close it here directly. Now, first of all, here we must set our class which will be added column form. After this, we must provide default text. And here we want to write the name of our column, which will be column, the title, but also must provide here a value. This is y, here will be title, which is our column title. And the last one is our callback, which is handled submit. And actually this method we can name, update, column name, and inside we're getting Festival, our event, which is actually our column name. And here we must also additionally provide column ID because it not the case Groupon know for what column we want to update this specific screen. Now, let's create this method inside our component. So here on the bottom I want to add update column name. And here we are getting first of all, our column name, which is the string from our inland fun. And secondly, we're getting here our column ID. In this case, we know what we need to update and what we want to do here. We just want to call our method from shred columns. This is y, here, this column service, and here is our method update column that we just created. First of all, we must provide here our board ID, column ID, and also our fields. In our case here we just have a single field, which will be our title, which is our column name. From the client side, everything is ready, but we must subscribe to the success of a birthdate in the column. This is why we must go here on the top, on now a socket services. And actually here we already have our update of the board, which actually means I want to copy paste this lines and just change them. Because here back, we will get our column interface after we updated our column. And actually here we want to subscribe to call them update success. And here we're getting not updated board, but we're getting updated column number must call another method from our board service. And this method will be update column. And inside we're providing our updated column, which actually means with this code, all our clients will be notified and we'll update this particular column. Let's check if it's working here on the backend, everything is looking fine. Here on the client, we don't have any errors. Let's jump to the browser. And as you can see here, I have this nice name and now I can click on it because this is our inland firm and not just the title. Now let's try it here, updated and I'm hitting Enter. And as you can see, it was updated and deferred loading the page, then this code is also stain, which actually means we successfully made this change is on the backend and they did all our clients. And here, if I'm jumping to the second tab, it looks exactly the same because it was also updated and notified through socket IO. With that being said, we successfully implemented our feature of update in the column. 42. Unsubscribe: In this video, I want to talk about unsubscribe because actually we have a problem. Let's look in our board component test. Here we have our initialize listeners and we're using dot subscribe quite a lot of times. And actually you must know that inside Angular every single time when you are writing the word subscribe, you are in danger because you are creating a subscription there. And this subscription will Hank there until the end of the world. Which actually means, for example, we're leaving our board and we're jumping to another board. And all these subscriptions are already there and they will never be destroyed because all the subscriptions doesn't have anything to do with our component and the angular does not do anything about them. But here it is important point to mention, if we're talking inside Angular about HTTP client, then we must not unsubscribe from it. This is not mandatory because angular will unsubscribe automatically, which actually means here when we're using this router events subscribe, This is totally fine. Here we can also look on our fetch data and here we're also use subscribe to our get bored. And for this we must open our get bored and check what we have here. And actually this is a pretty big Gad, which is an HTTP client, which actually means this code is totally fine and we should not unsubscribe. But actually, I prefer to unsubscribe everywhere, in every single application where a C subscription, because you never know what exactly is this get board method? Is it really HTTP client or is it just some wrapper around? And you really need to unsubscribe. And the question is how you can unsubscribe in your application to make it comfortable. And there are a lot of ways to do that. And actually we always want to unsubscribe when we're destroying a component. And typically where this turner component, when we're changing around, which actually means here we can write something like this board subscription equals. And here we're getting the result of our subscribe and the result of the subscribe easy subscription, which actually means per mass create this property and then right inside our engine, destroy Boards subscription dot unsubscribe. This is totally valid, but then we will create lots of properties and this is not that comfortable. This is why there are better ways to do this. I wanted to show you one simple approach that you can use. What I want to do inside my board component, I want to create one more property and they want to name this property unsubscribe. And actually I want to put here dollar because it will be a stream. And here I want to assign a new subject and actually also the youth behavioral subject inside our board service. But here we have a new subject with void, and I'm just calling it, the main difference between subject and behavioral subject is the behavioral subject always has an initial value and then say, subject, we don't have any initial value. Now here we want to add implements on destroy, which actually means we must create in G on destroy. And now here we're talking about in Germany in it. And here we can write in June destroy and what we want to do inside, we want to write this unsubscribe dot next, so we're column the next value. And after this, this unsubscribe dot complete, which actually means after we destroyed this component, we don't want to get new values inside this unsubscribe. And now we can use this unsubscribe everywhere to ignore subscriptions. How does it look like? Actually here, we don't need to use it, but we must use it inside the socket service because it is a custom subscription. And in order to do that before our subscribed, we can just try it dot pipe and inside we want to use method take until and inside they want to put this unsubscribe that we just created, which actually means here we're taking, okay, We must take new values and have this subscription until this unsubscribe is valid. At the moment when we're Colin complete with bond, come here to our subscribe. Which actually means in every single case, when we have a subscribe, we can just try it before by uptake until this unsubscribe. And we're good to go after our components will be destroyed. Here we will have complete and this logic will never happen. This is really a comfortable and easy variant to implement, unsubscribe. This is why I want to copy paste this code and put it in every single lesson that we're writing here just before subscribe. In this case where on the safe side, and we won't call this code after destroying a component. Now you for sure want to know if it is really working like this. This is why in order to test it, we can simply comment out taken till for example, in columns, updates access. But actually it won't work like this because when we were leaving the board, Bacon stops sending events to ask, this is why what we can do just for testing is championed inside controllers columns. And here is our method update column, and here we have our function are your two. And here we need to find only clients where they're inside this specific part. Just for the sake of testing, I will remove here to notify all clients at all because they want to show you that this subscription is still there when we're leaving the board. So now here I want to just try to console log. Got updated column. Here is our updated column. Let's check this out. I'm reloading the page, I'm jumping to this point and I'm trying to update the column. As you can see, this is our console log, and here we also have the console log. It is totally fine. But now we're jumping back to our boards and we don't have anything and our component was destroyed. Now here on the second tab, we will update this column. And as you can see here, insert first step. We have this got updated column and we're getting it because this subscription is still hanging with didn't unsubscribe from our code and denoted to do that, we can just uncomment take until, Let's try it. Now, here we're jumping inside our application. We're getting, got updated column where champion back to our boards. And now here we can try and update our column. But as you can see now inside the first step, we didn't get a message because here it didn't go through this take until, this is why it is so important to unsubscribe from all our subscriptions. Now let's change this code back. First of all, we don't need this console log. And secondly, I will jump inside our controller columns and change code back to i2 database ID. So in the real application, I highly recommend you to unsubscribe from all your subscriptions. 43. Task module and basic component: In this video, we start new and interesting feature and then talking here about feature task model. What does it have a mean? Actually, as you can see here, where inside board and when we click on specific task inside this point, actually, we must open here a model, but it is not as simple as that, because what we want to do, we want to change our routing. So now we have slash board slash board Id. And actually when we open a task after page reload, we want to see the same task. And the easiest way to implement this is obviously routing. So we want, at the moment when we're open a task URL like slash board slash board ID slash tasks slash task KD, which actually means we have a Nested Route inside board. And actually Angular allows us really simple to run the children droughts. Why do we need here a child drought? Because they actually here we want first of all to render the whole board and additionally to render this model, which actually means our model, will be here on the top and beneath our model, we will see the whole board. And this is extremely important because actually we will, even inside the model, fetch the whole board. And actually this whole component will be rendered Just as it is without any changes. And what is also interesting inside our task model, we will use this information from the board, and this is exactly what we implemented here. Here inside our client source, app, board services, Bot Service, we have three streams. Our tasks column and, but, and this is amazing because now inside our task model, we can read all our tasks, find needed task by this ID inside URL that we will implement in a second and then just render this information of the task without additional requests. And in this video, I want to start with the basics of this task model. Here we want to create a basic component and bind correctly our route. And for this, I want to jump back inside of our board module. And here we have our route with slash boards, slash board Id. And here we want to have a child drought. This is where here we can write children and this is an array. Here we also have an object with path, which will be Tasks slash. And here is task ID, which actually means we're taking here parent path and our child path. And together we will have our task ID path here, but also must provide a component that we will create in a second. And it is our task model component. But also we didn't implement changing of our route. And for this, I want to jump inside our components board. And here is bought component HTML. And as you can see here, we have a link to our task. This is this div class task, and here is energy for loop. And actually here we want to write a click event. And here what we want to do, we want to open task. And for this we just need our task dot id. And what we want to do inside this method is just change a route. This is way here. Let's create this open task inside board component. And here we're getting our task ID, which is a string. The back we're getting void. And now here we can simply use our router to change route. So here we can write this router dot navigate, and we're using here navigate and not navigate by URL because we want to pass inside an array. Here. First of all, we have boards, then we're concatenate this string with this board ID, then comma. And we have here our tasks, and here we will have our task ID. As you can see, it is much simpler to write navigate with array, then to navigate by URL, where we must concatenate this string ourselves. So our click event is completely ready, and now we just need to create this new component. This is why inside our board and we're still talking about board module insert components. We want to create our new component and it will be our task model. Now inside with first of all, need to create a task Model Ts and also task model dot component dot HTML. And now here inside the HTML, I want directly to peg the whole markup of our model without any logic. In this case, we can directly see the term model is working and router is also working. This is where here let's write the whole market. So here first of all, we have our class task model container, and here we won't bind any data yet. Now inside this div, we must try it one more deep, and it will be our task modal header. Let's close this div and inside it here we will render later our task title in line form. And after our inland form, we need here to render an image. And actually here will be source slash assets slash close icon dot SVG. And here we also need to provide a class which will be task. Model close and actually I wrote it not correctly. This image must go after our task title inline firm. So we're talking here about task modal header. And after dusk modal header, we want to create the next div, which will be Task modal body. Let's close here our div and inside we want to create one motif because we need to group our elements. So inside this div, we want to create our form later. You might ask, okay, but why here we're using Justin Lin firm and here we want to create a real firm because actually here later, we'll also need a select to change our column. This is why it is much easier to use for this forum. This is y here. Let's create a form for now without any firm group, just whisk glass. And here we will have our column select container. Let's close this form. And inside our form later, we will render here a select, but for now we don't have it. This is where here, just select column. And after this firm will want to create one motif where we will have our task model description. And here we will have our div with the class task model description label. And then side we will simply write a word description. After this div, we will have an inline form for our description. So here is inline form description that we will create late. And now after this div that we created would need to create one motif. And here we will have our task model actions inside with first of all, need one additional class and it will be task model actions labeled and inside this div, we will simply write actions. And after this, we need to create one more div. And inside this div, we will pack one motif with class, task, model, actions, action. Here, Let's close this div and then inside we can render an image with source slash acids slash trash SVG. And here is our class which will be tasked model actions icon. And after the second, we will just render a word delete. And after the whole mark-up at the end, we need to render a backdrop, so our whole board will be a little bit hidden. This is where here we must create div with class task model backdrop here Let's close this div so our markup is completely ready. Now, we just need to create this component. Let's first of all create here a class and it will be our task modal component. On the top were mastered our component, and let's register inside. First of all, a selector, it will be tasked model. And after this, a template URL and welded, the heavier it is task modal component HTML, but it is not all. We must provide one more class for the whole wrapper of this component. Only in this case, our market will be correct. And here we must straight host binding. And here I'm providing insight class. Here we can write classes equals task model. And if you never wrote something like this, we're using such notation when we don't need to apply this class to some deep inside this component, but we want the exactly to apply a class on our component element. So we did some basic components. Let's check now if it is working at all. So Festival here we have a lot of errors. For example, here in board module can not find task modal component. So first of all, here we must jump inside our board module. And here we need to input our task model component. And we're also must provide it here inside declaration, this is task model component. Let's check again with don't have any errors here. I will reload the page and they don't see any errors inside console now. But what we must do now, we must click on one of the tasks. For example, here is my first task and I'm just clicking. And as you can see, nothing happened. But inside drought, we can see now slash boards, slash our board ID, slash tasks and slash the d of our task that we just opened. And now you might ask, okay, but why we don't see our component and actually we didn't trend the outlet for our children, which actually means inside our board, inside board component HTML, somewhere inside our markup, for example, on the bottom, we must render Zhao outlet just like we did inside our app component. So here let's just close router outlet and now it must work. I will reload the page. And as you can see, we see our model by that because actually this is the route. And now every single time when I'm reloading the page, we see our parent in the background. And here we see our model and actually already have some basic markup for this model, which means it is fully working. But now I want to fix a huge pitfall which will be super difficult to debug what I'm talking about. As you can see here inside our board component, here we have a route check and actually here on the top, we subscribed to this event navigation stars. And here we're triggering live born. What does live board doing? Actually here we're meeting a socket event for our back-end, which actually means we are unsubscribe in this current socket, our current user from you went on this point, which actually means here we were on this point, slash board slash AD. And now here we're getting events. Everything is fine. But at the moment when we open our model, we changed around. And actually it means that we are here in this IV and here we see live what we can easily check it. For example, here I will just try it live, but I'm reloading the page. It looks fine. But when I'm jumping to our boards and then just click on my first task. As you can see here, we're getting leave board. This is completely redrawn because in this case we won't get any notification in our board, but already left the board. This is Sean behavior because we don't want to live a board. If we just open the model, we still want to be on this page, but we can do to fix it, we actually just need to check for our slash boards route. Because actually if here inside drought we have slash boards slash, it means that we're still staying on this page. Because if we're jumping back on our boards page, then here we have just slash boards and we don't have a slash. And then this is where here I can write end not event dot URL. And this is the whole URL where we're going includes, and we're checking that this specific URL slash, boards slash. So actually here we will trigger our lives board when our navigation start happened. And this URL we're going does not include slash port slash. This slash board slash is either our single bonds or our single board was model. Let's check if it's working. I am clicking here my first task and now we're not getting left part, which means everything will work fine. And now let's implement together. Go to the board because this is just a single line I want to do. I want to jump in our task model. And here on the top we have this close image. And actually here we can additionally just create a click event and let's name it, go to board. Now we can jump directly inside our task model and create this method, go to bond. And what do we need to know inside this component in order to jump to our board, we must read from this year. Well, first of all, our task ID, we will need it in any case. And here most importantly, board AD, which actually means we will write the same code like we did inside our constructor inside board. So here let's register our constructor. And inside we need to get first of all, our board AT. For this, we need to use route, which actually means here we must inject our route, which is an activated route. And now here we can write this route dot snapshot, dot, params, map, dot, get. And here we're trying to get our board Id. And as you can see here, we're getting strain on now. This is why it makes a lot of sense to check if we really got our board ID. In this case, we can save board Id and task AD directly as a property inside our component. This is way here I first of all want to create our board AD. It is a string. And secondly, task Katie, it is also a string. Now here we can check, okay, duplicate a board. If not, then we need to throw an error. This is where hear thrown you error. And here we can say can't get board ID from URL. And now we need to do exactly the same for our task ID. This is way here. Let's try to task AD and we're trying to get task a different route. And now here we want to write one more Eve and check here for task AD. So here we can write, can't get task ID from URL. But actually here I made a huge mistake is you can see we have a board Id and task ID, but with Taskade, It is totally fine. It is this route snapshot params map. But with Boyd AD, it is not fine because we want to read all this information from our parent. This is why here we must try route dot parent, and here we must put a question mark and then snapshot programs map. In this case, we will read it directly from the parent. And now after these two checks, we can just assign this task AD, and this is a string now, and here we also have this board ID and it is also a string. Now here we can implement go to board method, but for this womb must inject here. Additionally, shout to change your route. So here we have our router. And now inside this method, we can simply write this route and navigate just like we did previously. And here we want to go to board. And as a second parameter it is this board. In this case here, the URL will be slashed points, slash board ID. Let's check this out. I'm reloading page here. I am inside task and here I'm clicking Cross. And after clicking where they directly jumping insight slash forward slash id. And most importantly, we didn't have a page reload. We don't need to fetch data for this part because the whole data is there. And now we can simply open second task, close it, and it is really smooth and fast because we don't need to fetch additional information here. 44. Get task and columns: In this video coupon to talk about data streams inside our task model. This is where it will be really interesting. Why is that? Because they actually were already have the whole data for every single model inside our board, we just need to use this data and map it correctly inside task model. This is where the first thing that I want to do is inject here our board service that we already have and not Boards service not to work with the pie, but our board service with state. Now here, first of all, I want to find the task. And actually here for example, after this board ID inside constructor, we can just write this task was taller and it will be our stream of the current task that we opened. And here we can actually just tried these sports service. And here we have our stream with all tasks of our board. And as you can see, it is already available, but we don't need the whole array of our tasks. This is way here boop want to use map. This is by here we can write by map and then cite where getting access to all our tasks. And now we just need to find one specific task that we need for this task model. So here I want to just return tasks find, and inside here, we will get access to every single task. And here we just get this task by AD and we compare it with this task AD that here on the top inside constructor. So actually what this does, it transforms our stream board service tasks. And here we're just mapping the single task and here we're getting it back. But it is not all actually after map. I want to write filter and here inside I want to provide boolean. Why we're doing that? Because actually it might happen that at the beginning with don't have a task because we didn't fetch all these tasks here, which actually means where jump into constructor inside our model, this is our stream. Tasks is simply an empty array. Here we tried to find it and we can't and we get an undefined it, but undefined it is not interested in fast. This is where here I wrote filter Boolean and it will just get rid of every undefined it on. Now, in this case here, this stream won't be fulfilled until we can find a task. So now let's try to use this trim inside our HTML. Here on the top, we must create an inline form, the updated title of our task. And we can simply write here our inline form that put already used hundreds of times. And then side first of all, we must set a class, and here we will have task model added title forum. After this, we want to set our default text. And actually here we need to provide the title of the task. But again, I want to write it even better. We could use this stream inside our HTML. But as I already talked previously, we can combine different streams of data inside a single property, and this is exactly what we can do now here we can write this data was taller and we can use here combined latest, just like we used previously and actually later, we won't have here just a task at least will also must get here a list of our columns by that, because actually we have a select to change the column where this task is. This is way here. First of all, we will have our this task and later additionally pupil right here, stream for the columns. And here we need to pipe map all this data and we want to convert our array to the object. Here. First of all, we will get our task. Here. We need to return just a task. Now here we must create this data inside this component, this way here on the top. First of all, we must change task dollar to observable. And here we're getting our Task interface and never now because we checked it with filter. And now here we also need data we stolen. And here we will also have an observable of the object. And here we have our task, which is a Task interface. Now, data is ready, actually inside the HTML, we can use this data directly. This is where here on our top div, I will just try it. And G, Here we have our stream with data as, and here we're getting data, which actually means now in the whole file, we can just use data. This is y here inside default text, we can provide data dot task, dot title. And after this, we need to provide a title inside form, it will also be data task dot title. And as you can see, we don't have streams here, but actually here inside data, we created a task Stream, which is a string based on our stream where we have an array of tasks. And the last thing is an output here and here we have our handle submit, for example, update task name. And here inside where getting an event. And they just want to create this function inside our component. I won't implement anything here. So here we're getting our task name. Which is a string, back is void. And now I just want to write here console log. This is update task name, and here we're getting our task name. Let's check if it's working at all. We don't have any errors here and they will just reload the page. And as you can see directly here, we're getting my first task. How does it work? Here we build our stream task, which is based on our tasks and actually after pages a lot when not getting an error. And we could potentially get it. Actually not because we have here in GE with Chegg, but it is always nice to write filter Boolean just to know that we're on the safe side. And here we're getting our first task inside this data stream. Here we can directly change this, my first task and updated. And as you can see, this is our console log. Obviously we didn't implement update yet, but we're on the right way. Now. We can write exactly the same code with our inline form description. This is why I want to jump back inside our HTML. Here is our inland from description. And actually here we can just try it inline form like we did for the title. And here we already have the data inside the data stream. This is way here. First of all, our class task model, edit, description, form. And after this, first of all, we have here default text. Here we will try it data task description. And here I want to write, or because actually a description inside the task is not mandatory, which means at some point it will be an empty string. This is way here, add a more detailed description. After this, we also want to set our title. This is why data dot task description. Also we want to provide here at exterior, and this is our first usage of textarea. This is way here. Input type is text area also has Button property must be set to true. And after this button text can be set to save. And we also need to provide here I handle submit. Here, let's name it, update task description. Here we're getting our event actually. Here we must create the function, but it will be exactly the same. This is why I will copy paste, update task name, and just change the name and the console log. But obviously it is not a task name but task description. Let's change it and console log and check if it's working. As you can see here, we're getting an error type undefined. It is not assignable to type string. Actually it is a valid point from TypeScript because our inland From want to get just a string and not an undefined it here. This is why we can just try it or empty string. This is totally fine. As you can see now we don't have an error. Here we're getting now my description, which is a real description from our task. We can change it and hit Enter. And actually here this is a textarea, So Endo doesn't help. We must click on Save button. And here we're getting inside console update, task description, my description, which actually means our inland firm is working and our stream is also providing data fast. And now let's talk about columns. Actually it is even easier. We must just jump in, say task model. And here we need this stream for the columns from our board. And actually we don't need even to create additional property here inside combined latest, I can simply write this board service dog. And here we have a stream columns and we can just pack array of columns here inside this component, and we're good to go. So here we are getting our task. And secondly, columns in here inside the object boop want to return this array of columns. And now here we can use these columns to build a select inside our Markov. So actually here we have a form and inside it we want to write a select. Let's do this now. First of all, here will be S Select and we want to write here form control name because actually we need to bake it in from Group. Why we're doing it? Because actually it is much easier to work with reactive forms if you have, for example, a Select. This is way here. Let's create a form group. And here we want to create, for example, column form. And here inside select, we can just pack form control name, and it will be our column ID. And here we also must provide the class column select. Now inside select, we want to render all our options and it will be our array of columns. This is way here, option within G4, we're rendering it in here with just loop through our columns because we have them in data dot columns and we don't need to bother ourselves with streams here. Also here we want to use in G value and provide the value inside R option. This will be column dot AD because we're looping through them. Let's close this option and just ran the inside every single option at title. So here we will just run the column dot title. Let's check if it's working. I'm jumping here and we're getting an error and G value is unknown. And first of all, we must create our form. This is why let's jump back and set our component. And here on the top we must create a form for just a single property. So here I will try that we have our column form. And it is this FB. And actually we didn't inject here if p. So let's do this now. If B is as always, just form builder, and here we will write this F B group and inside we will pass our controls. And here we have just a column ID, but don't need anything else. And by default it will be. Now here we still get this Sarah. And actually, because we didn't inject reactive forms inside our board module. So we must jump back and set our board module. And right here inside the input reactive forms module, as you can see now we're getting another error inside our HTML. And here we're getting columns does not exist on type Task interface because actually we didn't extend our interface. Here on the top we have data stream and here we say that we just have a task and this is not true. We have here columns, and this is just an array of our column interface, as you can see now inside our console with don't have any error. So let's check this. Now I'm reloading the patient here we have now our awesome select and we don't see any value because we didn't provide a default value. Now here we can open this select and we can choose between different columns. And as you can see this a directly our columns that we have inside board. Now the only last thing that I want to implement, setting default value inside the select, because actually by default we have a column and this task is situated in some column. And we can easily do this because we have streams. So here we can just use this task was stolen because we have the stream. And here we know that we're getting our task and we can just write Subscribe here and we're getting access to our task. And now we need to update our form. So here we have access to this column form, which value, and if you don't know what pitch value is doing, it update properties inside form. So here we must provide an object with fields. And in our case this is just a single field column ID. The inside we want to provide an ideal for column from that task. It is task dot column ID, which actually means inside constructor on initialize where subscribing to the Task Stream. And when we're getting our task here, we're patching the value. As you can see now instead browser, we're getting our first column. But what I don't like here, we're using subscribe again without unsubscribe. This is why I want to do exactly the same what we did inside our board. First of all, here we must create our unsubscribe. And this is in use subject where inside we're providing void. And now here we want to create in G on destroying. This is way here, implements on this Troy. And somewhere after constructor we can create in June, the strike and insight with first of all, want to call this unsubscribe next and then complete. So these unsubscribe complete. And after this we should not forget before our subscribe Write pipe. And here take until here we're providing them with these unsubscribe that we just created. In this case, we are on the safe side onDestroy of this component. Our subscription will be also destroyed. 45. Update task: In this video, we must implement updating of our task from the beginning to the end. And actually inside of a task we have three different things. First of all, here we have an inline form for our title, for all of the implemented it. And we're getting here console log. Actually this is a partial update of our task. We have exactly the same logic with description. Here we can just change it and hit Save. But also here we have a changing of our column and actually we didn't handle it at all and we must do it. And this is also an updating of the task. Most importantly, these are all partial update which we must meet for our back-end because we want to notify all our clients about this change inside task, which actually means that our logic will be exactly the same like previously inside part, we're emitting something on the client, on the backend, we do something to our database, for example, web data task. And after this, we're notifying all our clients who are subscribed to this specific board. And the first thing that we need to do is create a new socket events. Let's start this time on the client. And inside our source app shred types, we have a socket events. And actually here I see tasks Create, and now we need exactly the same with PS tasks update. And here we have success and failure as always. And here we can change the name to tasks, update, then update success, and update failure. So our event is ready, Nobu must implement a new method inside our shirts service tasks, because as previously, we want to hide our socket inside this method inside share tasks. This is way here. Let's create our method which will update task. Here. First of all, we're getting our board ID because we must know what users, we must notify. This is where hear birthday, this string will also need a task ID because we must know what task we must update. And last but not least, here is a list of fields. And here we will have an object where all our fields won't be mandatory. This is why I'm writing them with question mark so we can update our title. It is a string. We can also update our description. It is also optional and string. And here we also have our columnated and our column lady is where our task is situated. And back here we're getting void. The only thing that we must do here is socket meet. This is why socket service summit. And here we want to use our new method, socket events in m dot. And we have here our tasks updates start here as the second parameter, we must provide an object with all these fields. First of all, it is a border radius, then column ID, and then our object with fields. And as you can see here, I made a typo. It is not continuity but task ID and because of TypeScript with directly see an error. So now we can jump back and set our component and do necessary changes. And here we have our update task name and the date description. Here in both cases we want to call this update task method. This is way here on the top with first of all, must inject these tasks service that were just updated. And it is tasks service. After this, we can simply write here this task service, and here is our new method update task, and then say it. First of all, we must pick a board AT this board ID here is of a task or do we have here task ID? Yes, we have, we set at it here inside the constructor. So here we can also write this dot does KD, and here we have our fields. In this case we just need to update the title. This is way here we can say title, Task, Name, and as you can see here, we're getting a strange property column ID is missing in type, which actually means I did something wrong. And they already can see the problem here. Column lady is also optional. It must not be there always. This is where here is. You can see now we're not getting an error because all our fields can be undefined it. And here we just need to provide a title. So here we updated our task name. Now I can copy paste this code and update here our description. Here I will just provide a description, and this is our task description from the parameter and now is the most interesting part. We must handle this change of this single select. And actually this is a reactive form, which is actually good because we can react on the changes in completely reacted way. What I want to write here is this dot column form Gad. And here we can get our column ID, but actually here we want to react to value changes and the actual value changes will give us back and observable, which actually means we can write here subscribe. But as you can see here, we're getting a warning from TypeScript that possibly this field can be now, but not in our case, because in our case, it is always said this is where actually here we can suppress this warning just by using bank here. In this case, we're saying TypeScript, don't bother with the check where sure that this property is there. And as you can see now here, value changes is an observable. This is where here I can now just try it subscribe and then getting here what is inside this column lady after the change, which actually means eat this column lady when it was updated. And now I just need to write insert console log. Changed column id. And here we can check if it's really working. Let's reload the page. As you can see here inside console, I'm getting changed column they D, and here is our column ID. And actually this is a problem because what we want to do now inside this subscription, we want to trigger a change for the back-end, like we did here with update task. But it doesn't make any sense to trigger it at the beginning when we have the same column id, we really want just too tricky when we change it. This is why what we can write here. We can check if the column needy, what was changed is not the same like valid half. But here too, the problem, we have this information only inside our task Stream, which actually means we must combine these two streams together. This is why here we can use combined lasers just like we did previously. And here we can provide, first of all, this task was taller. And here after this, this stream that we wrote here on the bottom, I will just paste it as a second parameter. And this combined latest is given us back an array, which actually means here we have access to our task and after this to our column id from the form. And here now I can console log both of them. Here I want to see first of all, changed column lady and secondly what we have inside task. And actually here we want to check task lot column id. Let's check this out. I'm reloading the page and we're getting both eighties. And as you can see, they are similar, which actually means this is exactly the case when we don't need to do anything. So what we want to write here, if our task column they D does not equal our column id, then we need to do an update. Here we can simply write this task service just like we did on the bottom update task. And here inside were provided. And first of all, this board ID, then task, do we have inside task dot id, and here is our fields. Inside fields, we just have our column id property. So as you can see, Eric's JS really helps us to work together with reactive forms, streams, our own streams, or a path which is extremely efficient. Now we can remove this commented code. We don't need it anymore. But what they want to do here, I want to write taken to deal with unsubscribed in this case here, we won't have a handgun subscription. This is where here we must straight pipe taken till just like we did here already. And inside these unsubscribe and actually our frontend part of the code is completely ready. Now we must try the standard stuff on the back-end, which actually means we first of all must copy paste events. Then we need to create new subscription to this event and then implement a new method inside controller to update a task. Let's do this now. First of all, I want to jump inside our socket events and copy paste tasks update. After this, we can jump inside of a server source types. Here we have our socket events and on the bottom I can paste these three new events. Now we can jump back inside or sorority S. And here on the bottom we can add new socket ton. Here we want to listen to our socket events in m dot. And here we have our tasks update here with don't want to call a columns controller, but tasks controller. And here we have a new function, update task, and we must provide insight or your socket and data. Now it's time to create this update task. And actually I need to copy paste from columns update because it will be super similar as you can see here we have update column. I will copy, paste the whole method and jump and say tasks, and paste it here on the bottom. Now let's change it here. We first of all have our update task and we're getting here the data. So what did we get inside data? It was a board ID. Then we have here at task ID, and inside our fields, we have three fields. First of all, title, it is optional. Then we might get here description. It is also an optional string. And last is our column they D, which is also optional. Now let's update our try and catch festival here we're checking for columns update this is drawn, we need to change it to our tasks. Update failure. Here we're sending user is not authorized, were also must change failure inside cage. So here we will have also tasks update failure. And now here we must change our model. The task model find by ID and update is totally fine. And here we have our data dot, and here we have our task ID. In here we simply throw all data fields that we have inside and it will be just updated with what we've provided. Here back, we're getting updated task and we want to send this updated task to our client. And here we're providing data board ID. This is totally fine and demand here is tasks update success. And here inside we're providing our updated task. So we're fully finished with our back-end part, but we must on the client, also write a listen to notify all our clients about changes. So we must handle the Summit on the client. And for this one must go back inside our clients source app, board Services, Board service by here, because actually we simply need to write a lesson inside our board components with don't need to write listen inside board model because actually bought model simply use our streams from here, which actually means with just subscribe inside our board component. In here we will call a method to update at task inside our task stream. This is why here I just want to look on our update column because it will be super similar to our update task. And actually we can copy paste it fully. So let's change it now. Here we have our update task. We're getting here are updated task, which is actually at dusk interface. Here we need to do exactly the same stuff with just need to update a single task inside of our array. So here we're getting updated tasks and here we're using our stream tasks get value and we're getting access to every single task. Now here we're checking, okay, our task ID should equal our updated task AD. In this case here we must return, are spread that task and we want to update here just a title. And actually this is not valid because here we need to return more here. First of all, updated task, the title, but also we must update here our description because it might happen that we updated it. This is where hear updated task dot description and the last here will be our column needy, and it is also updated task dot column ID. It is looking now totally fine. And in other case, we just return our task. And after this, we need to update our task stream with some updated tasks so our method is fully ready now we just need to go back and set our components board, board component. And here we must create one more lesson, lecture. I want to find here our cone update success because it will be super similar. Here it is. I will just copy paste it. And here we need to change it. First of all, back, we're getting our Task interface and here is Socrative and C num dot tasks update success. Now here we have our unsubscribe and back we're getting our updated task. And now here we can just call this method that we just created it, this update task. And inside here we must provide our updated task that we're getting from the backend. In this case here with this code, we will update the Task Stream for every single client who is subscribed to our page. Let's check now if follow a code is working here. We don't have any errors inside front-end, no errors inside back-end. Now let's open our website and actually I want to duplicate the tab so we can check it with another client. So here we're opened my first task and they just want to update a title here. Let's just write full and hit Enter. And as you can see, it was directly updated here, here on the board. And also in the next step, it was also updated, which actually means we successfully updated it on the backend, will notify the law clients with this listen subscription where updated the stream and now all places which are subscribed to the streams off dramatically rear-ended. This is working amazing. Now let's check that we can change a column. So here I want to select the second column, updated and some number. And as you can see directly, this task is gone from the first column, and now it is here inside second column. It was updated inside our form. And here on the next step We see my first task, which is also updated in the next column. Which actually means we successfully implemented updating of our task and also moving it between our columns. 46. Delete task: In this video, we will implement the last feature inside our project, and this is deleting of the tasks. Let's do this now. First of all, I want to start from our server here, but must jump inside our source types socket events, and create three new socket events. Because actually we want to notify all other clients that were removed a task. This is why we will do it through socket events. This is where here I will copy paste tasks update, just change it to tasks, delete. And here on the right we can change it to tasks, delete, tasks, delete success, and tasks delete failure. After that, we can jump inside those celebrities and new socket ton. So here we're must name it dot, and here we have our tasks delete, which is a standard. And here is our tasks controller where we're calling our delete task. And now actually I want to copy paste our deleting of the column. It will be super similar. As you can see here on the top, we have delete column method and they will just copy it and put inside our tasks here on the bottom. And now let's change this method. First of all, does not delete column but delete task. And what we're getting here, we're getting as always bored, they need to notify all our clients. And here we must get just the task Katie, to know what we need to remove. And here we have our error and we just need to call here tasks delete failure. And here inside our cage, we can also call tasks delete failure. Now here instead of column model, we can just use a task model dot delete one, and we simply delete our task by task ID that we provided. And after this, we're not define all our clients with this socket tasks. Delete success in here Beckwith, just need to give a task a D because we don't have more information and this information is sufficient for our client to understand what task must be removed. Now we must continue with client path and for this one must copy paste these three socket events that we just created. I will go back inside our clients source AB, shared types, socket events. And here on the bottom we can add them. And now we must update or service to work with tasks. And what we want to do here, we want to create a new method which will remove at task. This is way here. Let's create delete task. And we know that we simply provide here a board ID, which is a string. And also we need here our task ID, and it is also a string. And back we're getting here void. And now inside we can simply call our circuits service dot image. Here is showing you event socket event cinema dot tasks delete here as the second parameter. We're providing our options, which is first of all board AT and secondly, our task ID. And with that, our API method is completely ready. Now we must jump inside of board module and board service. And actually here we need a new method just like delete column, but it will be deleted task and actually the code will be super similar because here we just want to filter one specific task from our array. This is where here let's change it to delete task, and here is an argument we're getting our task AD. This is where here we want to loop through our stream, which is Task Stream get value here where I get an access to every single task. And we're comparing our task k, d with the task id that we need to remove. And here backward getting updated tasks. And now here we want to update our stream, which is our Task Stream Reserve and you updated tasks array. So we successfully created our delete task for the board state. And now here I also want to remove this comment. We don't need it anymore. Now, we must create some HTML to remove our task. This is where we must jump back and said our components task model. And here on the bottom of our task model component HTML, we have actions, and here we have a delete with an image. And actually now on this div, we can simply add the click event and call here a new method which will be deleted task. Now let's create this delete task inside our component. Here we don't need anything, we just need this task ID and this board ID, and we already have them. This is why here we can simply write this task service Dot Delete Task and we're providing them inside. So here this point AT this task KD, so our clients successfully emitted this event to the back-end. Back-end updated our task and notified all our clients. But actually we must subscribe with the listen into different places. First of all, we want to do it here inside our task model. And secondly in our board, and actually inside the board, we simply need to call this method that we created Delete Task just so we updated a stream. But what I want to do here, I don't want directly inside delete task to go to our board page. Actually, it makes sense, but we're not sure that we removed successful at task. This is why I don't want to write code here. I really want to write listen, for example, inside our constructor. For this, we must inject here our socket service. This is where hear private circuit service and we're getting here our socket service. And now here in South constructor for example, on the bottom, we can just write this socket service lesson. Here, must provide that by getting back strain. And this is the task k d that we're removing. Now here we can use socket events in m dot and where subscribing to our tasks delete success. And here I want to ride by taken till we're on the safe side and then providing insight these unsubscribe. And after the pipe, we can use our subscribe and actually don't care about Tuskegee at all. We simply want to go too broad and already created such method. This is, this goes to what? We have, this method directly here inside this file, which actually means when we are getting success and our model is opened, this code will directly jump back to the board because we can show this deleted task anymore. And now I want to copy paste this code fully because we will write exactly the same inside of our board. And here as you remember, we're writing all these calls to our board service. This is where it makes a lot of sense to put this code here. And instead of this go to board, just try it here, this word service dot. And here we have our delete task where we're providing task ID. And in this case here we need this task AD that we're getting from the backend, and they actually were fully implemented this feature. Now let's check if it's working, but don't have any errors here and no errors in the backend. Now, let's jump to the browser. Here I have my first task, so let's remove it now, as you can see inside the actions, we have this delete and then hitting here delete and this task is completely gone with don't see it here inside the board, and we don't see it inside second board. And actually on success where successfully redirected to slash slash board ID, which actually means we successfully implemented this feature, Fool Live from start to the end. 47. Deployment: We successfully finished our project with creating Trello clone, and now we must talk about deployment. And typically deployment is not an easy task and a lot of people have questions. How should the player project, how we will manage it, what service we must use for it. And this is actually a problem. There are hundreds of different companies where you can pay money and they will deploy for your project. But first of all, you must compare all these companies understand how to deploy their project, learn their online tools, and so on. It doesn't make a lot of sense. Actually, all these tools at doing exactly the same. They are setting up your project on production on a real server. And actually the best variant to learn production and deployment is by deploying our project by ourselves on our own server. This is the bare bones of deployment. This is where it makes a lot of sense to learn how to do it. Also, it will be probably the most cheapest variant, how you can host your project. Yes, It won't be free because you must pay for the server, but you don't pay the company to manage a server and you don't pay for some graphical tools to applaud for you your project. This is where in this video, we must rent a server together, configuring it, and then deploy that our project. And actually, if you don't want to pay for the server, this is totally fine. You can simply leave your project as it is. And checking said the video, how I'm doing it and does a server company, I myself use hertz and this is quite cheap and reliable server provider. And actually you can choose any provider that you like. You just need access to virtual private server. But I like hatsune because it is reliable and not that expensive. As you can see here, we can click on the Cloud and check the prices here on the bottom. As you can see, there are lots of different packages and the minimum is here for years and $0.15, which is quite cheap for the month of 20 terabytes, tragic two gigabytes of RAM and CPU Processor. And actually, I am using this smallest server for two projects in production, but quite a lot of people are coming. And if you optimize your projects thriller, good, then you are totally fine with a small syrup. This is why in this video we will rent exactly the syrup. So now the first step is to register just inside her son a comb or any provider that you would like to. I already have here an account and after registration and confirmation of your email, you will see such page. Actually here, this service in your profile will be empty, but this is my own web server. Here I want to click at server because they just want for the sake of this course, create a new server. So the first one here is location, doesn't really matter. We can choose here Helsinki or whatever you prefer. Image wound is totally fine. We don't need to choose anything. Here is type standard, totally fine. And here, the smallest tier, which is for yours, $0.15. We don't need to change anything. We don't need volumes, Networks, firewalls, additional features, SSH key, and here just a name. We can name it here, l trailer, just like our project so we know what we're talking about. And as you can see here with didn't select our SSH key, which means we will get an e-mail with root user and the password, which is totally fine fast. I'm hitting here create and by now, and our server will be created. As you can see, my server is already the green and running. And actually in say, the email, I got my credentials where I have a root user and the password for our server. Now we must jump inside console and write SSH. And here will be first of all, our root user add. Then the IP address that we have here, we can just click on it and it will be copied and they need to paste it here. So we have here SSH, root at, and here the AP artist. I'm hitting Enter and we're getting the message. I assure you that you want to continue. Where right in here, yes. And hitting Enter, as you can see here, we're getting, first of all, the question regarding our password. So we need to take a password from the e-mail and paste here. And after this, we're getting lots of information regarding our server. And we start the process of changing the root password and actually to change the password with first of all, must provide a current password. This is why I'm pasting it again and hitting Enter. And now we must provide a new password for our root user. And we're doing it just so Kasner doesn't know our password. Here, I will provide just 123. And once again, 123. And as you can see, we're getting a message. You must choose a longer password. Let's make it 12345678. And once again, and actually you must understand that for the real production project, you should make some secure password and not like this, this is just for the testing. So if you have such output with root at L, Trello and hash here, it means that you've successfully, we look inside the observer. Here we can do something. Here I want to mention something important. We're not talking inside this course how to manage servers efficiently and securely. Which actually means I will show everything, the whole deployment with our root user. Typically in a real production project, you don't want to do everything with the root user. You want to create another user with limited permissions that can just deploy a project. So again, using route on production is bad, but if you do it as your pet project, this is totally fine. Our next step here is to bring our project inside the syrup. And actually there are lots of possibilities for this and I want to use the easiest here. What we can do, we could just push our project to GitHub or GitLab, whatever you prefer, and then clone this project inside our syrup. This is really efficient because you can do some changes to a project. You will for sure one to store and update your project inside Git repository, which actually means every single time when you want to update your project, you simply jump here inside your console and said Sarah, you just try to get pool to pool your project and then you restart it. This is it. I hope you already didn't know how to deploy your project to get lab or GitHub. But if you don't hear a short steps, I prefer for my own projects to use MATLAB, but it is just my personal preference. Here I already locked in inside GitHub and they clicked Create New Project. Now here I just need to click Create blank project. And here we can write some name. For example, we can name our project L trailer, and we don't need to change anything here. And actually by default in GitHub, we're getting private for free, and this is awesome for our needs. Now here inside our project URL, we must choose our namespace, and they will choose the namespace of my user. Now I just hit Create Project here and our project is created. And here we're getting some steps how we must bring this project to get lab. Now we must jump inside the console of our project and write good in need. This will initialize good for our project. I'm hitting here and then getting a message that my folder is already a Git repository because they already have my project inside good, typically you won't get such message, but just the message that we successfully initialized. Good inside this repository, Our second step here is to deploy all our files inside MATLAB. But the most important point here is that we must add to get ignore all node modules inside client node modules and insights Server Node modules. We don't need to upload all these libraries inside Git repository. This is why we must create dot gitignore file inside server. They have here node modules in this and also inside client. Here, as you can see, I also have dot gitignore, and here we have lots of stuff. It was created automatically by angular with don't need to change anything here. Here node modules signaled and this is ignored, which means actually we must change just server. And here is our get ignored. After this, we must jump in set console here, right? Git add dot and it will add all our files to the good. Now we need to create our first commit for this, we can try to git commit am. And here, for example, finished project, as you can see here, I'm getting a message, nothing to commit, but it should not be your case. In your case, you will get like hundreds of files here, which were already created in this project. Our last step here is you can see is add this line, git remote, add origin HTTPS, and then the full path, I will paste it now here. And with that, we successfully binded get lip to this repository. And our last step here will be this git push minus uf origin main. And actually as you can see here, it is written in main. But for me by default I have a branch master, which is totally fine. This is why I want to rename main to master. It is good. Push minus uf origin, master them hidden here, Enter, as you can see here, I must provide first of all, a username of my GitHub user. And secondly, the password is, you can see here I'm getting a message is to deeply basic access denied, which actually means it didn't happen. But here we're must create a personal access token with redeposited right repository inside GitLab. If you're using GitHub for example, maybe it worked for you. If not here we can jump to this link slash profile personal access tokens. As you can see, I opened it here and here we just need to create an access token so we can push to GitHub. And here for example, it can create trello talking name. And here we must select scopes. For us. We must create right repository and read repository. This is the most important. I'm hitting here, create access token, and here we're getting on the top our new access token. And fortunately now we must change our remote again because of this access token for this table, right? Good remote Ashram or region, which will remove this origin that we created here on the top with this line, and this will be removed. Now I want to copy paste this line and this is how we're doing it with access token inside GitHub. As you can see here when writing git remote add origin HTTPS. Here we must first of all provide access token name. This is why here we created l trailer as our token. I will write this here, ultra law, and now here we have colon and our access token. I will copy paste it also from our page where we generated it. And after this we have exactly the same what we have here on the top. For me it is https github com slash my nickname slash L dot. Good. This is where here I will write exactly the same. And then my repository, I'll Trello, lets check this out. We're trying to push again to our repository with git push origin master, just like we did previously. We're hitting here. And as you can see, when not questioned for our username and password, because now we're pushing with our access token. And as you can see, we don't have an error. Here. We're getting that everything is resolved and now we're successful at boost to the master branch inside origin. As you can see now here inside of our project we have a master branch, and here are all our changes. We have here two folders, client and server. And here inside we can see the whole project that we build. And now we can applaud our code to our server. This is why here I want to jump back inside our server that we just created. And as you can see, I am inside the syrup. So first of all, here I want to create a new directory which is called projects. Now, I want to jump inside this directory project and clone this project here. And actually here we can try and use with same access token that we just used. We can just write inside console, get chmod minus version inside the local console, not inside the server. And here is our remote with this token URL. And actually we can just copy paste this URL and use it here inside syrup here I just want to write git clone and then this URL I'm hitting here. And as you can see, we don't have any permission problems. And we successfully cloned our project here inside projects. And here now I can write Ls. And as you can see, we have the folder L trailer, which actually means we successful abroad our project to our server. Now to proceed, we must update all packages inside our server. And for this, we can simply write apt-get update and hit Enter. As you can see, all our packages where updated and now I want to install, first of all in jeans and secondly MongoDB. So what is in jinx? This is our future web server which we will use for our project. This is where here we can write EPT in style and jinx. Here we're must hit yes, to install this package. As you can see, our package was successfully installed. Let's check if it's working here, we can simply write service and jinx status. And as you can see, I'm hitting Enter and we're getting quite a lot of information. First of all, what is in Jinx and here, active running, which actually means it was successfully installed and it is running now our next step is to install our database, and it was MongoDB. This is way here, apt install Mongo DB and we're must confirm it with yes. Now let's check the state of our MongoDB for this weekend, right, service then Mongo DB status. And as you can see, it is also active and running, which means everything is fine. The next tool that I want to install is called n. And actually we will use it to manage our node version because actually it might happen that we want to update node and it is much easier to do it by using this tool, especially if you have several projects and you need to switch between different node version. This is where I will paste this line inside console. So it is curl minus l and this URL, it is Gita, your slash n in style bash. I'm hitting Enter and we're getting an error. This is why what we must do. We must first of all execute apt install. And here is built essential. I'm hitting Enter and we must confirm it. Now as you can see, it is installed so we can try and install. And again, I'm hitting Enter and put. Don't have any errors. Here. We can simply write yes and proceed to install it. As you can see here, by default, n installed for me, know, 16151. And actually this is exactly the same node that they have locally. And they always highly recommend you to have the same node version on your production server and in local environment. In this case, you will avoid hassles and magic box. And the last two that we want to install is called PM2.5. This is special manager to restart our node processes and we will use it to start our beckoned. This is where here we can write npm install minus g, which means globally VM2. And as you can see here, we're getting an error command npm not found, and the same for command node not found. If I'm right in here, node minus version. And actually after installation of n, both domestically and getting Node and npm. But we must restart our terminal. So we must disconnect from the server and connect again in order to bring known chance inside path. This is where we can simply write exit and then again, use SSH root and our IP address. Keaton here Enter and we must provide our new password. And as you can see here, I'm inside and now I can write node minus fashion and then getting the version of the node and the same with NPM minus version, which actually means now we can install TM2 again with npm install globally VM2. Now we don't have an error and our PM two is being installed. Now, we must install all our packages for the client and for the server. And for this I must jump again inside projects folder. And here as you can see, I have our ultra lab project. As you can see here, I am inside the trailer and they have client and server. First of all, I want to jump and say server. And here we have a lot of files, so we can simply write and payments style and it will install all the dependencies for our server. As you can see, everything is installed now we must jump inside our client. So I'm writing CD client and after this npm install again, and we will install all our front-end packages for Angular. So all our packages where successfully installed and now we must create a configuration for nginx for our project. And for this we can write cd slash UTC and jinx Cohen's d. And here inside we must create a new file. And for this we can write Tij and then L trailer dot com.com. And actually here to open and edit file, we must use some editor from the console. And I will write here nano and then the name of our file, which is the old trailer, calm, calm. I'm hitting here and this is how this editor is looking like. So here we can simply type something and then later safe. And actually here I want to already paste the conflict often jinx the type prepared previously, and this is how it looks like. So here we have a server blog. Now inside we have listened AT, which is a default AT part. And here is where our root of frontend is lying. Here is slash route slash projects where already created it. Here the folder is strong. It is actually Ultra low folder that we just created. Then slash client slash and slash app. And actually we must build also later our client after installing packages. So our type script will be converted to JavaScript, and it will be here inside this folder, inside slash app. This is why now it is totally fine. Here we're resolving our index.HTML and here the server name, the surname is really important because actually this is our domain. This is L.com and www L Trello.com. And actually we don't have a domain at all. And this is totally fine because actually we can inside our local machine, inside host file, just write an APR address of the server. In this case, we don't need to bother with strategy soon as real domain, and it will work exactly like with the domain. After this we have location. So we're trying always to load our index.HTML. And here we have location slash API. And actually this is important because here we're saying, okay, When we're champion in L Trello.com slash api, then we must proxy our request to this web server and this web server we will be using inside our backend. This is local host for 1001 slash API. After this, we have exactly the same but for socket IO requests. And here we have http localhost 4,001, and here we have some headers. And actually this is the whole config that we need for In Jinx. So now the question is how we can save this file? And for this, first of all, we want to click Control O. And here on the bottom we see filename to write ys l Trello com conf, where just hitting enter. And this is totally fine. It was saved. Now here I want to click Control X, and now we're out, we're back inside our console. And now if you need to check if everything was saved successfully, you can write cat and then I'll Trello, I'm hitting Enter and we're getting inside the console this nice output with the content of our file, but it is not all were also must change a user inside the genes configuration. This is way here. I want to go out from this folder in here I want to write again nano, but in our case now it will be in jinx.com. And actually this is the default configuration, often Jinx. And here we want to change just a single line. Here on the top we have a user data and we want to change it to user route with which we're locked in here, and we need to save this file again. So Control O Enter, then Control X. Now we must restart In Jinx to apply the configuration that we did. This is why we can write service and jinx restart. I'm hitting Enter and we don't have any errors. And now we should not forget to build our front. And this is why we must jump back inside slash route slash projects. And here is our L trailer and Client. And actually we're inside client. And to build our Angular project, we can simply run npm, run build. And as you can see here, we're calling in GI Bill, which is the command of Angular, and it will build for us the whole project inside this folder, as you can see here, after building, I'm getting quite a lot of errors inside the console. And actually the main problem is that it is a production build and the payroll does not exist on the type production Boolean, which actually means we didn't update our environments, Config inside our project. This is where it is real and nice that we have now good, so we can quickly make adjustments. Here I want to jump back inside our project and we're interested in our client part source environments. Here we have two files. Environment, yes. And on the right, I will open environment protest. Here. As you can see on the left, we provided API URL and sockets URL, but we didn't provide them on the right. And actually I will just copy them from the left to the right here. Now, we have this properties inside our configuration. After this wound must deploy these changes to the good for disabled jump in the local project, right? Git add dot, it will add just all files locally and after this commit. So git commit minus m and for example, updated environment. I'm hitting here, enter our commuted them. After this we can simply write git push origin master and hit Enter. And our changes are already inside GitHub or GitLab. After this, we can jump back inside our server, which was entered. And here I want to go out of the client. And here I am inside our little trailer folder. Now I just tried Git pool and we're bringing our changes as you can see here, environment protease inside our server. And after this, we must try again to run build, and it is npm run build, but we should not forget, we must jump inside client, as you can see, no such file or directory package, Jason, because I'm not inside client. So the client and here npm run build. Now as you can see, we don't have any errors and we're getting a message that everything was completed. And actually here we must check what we have inside our dist folder. So ls decreased. And as you can see here, we have all trailer and inside all Trello, we have all these files. First of all, our index.HTML, and then our assets, mangers and so on. But actually it means that we have a small problem inside our config inside and jinx because there was rolled our root folder, this slash app. And in our case here we have a decreased slash, I'll Trello, which actually means we must update it now. So we must try Nano slash, ETC. And jinx Cohen's d. And here we have our L Trello Comic-Con. I'm hitting Enter and again opened our config. And here inside route we must try this slash l Trello. Now I'm hitting Control O, Enter Control leaks and we must restart and jinx, so service and jinx restart. So now our frontend is completely ready and we simply need to run our backend and we don't need to start somehow our fronted because in jinx will do it fast. But for begun, it won't because actually inside our front-end with just have a static files like HTML, JavaScript, and CSS. But inside our backend we have our observable. This is why I want to jump inside our back-end. So here CD server, and here we need to start our server with PM2.5. But actually here we also have a problem inside our server. We have TypeScript with don't have JavaScript files and actually womb must convert all our TypeScript to JavaScript before we will start to run it without PM2.5. And actually for this one must create in your command. This is why we must jump back inside our project and go inside the server package, Jason. And here we have a script for start, but we don't have a script for Build. This is why here we can simply write build and here the script will be TAC. So what is TAC? Actually it is a TypeScript and it will simply transpire the whole code that we have inside this project with this ts config. As you can see here is output, it is dist folder. This is completely fine fast. But after we did this changes. We must jump in set console and do exactly the same stuff again, first of all, get head, then git commit, and then git push. So with this commands, we're bringing our changes inside get wrapper. Now we're jumping back instead of a survey. Here we're going out and I'm pulling my project again. So we're good to go now, we can jump back and said, oh, server folder. And here we can try to build our back-end. This is where here I can simply write npm run build, and it will transpire my type script to my JavaScript. As you can see here, it is done. Now we can just try it a less dist and check what we have. And as you can see here, we see all our files that were created, but with js extension, which actually means this is totally fine and we're must start dist slash server.js and it will start our project. We want to use PM2.5. This, this is where we can simply run PM to space, start space. Here will be decreased slash search. Yes, I'm hitting Enter and we're getting lots of output. As you can see here, this is the whole output of PM two. It doesn't matter, but here on the bottom we see spawning PM to demon. It is successfully demonized and we're starting out with this surges in 4k mode, and it is done and here is our server. And actually why we're using here P M2, not just note process we could write here node and then for example, the surge, yes, this is totally fine. But pm tubule, first of all, risks start for us, this web server if it is broken for some reason. Secondly, PM two is better suited for the production applications. So what we did here, first of all, we successfully built our client and secondly, we started our backend. And the last step that we want to do is open a browser. But we can simply open a browser because we must point our domain, L Trello.com, which does not exist. We didn't buy it from our local machine to our server. And actually here I must jump inside the console locally. And open host file, for example, inside Linux and macOS, it is line in slash, ETC slash hosts. So here how it looks like for me, if you're on Windows, here is your path, it is Disk C, Windows system, so the two drivers, ETC, host and you're opening this file and this is exactly like my file here. And as you can see here, I already tested this project. This is why I have this line. So here I have a domain, L Trello.com. This is what we're registered, but this is the old API address. I don't need it. I must jump back inside my panel of head SNA and copy this domain and just paste it here, which actually means on our local machine when we're jumping inside the ultra low-dose come when not looking in DNS lookup table, we're just pointing to our IP address of the server. So now the moment of truth, Let's open our project. I am writing inside browser L Trello.com. And this, you can see this is our project. It is working. And actually I want to open here console so we can check if we have some errors. And actually here we have a narrow at local host for 1001 slushy ice lift user from origin, I'll Trello and actually as you can see, network, this is our request to API. This is http localhost 4,001 slushy pairs plus user. And obviously this is strong. This is not what we need to use. This is why we must jump back inside our project and go inside client locally and change it. So here is our client's source, environment and environment protest. Here. Obviously this local host does not exist. What we have now here is a CTP L Trello.com slash API and the same here, http L Trello.com. And then we don't need to provide here a port. And now we must commit these changes again. This is why git add git commit and then git push. Now we want to jump to our server, go out and say Trello folder and right, get ***. But after this, we must build our client again because we changed our client. And in order to do this, we can write c, d client. And now again, npm run build and it will simply generate fast static files for the frontend, our project is successfully built. I'm reloading the page here and we don't have an error. We have here for 01, for HTTP L trailer com slash APIs slash user. This is totally fine. We're not locked in. Now let's try to register user. So here I am writing f2 at gmail.com. Here is our username and password 123 hidden here register. And actually it worked. And this is important to check because it means that here we successfully configured MongoDB because this post request is go into the API and this is our response. And here we're getting back the a d of saved user and here the token. So our backend and DPI also works. Now here we have a board and here I will create my first board. Let's hit Enter and we're getting our board, we can open it. And here we're inside the board. Now let's check if our socket IO is working for this. I want to duplicate that tap here and try to create a list. So here for example, first list, I'm hitting here at least, and we're getting the list. And also on the next step, we're getting exactly the same list. Now here on the second term, we can create a new card. For example, first card, I'm hitting here, add and we're getting this card on both pages. Now here we can open our model and it is working as intended, which actually means we successfully deployed our project to production. It was not easy, but this is a bare bones of any project you can deploy. It doesn't matter what angular view react. Any client that you want, plain JavaScript or any backend, it will always be really similar. 48. Homework: My congratulations, you've successfully finished this course, and I really think that you are awesome and you learned quite a lot of stuff. Now you for sure learned how to create your full-stack project with Node.JS on the backend and express as a service. Also, you can for sure easily use socket IO because we used it quite a lot on the client. You again, lots of experience regarding n cooler TypeScript, great and interfaces and creating a good reactive state. But obviously it is not the end. As a good teacher, I must give you homework because actually if you want to improve your skills as a developer, you must learn and create your own projects. And here you have two possibilities. You can create your own project from scratch. This is what I really recommend, or you can implement features in this project. And actually there are benefits in both possibilities. If you continue to implement this project, you already have a really good architecture and it will be much easier for you. And actually the amount of feature that you can implement in this project is really tremendous. First of all, you can implement here different roles. For example, like admin users who can create, for example, teams, which actually means you start to organize people inside Teams, just like in the real Trello also, for example, on the front end, you can implement drag and drop for tasks inside the board. The easiest variant for you would be to open the official trailer application and just look on their set of features and just implement something which is interesting for you. And actually, this is super important and it is related to your own project. If you plan to do your own project, I highly recommend you to implement something that you're really interested in. Because if your project is not interesting for you, you won't do it long period of time. And if you're looking for ideas for your own projects, disrupt plenty of them. For example, you can implement an e-commerce shock, or maybe a bookstore, a clone of netflix, or a financial application to manage your expenses. I really hope that you liked this course and you learned a lot and we'll see you in my next course.