What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
Integrating Angular with Node.js RESTful Services
by Dan Wahlin
Learn how to build an Angular and Node.js application that can perform create, read, update and delete (CRUD) operations. Topics covered include building RESTful services with Node.js and Express, manipulating data in MongoDB and consuming services.
Resume CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Course Overview
Course Overview
Welcome to the Integrating Angular with Node.js RESTful Services course. My name's Dan Wahlin, and I'm a software developer and trainer, specializing in web technologies. I work a lot with Angular and different server side technologies, so I'm really excited to introduce this course. Now, throughout the course, you'll see firsthand how Angular and Node.js can be used to build an application that allows users to view customer data, page through it, and then perform, insert, update, and delete operations. This includes learning how to move data from a database all the way down to an Angular client, using RESTful services. As data's modified in the client, you're also going to learn different techniques for sending that data to the service, so it can be stored in the database. On the server side, you'll learn about Node.js and Express and how they can be used to define RESTful endpoints. You'll also examine how Angular services and the HTTP client can be used to make async calls to the RESTful service and retrieve data. You'll see how components can subscribe to observables and render data in the user interface, using child components. This includes discussing input and output properties and how they can be used to pass data in and out of components. The course will also discuss different form techniques, including template-driven forms and reactive forms, and highlight the differences between them. So let's get started, and jump right in.
Course Introduction
Course Introduction
Let's start things off by talking about the overall goals of this course, some of the key technologies we'll learn about, and the sample application that we're going to walk through. So the first thing I'll do is walk you through the prereqs that you need to know so you can maximize the learning process and get through this course and feel like you got something out of it as well. We'll talk about the overall learning goals and what you can expect right up front, and then we're going to clarify some of the key, server-side technologies and concepts that we'll be covering as well as the client-side technologies and concepts. So that'll include things like RESTful services, what that means, observables in Angular and more. From there we'll talk about how to get the sample application that we're going to be building up and running locally on your machine, and I'm also going to show you how you can get it up and running using something called Docker. So let's jump right in.
Pre-requisites to Maximize Learning
Let's take a quick look at the prerequisite knowledge you need to have to maximize your learning as you watch this course. Throughout the course we're going to be using JavaScript and TypeScript a lot, so you should be very comfortable working with those two languages. On the server-side, we'll work mainly with JavaScript; but when we get to the Angular code, we're going to be using TypeScript. You'll also want to be comfortable with Angular Fundamentals, so knowing about components, services, how those work with providers and modules will be very helpful. So if you're new to Angular or some of the languages, definitely take the time to watch some of the other introductory level courses that are on Pluralsight.com. Finally, you'll also want to have at least a basic knowledge of how Node.js works since we're going to be using that to create a RESTful service and integrate with the database; and there's also courses on Pluralsight.com that will cover that topic as well if you need a little bit of material there to get you up to speed. If you feel comfortable with these three different areas, then let's move ahead and jump into more specifics about the learning goals in this course.
Learning Goals
Before jumping into a book or a video course, I always like to know more about what I'm going to learn. So let's take a quick look at the overall learning goals I have for you as you go through this course. So first off, we're going to be focusing on two main areas and how we can integrate these together. We're going to talk about client-side technologies, and then we'll talk about server-side technologies. So we'll be talking about Angular on the client-side and then integrating that with Node.js, of course, on the server-side and building a RESTful service that integrates with a database, which will be MongoDB in this particular application we'll be discussing. So the overall server-side learning goals include understanding how Node.js and Express can be used to create a RESTful service. We're also going to talk about something I call convention-based routes. Now this is not a normal way to build express routes; it's something custom that I like to do that I think really cleans up the amount of code you write. So I'll show you a little bit of customization you can do. We'll also talk about how you can expose RESTful endpoints using Express and how we can write some reusable code and build some library-type code that can be used to integrate with one or more different databases. In this particular case, we'll be using MongoDB. Now on the client-side, we're going to be looking at Angular and how we can use the HTTP client to integrate with the Node.js RESTful service. Now technically we could call any type of RESTful service; but for the sample application we'll be running, it'll be based on Node.js as mentioned. So we'll look at the role of RxJS and observables and see how observables play a big role in the asynchronous calls we're going to make to a RESTful service. We're going to use the HTTP client to call different functions that can be used to interact with the RESTful service. We're going to be making Ajax calls or technically XHR, XML HTTP requests, to the server. We'll also see how we can perform complete CRUD operations: create, read, update, delete; so that we can insert, update, and delete data ultimately in the target database. And then finally, we'll also learn how we can page data in the application and how the server-side is going to play a role in that and how the client-side can then render that page data. So that's a quick look at the overall learning goals. From here, let's jump into some of the key technologies and the concepts you're going to need to know on the server-side and the client-side.
Server-side Technologies and Concepts
In this section we're going to take a quick look at the key server-side technologies and concepts that you need to know. That way when we jump into the code a little bit later in the course, you'll already have some clarity on the concepts that we'll be talking about there. So we're going to be using Node.js and MongoDB on the server-side; and we'll be building some RESTful services, of course, in Node.js. We'll also be building some modules that are reusable for MongoDB that could be used to perform CRUD operations: create, read, update, and delete against MongoDB. Now when it comes to the RESTful services, we're going to be embracing, very heavily, HTTP concepts in using those and that will be used to ultimately build our RESTful services. Now if you're new to the concept of REST, let's talk about what that is, at least from a high level. It stands for Representational State Transfer; and I know for me personally, the first time I heard it, I went, okay, that doesn't tell me a lot. Well, really what it's all about is we want to transfer state data between one type of client up to the server in our particular case. That means we want to go from Angular and transfer some data up to Node, or we want to request from Node some data that we want to get back into Angular. Now REST itself is a pretty high level architectural concept or style that's used to build distributed systems. Now we're going to use Angular 2 in the browser throughout this course, but technically I could make this work on mobile devices. It could be something for iOS or Android or whatever it may be, and that's really the importance and why RESTful services are so popular these days because really any type of client can integrate with them as long as they support HTTP concepts. So we're going to expose different resources and really resources are the state or the data that the clients want to get to or send up to the RESTful service, and we're going to use a URI or URL, so a uniform resource identifier, or just a standard URL that we're all used to, a link, to identify these resources; and that's what really makes RESTful services pretty neat is because as long as you use standard HTTP concepts, which we'll be doing, anything out there that understands HTTP can interact with these types of services. It can be something as simple as a raspberry pie all the way up to a fully functional, single-page application that's built in Angular. So that means we'll be using HTTP, URIs and also MIME types. MIME types are the underlying string that's passed back and forth to say what is the client sending up to the server and what is the server sending back. It could be HTML, could be XML or, in our case, it's mainly going to be JSON, JavaScript object notation type of data. Now from a really high level, let's look at what a RESTful type of system looks like. Now we've all called in to some type of a phone number service; and some of those call-ins, you go through what feels like 10,000 different options to finally get to talk to someone. With a RESTful service, we expose the resource we want to get to directly. That means we can call 1-800-gold, for instance, if we're a gold customer service type level and want to talk directly to the gold desk. If we were on the silver side of things, this would relate to, you know, hotel type of systems or airlines where you have different statuses. Maybe we want to do 1-800-silver to expose the direct silver line and allow us to get support for that type of thing. And then, finally, any customers that really don't use the service very much, they just call the standard number; and they could get directly to the standard resource. Now what does this have to do with RESTful services, you might ask? We can see that we're exposing a resource by giving it something unique, a unique URI. Now in this case, it's more of a unique phone number; but in just a moment I'll translate this over to URIs, and we'll see how that works. So now we can simply call 1-800-gold, 1-800-silver, 1-800-standard and get direct to that resource. We're not having to get routed through all kinds of different options that we might have to select from. Now let's convert this over then to more of a RESTful service type of concept in URIs. So instead of a phone number, we might go to /orders/gold and that gets us to some gold type of resource, or /orders/silver to get to the silver one, or /orders/standard to get to the standard type of resource. Now the resource in this case is going to be the data that we're either sending up to the server or getting back, and that's where the RESTful service becomes a very novel type of way actually to expose data. That's why a lot of the different, popular social media sites out there use RESTful services. Because, again, the clients in this case, the gold, silver and regular customers, they could be anything. They could be a phone; they could be a desktop browser. They could be a raspberry pie or something in the IoT type of world. As long as we're able to embrace HTTP in this URI concept, we can get to a specific resource and share that data. Now the key technology players that we're going to be discussing throughout the course include Angular, Node.js and MongoDB. So really what we're after is we want to make a RESTful service that's capable of integrating with MongoDB and returning data to Angular. Angular may then update that data and then send that back to the RESTful service so that we can put it back in the database, so it kind of looks like this. We might do a GET request and that would allow the data to flow all the way down to Angular. It may then change that data in some way, shape or form. In this case, we just changed the name; and then that data's going to flow back up to the RESTful service built in Node and Express and then that will take care of calling in some library-type code that can do, for instance, an update in the MongoDB and that's really what we're after here as we build the application and work with the server-side code.
Client-side Technologies and Concepts
On the client-side of the application, we're going to be using several different technologies and concepts as well that I want to go over from a high level so that, again, once we jump into the code later, you'll already have that foundation in place to understand what we're doing. So first off, we're going to be using Angular; and then we're also going to be using another library that Angular relies on quite heavily called RxJS, or Reactive Extensions for JavaScript. Now by using Angular functionality, we're going to be able to make XHR/HTTP calls up to the Node.js, Express, RESTful service; and then, as you saw, that'll integrate with MongoDB to allow us to get data and do things like inserts and updates and deletes of data. Now, as the data is going back and forth and we're making these asynchronous calls from Angular 2 though, we're also going to be using something that's part of RxJS called observables. So you're going to learn about how to import RxJS functionality, what observables are here and what they're all about. So let's first talk about what is RxJS. Well RxJS, or Reactive Extensions for JavaScript, you'll see a link down here on the bottom left, is really a library. So it's just some JavaScript code that you can import into your Angular apps and then use it to build these asynchronous, event-based type of programs. Now because we're going to be making Ajax calls, or what a lot of people would just call HTTP calls, up to the RESTful service, we're of course going to have a lot of asynchronous type of code going on; and RxJS provides some really, really interesting and powerful functionality for working with these asynchronous operations. Now, we're going to be talking about something called observables and observable sequences. This is something that RxJS makes very easy to work with, and I'll talk more about that in just a moment; but the bottom line is, this is what Angular uses out of the box. And so as we're making the calls up to the RESTful service or getting data back, we're going to need to work with these observable sequences of data. Now let's talk more about what I mean then by observable sequences and asynchronous operations and even other options you might've already heard of or used in the past. The number one asynchronous operation that most JavaScript programmers know about is Promises. Now you can use Promises in Angular; but it's not the default option, as you're going to see. In a nutshell, a promise is a way to work with an asynchronous operation that hasn't completed, but you know it's going to come back to you with some data sometime in the future; and so we call this async/deferred operations. The browser makes a call up to the RESTful service, but we don't want to lock up the browser, of course; so we do that call behind the scenes, and then eventually it comes back and some type of callback function is called and we have to write the code to hookup to that callback function. And this is what, as I mentioned, most JavaScript programs have done with asynchronous operations in jQuery, Angular 1, and many other libraries and frameworks that are out there actually. Now an observable is actually a little bit different. If you've ever heard of the publish subscribe type of model or something called the observer pattern, this is the process of having an object that we can subscribe to; and this object is going to return different data over time and as that data changes, we subscribe to it and we instantly know, oh, okay, new data just came in. So, really, this is all about returning multiple values over time. Now the difference between this and promises I'll make a little more clear as we move along here; but in a nutshell, a promise allows one piece of data to come back. An observable could have multiple pieces of data coming back over time, and so this is more of an event-based type of technique that we can work with. Now let's look at the differences between these two asynchronous options because I know for me, personally, I was much more comfortable with promises than I was with observables and RxJS concepts. So let's start with promises. Promises have been around for quite a while now and, as mentioned, they allow us to handle asynchronous operations in the browser. So let's say we have an Angular component and it calls up to an Angular service, and that service may make an HTTP call up to a Node.js RESTful service. So, in order for that to work, we would have to call up from Angular the component; and then we don't know when that data's going to come back, so we would be returned a promise. And then we would hook this promise into a callback function. Now eventually the server returns data to the Angular service, and then that data would flow down into the Angular component; and then we're done. So a promise only returns one piece of data over time; but it's a great way to work with asynchronous calls, and that's what most of us have used over the years. Now observables are quite a bit different, so let's take a look at them. Let's say again we have an Angular component and an Angular service, but the service function that we're hooking up to returns something called an observable instead of a promise. So what we can do is we can subscribe to some type of object that could be returning data over time. So, for example, we might have a random number generator in the Angular service that just, every five seconds or something, returns random data back to the angular component. Now to make this possible, we don't have to hook a promise up to a callback function every time we expect a new random piece of data to come back. In this case, we have maybe a timer in the Angular service; so, as mentioned, all we do is subscribe to the observable that's going to be returned from an Angular service function and then let's say that random data fires every five seconds. Well, we can get this data over time dumped into our Angular component callback function. Now this is like hooking up to a pipe that you really don't know when the pipe's going to stop dumping data out to you. Maybe you have just a basket at the bottom of the pipe; and, in this case, the basket would be the Angular component call back function, and then the pipe would be the observable that's returned from the Angular service. By subscribing to this, we get data over time. Now let me throw one more feature in that we could use this for. With HTTP, you only get back one piece of data. It's a request, and then you get the response. So you might say, why not just use a promise there? And the answer is, you could; but the default in Angular is observables, mainly for consistency because there's a lot of other areas in Angular that use this as well. Routing, for instance, uses observables. So what we can do is hook up to the function that returns the observable and get back that one HTTP value, but let's say that the server was actually a web socket server. Now if you're not familiar with that, a web socket server can return data or push it from the server down to the browser over time. So let's say we have stock quotes, for instance, that over time we want to subscribe to. The server then, as the data changes on the server-side, pushes those down to the Angular service. The observable gets those changes, the pipe; and then that data can start flowing in over time from the service. And with an observable, we only have to subscribe to that once; and we just continue to get this stream of data over time. Whereas with a promise, we'd get one piece of data then have to re-hookup; and it would actually be a lot more challenging to do that. So here's a quick comparison to review the two concepts. Promises return a single value, and you can't cancel it. Once you hook up to a promise, you can either get the data back or you can get an error back. Now you could choose to ignore the data, but you can't really cancel a promise, per se. Now one of the nice things about them, they are natively supported in browsers. So if you have a modern browser, you can use promises directly; but even older browsers can work well with promises because there's libraries like Q that could be used. Now observables, on the other hand, can return a stream of data, multiple values over time. So a random number generator, a web socket scenario or even just one piece of data that comes with an HTTP call to the server. Now what's nice about these is once you subscribe, any time you want to stop getting a stream of data, you can just unhook it. You can cancel it, unsubscribe; and that's a nice feature. So maybe you are hooked up to a web socket scenario where the server is pushing, pushing, pushing data; and maybe after 10 minutes, the client has all they need, so you say I'm done. I want to unhook. Well, that's like detaching from the pipe line. Now the server might push it to some other clients, but your client then could stop receiving that data. Now this means that when you work with observables because we're getting an array of data over time, you can work with standard array functions that you might've used before, like map or filter or reduce; and we'll see a few of these as we move along later in the code. _Now observables are not built in to the browser though. This is something that we need another library, a little helper that can help us out; and that's why Angular 2 doesn't have this built in. It actually relies on the RxJS library. So if you're new to that, we're going to talk about later once we get to the code how we can import RxJS functionality, work with operators and more; so that we can subscribe to these observables and then use them to communicate ultimately with our service.
Running the Application
Now that you've seen the technologies and concepts that we're going to be learning about throughout the course, let's jump into the sample application that's going to be using these technologies and putting all the concepts together. So what I'm going to demonstrate is how we can get the app up and running. Now before I do that, let's talk about the software requirements and the different things you're going to need to install if you want to get the app running locally. So first off, you can use any editor you'd like. I'm going to be a using a free one that works on Windows, Mac and Linux called VS Code. You can get it from code.visualstudio.com, but technically you can use whatever editor you'd like to get through the course. It doesn't really matter, but this is what I'll be using and what you'll be seeing throughout the videos. Now regardless if you're going to be running the app locally or through another option I'll be talking about later, called Docker; you will need to install Node.js 65 or higher on your machine, and you can get this from nodejs.org. So if you already have it and you have the appropriate version, great. If not, go ahead and go to this site; and if you need any help with the installation, they have some walk-throughs there. Now the reason we need a 65 or higher edition of this is I'm going to be using some ES2015 features, some more modern JavaScript features, in some of the node code that we're going to be running. Now the final thing we'll need is MongoDB. Now this also can run, like node and VS Code, on all the operating systems: Mac, Windows or Linux anyway; and the installation for this definitely depends on your operating system. So if you head to the doc link that I have here for you, you'll see some tutorials that'll walk you through step-by-step getting this up and running. Now once you have that up and running, you can run the sample app. So let's take a look at how we can get started doing that. So if you open the application itself, you'll see the project code. I'm going to be talking about the folder structure and the various files a little bit later in the course. For now, we're just going to open the read me mark down file and walk through the running the application locally steps; and you'll see the first step shows how we can use node and mongo and has the same links for you, but the next one is we need to run a mongod command from the command line. So I'm going to right-click at the bottom here in VS Code and say open in terminal. Now if you're on Windows machine, you'll see open in a command prompt type of option. So I'm going to go ahead and open that, and this takes me to the root of the project; and now I'm going to try to run this mongod command. Now I have this command set up so it's in my environment path. So I can type it from anywhere, any command terminal window, and it'll run. So if you run this and get an error like the program's not found or something, it probably means it's not in your environment path. So I'd recommend go back to the MongoDB docs if you need any help there, but I'm going to go ahead and start mine up. You'll see it's pretty quick and easy, so now it's up and running. So that's kind of the first step there. Now next thing we're going to do. We're going to install some global Node.js dependencies. Nodemon, the first one here, is going to be a Node.js module that'll monitor any changes to code; and when it detects that a file changes, it'll automatically stop and restart the node process. So it's really, really nice during development so you don't have to keep starting and stopping your command window. Gulp is a JavaScript task manager. We're going to be using that to copy some Angular scripts into a static file folder called Public that we'll also talk about later. So I'm going to go ahead and run this command to get these installed, and I have it set up so I can do multiple terminal windows through a kind of tabbed interface. If you don't have that, just open up a different command prompt terminal window and you'll be good to go. We'll go ahead and run this. As you run these different install-type commands, you're going to see some warnings and maybe some deprecated notices; you can ignore those. As long as you get this kind of tree view structure at the end, you should be good to go. All right, so now that we have that; let's move on to the next step, and we need to install the actual application dependencies. Now these are all listed in a package.json file; and so all we're going to do is fire up npm install, or you can do npmi. And this will take a little bit of time to install; so through the magic of video, I'll wait 'til it finishes and meet you on the other side. All right, so it looks like that's all installed and we're ready to go there; so we're really close to getting the app up and running now. So now we need to copy some Angular scripts that are here in the node modules folder that was just installed into our public static files folder and have a lib folder we're going to copy those to. So we're going to run this Gulp command to automate that task, and this will run really fast and copy those in. All right, we're good to go there. So the last thing we're going to run, if you go back to the read me, is npm start; and this is going to actually start up the Node.js server, start up the RESTful service, and allow Angular scripts and the web pages and things to be served up. So let's go ahead and start that. Now the first time you run it, you'll see some data's going to be inserted. Looks like nodemon caught some changes and restarted the server for us, and then it says we should go to this localhost:3000, so we'll go ahead and do that. So let me open this up, run off here, and there we go. Now the application that we're going to be discussing throughout the course is all about integrating Angular with a Node.js Express RESTful service; and so I'll be building out those different pieces with you as we go through the course to do GET requests and put and post and delete, and we'll do paging and things like that. But before we dive into those details, let's just look at what the app does. First off, it displays customers by doing a GET request to the RESTful service. You can also sort. This is a local sort. We can also filter. So I could go find Bell, for instance; and then we can also edit the customers. So we can come in and select Michelle Avery. Maybe I'll change that to a two on first and last name, update, and that just pushed that data up to the service, which then updated MongoDB. Then, of course, we can go back, take that out; and you can see everything works as you'd expect. And we can also add a new customer. So I can come on in, and we'll do a real sophisticated one here with my favorite test data. All right, now you won't see that customer here because you'll notice there's also paging built into the app, which we'll also be talking about. So I'm going to go to the last page. Everything's sorted by default by last name to start off; and there we go, there's our test. So let's click on it, and then the last thing was we can also delete requests. So I'll say delete and yes. Now if we go back to the last page, you'll see it's gone. So that's the sample application that we're going to be building throughout the course to show you how we can integrate Angular, RxJS, observables, services and more with Node.js, Express and RESTful services that are capable of integrating and doing CRUD operations with MongoDB.
Running the Application with Docker
If you'd like to run the application using Docker containers, I have that available for you as well in the sample kit. So I'm going to do a real quick run through of how to do that, the software installation requirements, and those type of things; and I want to emphasize this is really intended for people who are already very comfortable with Docker. So if you're not, you can certainly skip this section and just go with the local install that's already been covered. But if you are interested in getting a Docker container up and running for Node.js and MongoDB, I'll walk you through those steps here and some of the basics. Now as far as the software installation requirements, you'll still need a local editor, of course. So I'll be using VS Code for that, and you still are going to need Node.js because we're going to be using that for some of the Dev-type tools to run npm install, Gulp, and things like that. Now, MongoDB and the actual node server, the RESTful service; those are both going to run in Docker containers though. So those won't actually be running on your local system, they'll be running in Docker containers. So, of course, to do that you'll have to install Docker. Now you can do Docker for Mac. There's Docker for Windows if you have Windows 10 Professional or higher. Or if you don't, you could look at Docker toolbox; and then you can even get Docker going on Linux as well if you'd like. So let's jump in to the application itself, and I'll show you the steps to get this going. So, again, I've opened the Read Me that we've seen earlier in this module; and in this running the application with docker section, I'm going to walk through the steps real quick. Now I've already installed a lot of the dependencies to speed this up for you, but the first thing we're going to do is once we've installed node locally and either Docker for Mac, Docker for Windows or Docker Toolbox as appropriate, then we're going to come into our development file here. So I'm going to come into config development, and this is local host by default since we'll be hitting the local version of Mongo, but we want to hit MongoDB in a Docker container; and we're going to name that MongoDB. So that's why the host is going to change here. So once you've saved that file, we can move on to the next step. Next thing is we'll have to install Gulp. So we'll come on in to our terminal window, and we'll run the global install of that. I already have it, so it should be pretty quick here; and this, again, is going to be used to copy our Angular scripts into our public static files folder. We'll be using those in just a bit here. The next thing we'll do is our package JSON has all the Angular scripts, the node and everything we need. So we need that node modules folder. Now I've already run this, but I'll run through it really fast. So we'll do npm install. That normally would take, maybe, a little bit of time; and then we're ready to go there. Now we'll also need to run the Gulp copy libs to get the script from the node modules folder into the public static file folder. I showed this in the previous clip, so I'm not going to run it here; but just copy and paste that command there, into the command window, and run it, and that'll get the scripts copied. Now the next thing is we're going to be working with code locally, but it's actually going to be running up in a Docker Node.js container. So what I'm going to be doing is linking the Docker container back to our local machine folder using something called a volume; and that means we have to get everything ready locally so we can link back to our source code for this volume. So I'm going to run the compilation step for our type script code for the Angular 2 app. We'll run that, and this one I'm going to leave up. This will sit there and watch for changes that we might make as we go through and modify the app at all. Now the next step is we're now ready to run our Docker. So I'm on a Mac in this particular example; and you can see I have the Docker whale up here. If you're on Windows, it'll be down here in the right corner in your tray area; and that's for Docker for Mac or Docker for Windows. If you're doing Docker Toolbox, it's a little different. But hit docker.com, and you can get more details on that. If you're on something like Windows 7 or Windows 8, they have a nice walkthrough for you. So I already have Docker running, so I just have to run this build command. Now this is going to get the node and the MongoDB docker images available and ready. Now I've already downloaded these local, so this should go pretty fast; but it's going to build our node image. The MongoDB image I didn't need to modify, so it's just going to pull that from Docker hub. All right, and this is already done because I had run it earlier. Now the last step is we need to run Docker compose up, and that's going to start the Node.js RESTful service in the container and link that over to a MongoDB Docker container so they can communicate; but the Node.js container itself is going to link back to our source code using this thing called a volume. So let me go ahead and try to start this up. That's going to create the containers. What's really nice about this if you haven't done Docker before is I literally don't have MongoDB installed locally on my machine. It's in a container the I could easily stop and then delete the image, and it's just gone. So if you're interested in more details, check out my Docker for Web Developers course, which is also on Pluralsight.com. But now that we've done that, we can run on back. Let's go to localhoost:3000, and there we go. So we'll see the same app. I can edit customers, do all that type of stuff. See that all works. Looks like everything's working well; and then when we're done, we can actually go back, and I'm just going to do a Control + C here to stop everything; and then I'm going to say Docker compose down, and that's going to stop those two containers and now those are done and then I could go to Docker images if I want to see the different images. There's the node image, there's the Mongo. So I could actually delete those if I wanted to and it would be as if they were never on my machine. So that would be an example of how you can use Docker if you'd like to work with a sample application, and it's a great way to go if you don't want to have to install all these servers on your local machine.
Summary
In this introductory module, we set the stage for the overall learning goals that I have for you as you walk though this course. And, really, the overall goal is I want to show how we can integrate Angular 2 with Node.js RESTful services and also talk to an actual database. So as we start moving along in the upcoming modules, we're going to see that process. We also learned about some of the key technologies and concepts on both the server-side and the client side. So on the server-side we talked about node, MongoDB, HTTP, and RESTful services being used; and then, of course, on the client-side, we have Angular, RxJS, observables and HTTP Ajax type calls are going to be made up to those RESTful services. We also took a look at the sample application and saw how you can run it locally or using Docker containers. So now it's time to jump into the actual application and start building some of the different pieces that allow us to integrate Angular with Node.js RESTful services.
Exploring the Node.js and Angular Application
Introduction
In this module, we're going to take a moment to explore the Node.js and Angular application and look at things like the project structure, how Node.js and Angular's modules work and how they're configured and even explore some other aspects of Angular such as modules, components and services. So, if you're already very comfortable with how Node.js modules work and how Angular modules work, you could certainly go through this module, maybe skim it and jump right to the next one, but if you are new at all to some of the concepts we're going to cover, I would definitely recommend that you take a moment to go through it because I'm just going to provide a quick overview of how everything's put together, and that way in the next module when we start building out the code you'll understand the base behind the application that's making it possible to run. So, in this module here's what we're going to cover. We're going to talk about the project structure first off, and I'm just going to walk through some of the key files, some of the folders so you know the lay of the land, if you will. From there we're going to talk about the Node.js and Angular modules that are needed and just a quick overview of how they're used in the app. I have kind of a unique way of configuring my Express Node.js routes. So, we're going to talk about a convention-based routing technique that can be used. We'll also go into the fundamentals of ES6 module loaders. In this particular application, I'll be using SystemJS. There are many options out there though. So, I'm going to go through how SystemJS is configured. Make sure that you understand how it's all working under the covers, and then finally, we're going to create the basic building blocks that are going to be used later in the course as we start building our get and put and post requests and things to the restful service. So, I'm going to show an Angular module, a component in a service, and I'll show you the fundamentals of how all that works together if you're new to that at all. So, let's go ahead and get started by jumping into the project structure and walking through what it has as far as folders and files.
Exploring the Project Structure
Let's take a quick look at some of the different files and folders that make up the overall project structure of the app that we'll be discussing throughout the course. So, I've opened the application up in my VS Code editor and as mentioned earlier, you can use any editor you'd like, but this is what I'll be using throughout the course, and I'm going to take a bottom up approach to show you, just a quick look at some of the different files and folders. So first thing, we have our tsconfig file and this'll be used to convert our Angular to type script code down to our ES5. I'm going to be using a commonjs module resolution system in this example. I am going to generate source maps or debug capabilities, and then I have some type script and Angular two specific features in this area. So, I'm going to support decorators such as the component decorator. I'm also going to make sure that some of the folders are excluded so that the type script compiler doesn't waste time jumping into the node modules or this public lib folder. Now, we also have the Node.js file itself that acts as the server. So, this'll be our Express server. You will notice I'm importing some Express specific features, some modules here, and then I have some custom modules down here, and I'm also using some ES 2015 features such as a class here to organize my code kind of nicely. Certainly optional. I decided to throw this in to show that you could now with node, and this is the actual file that as mentioned kicks off the server that we'll be using. Now, the readme's going to have the instructions for running the app locally or through a docker. So, if you didn't go through the section earlier in the course where I showed how to get the app up and running, you'll find all the details in here, and then we have our standard package json. This'll have our Angular modules as well as our Node.js modules. Now, the gulp file I ran earlier and this was used to copy our Angular two libraries and supporting scripts into a static files folder Express uses called public. So, really one of the main things that the gulp file is used for is just to get the scripts from Angular into this folder called public into this lib folder. So, you'll notice our different Angular scripts in here. Now, if you're new to this the public folder is used by Express by default. Although you could change the name if you wanted, but it's used to serve up your CSS, your images, your job script files and things like that, and so, I'm just using gulp to copy those necessary Angular two scripts into here and that's where they'll be served up by Express. Now, it can also be used to do sass and things like that. Some minification is in here for compressing scripts, watching for changes and things along those lines, but really I'm just using it to get our Angular two script into the lib folder. So, we ran that a little bit earlier. Now, moving on up we have our docker compose file if you wanted to use the docker option that I provided and showed how to run earlier, then that's available for you, and then we have the standard gitignore for ignoring files from source control. Now, a little bit later I'm going to talk more about how routing works. I like to use a convention-based routing approach. It's not the standard approach that Express uses. It allows us to have a convention-based folder approach that I put into this controllers folder. So, this'll actually have all the functions that convert MongoDB data into json data that can go down to Angular as it makes http calls. So, I'll talk a little bit more about that later, but I like the approach. It really cleans up the amount of code you write, minimizes that and provides some nice conventions you can follow. Now, moving on up, the models folder. These are going to be the schemas and model objects that really just define the objects that'll be stored in our MongoDB database. So, this is a CustomerSchema for instance and then we have a model down here called Customer that we create, and then we also have a StateSchema and as State model, and again, these will just represent the actual data and the structure of that data as it goes in and out of our MongoDB database. Now, the Node.js modules that are actually responsible for interacting with MongoDB are shown here. So, we have our database object which is responsible for opening and closing connections. We have a config loader which allows us to easily get some configuration information such as connections strings based on the environment we're in such as development or production, and then we have a db seeder which is used to get some initial data into our database. So, this is just kind of fake data so you don't have to type it in yourself and this makes it easy to get the app up and running with some data in the database, and then finally, we have our customers repository. This is where we're going to be doing queries using something called mongoose which is a module that can communicate with MongoDB to get our data and then we're going to be converting that data to json. That'll go down to Angular. We also have a states repository which just gets our states information. So, it'd be like U.S. states for instance. So, that's going to play a pretty critical role, this lib folder in working with data in the app. Now, controllers as mentioned will tie in terms of routes. We'll get back to that a little bit later, and then we have our config which is just basic configuration info. In this case, just a connection string for MongoDB. Finally, we have our VS Code settings. These are just custom settings I have for the editor and then we have our docker file for node and this is what's actually used to create the node image if you ran the docker option that I showed a little bit earlier. So, that's a quick run through of some of the different files and folders and we'll be diving into several of these in more detail as we move on throughout the course.
Application Modules
Before we jump into the actual code of the app and learn about more on routing and Angular modules and things like that, let's take a quick look at the actual npm modules that are being used. The node modules and the Angular module throughout the application. So, I've opened up the package json file and you'll see right off the bat, we have the standard properties that you would normally find in type of file. So, we have the name and repository and license and things like that, but I also have few custom npm scripts I can run. So, if you run npm run and tsc, that'll just run a onetime type script to ES5 compilation. That of course will use the ts config file to determine how to compile the type script. If you run npm run tsc:w, that'll do the same thing, but it sets up a watcher that'll watch for changes to our type script file and anytime you save a file it just automatically then would compile that down to ES5, and then you have two ways you can start the server. You can run npm run server. That'll run a standard type node command or you can run npm start and that would run not only the nodemon to watch for changes to our node files and then restart the server if needed, but also behind the screens run the type script compiler in watch mode, and so there's an example of the one I showed earlier to get the app up and running locally. Now, as far as dependencies and devDependencies. We have quite a few dependencies that we need on the Angular side and on the Node.js side. Now, I've stripped out the versions because they change very frequently and wanted to focus just on the modules here, but you'll notice right of the bat here we have pretty much from here on up our Angular dependencies. So, we have the standard Angular modules that you'd need like cores, one of the critical ones. We're going to be working with forms. We're going to be working with http. We have some of our bootstrapping options that we'll get into. Routing and things like that, and then we have our supporting scripts, zone js for change detection, rxjs for observables and more. Now, everything else moving down is being used on the Express and Node.js side. Now, some of these quite honestly I could remove. I'm not really using a view engine per say. We have in the public folder an index html that's actually going to represent the entire application, but I went ahead and left this in, these modules here because if you ever wanted to dynamically serve up an Angular template or maybe the homepage is dynamically served using Express, then we could do that in this case using the handlebars data binding type of engine. It's my preference with Express, but there's many options out there. You can use Pug or many others, EJS, so on and so forth. You'll see we have mongoose and this will be our MongoDB connectivity type of module. Morgan's a standard Express logging type of mechanism and then I have a way to serve up that nice little favicon that you get when you bookmark a website. Now, we also some supporting scripts. We have concurrently is used to run multiple tasks. That'll run our tsc or type script watch and our nodemon simultaneously, kind of in parallel if you will. I'm not using lite server, but this is kind of a standard one for serving up static files. You have type script of course, and then the rest of these are just used with gulp. I can compress and kind of uglify my scripts and things like that. Now, the final two here are used with Angular as type definition files. This is kind of a newer technique to automatically install the type definition files for in this case, core js and for node and these are actually used a little bit in the Angular application. So, if you haven't seen this @types before, instead of running off to a site like definitelytyped.org or using tools like Typings, we can now get to the types for our different scripts and things directly which is really nice as you're working with type scripts. So, that's a quick look at some of the core modules we'll be talking about, and then now as we move forward, we'll start to use these modules as we move into the Node.js side and into the Angular side of the application.
Configuring Node.js Routes
As you work with Node.js and Express on the server side, you'll need to configure routes. Now, routes can be used to serve up views, your html that goes to the browser or to define routes to restful service apis and that's what we're going to focus on here, because ultimately we're all about Angular two talking to an Express restful kind of service. Now, I'm going to be using a convention-based approach. The approach I'm going to show you is a little bit different than the normal for Express, but I really like it. It's certainly optional. You can do the default Express way if you'd like, but I'm going to go ahead and show you the technique I always do as I work with Node.js Express on the server side. So, jumping back into the code, you can see that I have my server js file up here and the server js file of course is going to be what starts up the actual Node.js Express server and actually is the host of the restful service and also serves up our static files, our JavaScript CSS images, things like that. So, one of the first things I need to do in addition to registering all my middleware is to define my routes. Now, normally in Express, you actually hard code the name of the route and the function that it calls ultimately when that route is hit as the Node.js server loads up. I don't actually like to take that approach. I have a as mentioned convention-based approach that I like to go with. So, I have a router js file and we're going to come into that in a moment and it has a load function which we're going to call to load the routes. Now, instead of hard coding the routes though, I like to use a folder based structure to define the routes. That way I don't ever have to define a single line of code with the name of the route in it. I could just use a folder based structure. If I add a new route, I just add a new folder and the app automatically picks up that change and restarts the node process. Now, the way this is going to work is we're going to come into controllers. Now, this is a folder that I like to call. You can certainly name this whatever you want, but I'm following a similar model view controller type of pattern here and this is my restful service routing. Now, api/customers, api/states, api/tokens are going to be my routes, but these routes are all going to be driven automatically as the server first starts up by using this convention-based approach. I'm not going to hard code that api customers, api states anywhere in the code base actually. Instead what I'm going to do is use this router js to handle everything and it's going to parse the folder structure and then automatically generate the routes. So, the first thing I'm going to do is let's come on in and we're going to create a reference to this particular router js file. So, I'm going to go ahead and require the file and we'll go from the current location down to the routes folder and we'll grab router and that'll pull in that module and make it available. Now, the next thing I need to do is when the server initializes, you'll notice it's going to call into our middleware, seed the database and then it's going to initialize our routes. So, I'm going to come on down to initRoutes and I'm going to add just a single line of code here to make the router load the routes. So, I'm going to router.load and then the load is going to take the Express app which is defined up at the top of the file here and it's going to take the folder that it needs to parse to actually generate the routes. So, I'm going to command say controllers here. Now, that of course is the same exact folder that I just showed you right up here. So, what's going to happen is the load is then going to go through these different folders recursively and keep looping until it gets to the bottom of the folder and finds a JavaScript file and now the file I'm going to call a controller. It's really just a set of functions that are associated with the different routes. All right, so let's go ahead and save this file, and now let's jump over to our router js and I'll talk a little bit about what it does. Now here's the load. It takes the Express app and it takes the folder name that we want to start with and what it's going to do is this is only going to be called right when the server starts up. So, I want to wait before everything else loads and do this synchronously, one of the rare scenarios where you use a synchronous function in node, but I want to block the server from actually starting up until the routes are all parsed. So, this is going to loop through everything it finds inside of the controllers and then check if it's a directory. Now, if it is such as api, it's going to recursively walk through any children. So, in this case it would then find api and then recursively walk through customers. Now, at the bottom of customers you'll notice we have customers contrller.js. That's going to hit this else if and what we're going to is as we keep looping through the folders, we start to build up the directories. We're going to put these into an array that you'll see here. Now, I'm going to do a little string manipulation here on my directories, but the important part is down here. Every time I get to the end of a folder structure where I know there's no more folders in here. I found the files so I want to go ahead and now use that as the controller with a function for an associated route. Then, I'm going to fire up a new router just for that route. I'm going to create the route here. That's the base route and then I log it. You'll see that in a moment and then I need to load the actual controller itself, the functions for the route dynamically. So, the routes will be built up dynamically based on the folder structure. Then what we're going to do is load up the controller class. So, I'm going to go ahead and create a constant here. I'm just going to call it controller class and we're going to require and we're going to go to a full name variable. Now, full name you're going to see here is actually logged out, but this full name is kind of built up as we work with things. So, as we are looping through, full name's going to get modified and worked with and this will be the full name, the path and the controller. So, I'll go ahead and put full name. Now, what this will do is an on the fly require of the customers controller js for instance, or if we go into states. Once it gets to this level, it'll require states.controller.js. All right, now from here we're going to create another constant which is the actual controller because I need to feed this router into the actual controller. So, I'm going to say new whatever the controller class is that required and I'm going to feed it the router here. Now, if we go into one of these, let's go into customers for instance, you'll notice the router's passed in and then slash would represent the root. So, it'd be api/customers in this example. This one would be api/customers/page. Api/customers and then a route parameter of id as an example. So, we'll feed that router in. This now maps any child routes unless it's a root and then we're kind of ready to go. So now, once we have that ready, I'll just put a comma here. I'm going to associate the route with the router and we're going to do that by using Express. We'll say app.use. I'm going to give it the base route. That's the one where we take all the directories like api and customers shove them together with a slash. That's our base route and then I'm going to feed it the router which is also been passed into our controller. So, in essence, what's going to happen behind the scenes now is when we call load, it simply parses this folder structure automatically generates the route and then hooks the route into this particular file, this customers controller. Now, the customers controller responsible for then mapping the in this case, root route which would be api/customers to this get customers or this particular route will be mapped into here and we'll talk more about some of these routes and build them out individually as we move through the course. Let's come back into the router. So, we'll loop through all the directories recursively. We'll then say okay; we must be at the end of the road. This is our what to do file. We'll then build up all those directories, create a router and then we'll use the full path to where we are to load up that controller file, that class, and then we'll map the router into the Express instance. So, now this base route will be associated with this child router here. Now, if you're new to Express routing this might seem a little bit complex to start, but here's what's nice about it. You wouldn't even have to modify anything in here as long as you understand what's going on with the folder structure, we'd be good to go. So, if we wanted a route called foo. I could add a new folder called foo and then I could have a foo.controller.js in here and then I'd have to put my code of course for that, and we'd be done. I would just restart the server and now there'd be a route called slash foo that would map to some functionality in this file and that's how easy it would be to add new routes. Now, whether or not you like this approach, I'll leave that up to you, but this is what I do for all my Node.js Express apps because it means I write less code. It's very easy to discover the routes first off without actually looking at any code and it ends up in my opinion working out pretty well. All right, so let's try this out and we'll see the logging that you saw in the router as it creates the routes dynamically. So, let me open a terminal here and I've already started my MongoDB. So, I'm just going to run npm start and it might restart if there's any changes. Okay, it looks like it found one thing. Here we go. So, created route api customers for and then it gives you the full path to the customers controller. So, that's what to do when this route is encountered. Api/states was created. Api/tokens was created, and then we're done, and so, that's how routing to the restful service is going to work. Now, just to show you this that hopefully it's working, I can now come into these routes. So api/states, I've already loaded it, but you'll notice this loads all the states. Now, I'm using a postman three Chrome extension you can get. If you haven't seen it before, it's a very popular way to test your restful apis, and you can get that in the Chrome Web Store. I can also come in and do for instance customers, and we can get all the customer data if we'd like or we could even come in and get a specific customer. I'd have to find the ID for it, but we could do that as well if we wanted. So, it provides a nice way to test our functionality and actually see that json coming back. So, it looks like the routes are working properly. Now, that's a quick look then at this convention-based approach to routing and that's what we're going to be working with through the rest of the course.
Configuring the ES Module Loader
One of the more challenging aspects at getting started with Angular is understanding how module loaders work. So, I'm going to jump into a demonstration of the configuration of an ES6 module loader and just show you behind the scenes what's going on so that later when we do our imports and exports of various Angular modules, you'll understand what's really happening behind the scenes. So, jumping in to the public folder that serves up our static files. We have our index html and this is going to be our homepage. That'll load our initial Angular two scripts and then we have our loader script. Now, we have two aspects to this. First off, we are using SystemJS in this example. It's just one of many options. You can use web pack and others, but SystemJS is one of the easier ways to get started with module loaders. Now, ES 2015, the ES6 standard if you will for JavaScript is what introduced modules and this provides a great way to import and export functionalities. So, instead of using a bunch of script tags, this is all I have for the entire application. You'll notice not one of these is custom aside from right here. So, what happens is I define the configuration of where things should start and what are the file names and what are the default extensions and some things we'll look it here in a moment, and then as the app loads, this system.import app kicks off. That's going to jump into our app folder and that's going to cause a main.ts to be loaded. We'll talk about that in just a moment. So, let's first go into our SystemJS config file which you'll see right here in the route of my public folder. Let's talk about what's going on here. So, first off when I'm doing system import app, that's actually mapping to the app folder that you see right here, and that's why we have this little map section that'll be loaded down here at the bottom. You'll see right here this is the actual configuration that the SystemJS module loader is using. So, anytime it sees app, it's really just linking over to our app folder. Now Angular, whenever it sees @angular, it's now linking over to our lib/@angular. How would it know where to go for those scripts otherwise? It wouldn't, and so, as we start to import @angular core, @angular forms or http or other Angular modules, this is where it's going to look at to find the root entry point. Same thing for rxjs. How would it know where to find those scripts? Well, we're going to map that into our lib folder, and this is where we can find that functionality. Now, we also need to say when you go into the app folder, what's the start file? Where do things kick off from? And that's going to be our main js. Now, if we go into the app folder, we'll have our main ts and this is where we do our bootstrapping of our Angular module that we're going to actually talk about to wrap up this particular module of the course, but this is where we bootstrap the module in. This is how we tell Angular this is our start up point of the application. So, we have all these other imports up here. What happens then is when we say system import app, that goes and reads this configuration. We know app simply maps to the actual app folder, and then we're also saying that in the app folder we have this main.js. Now, it's main.ts, but of course, that's going to get compiled down to ES5. We also have default extension of js. So, it knows anytime it sees imports, we don't have to put .js on those imports, just see like this one here for instance. So now, when it sees @angular it knows where to go, lib/@angular and then it goes in there, can find these different modules that Angular provides. In this case, when it sees app.module which you'll see right here. We'll look at this in the next section actually in more detail, then we don't have to put the .js extension because we've already told it that that's the default extension as you can see here. Same thing for rxjs. We know where to look and the default extensions for files we're going to load there is also going to be js. Now, as far as the actual Angular modules. When we do @angular/core, compiler, forms, router, those type of things, you'll notice that I'm registering the key ones right here, and then we have a little function here that loops through each of those package names and calls this set package config. Now, set package config, either calls this pack index or pack umd depending on what we're working with. In our particular case, we're going to come on in and load in some bundles that'll be provided and these bundles will be located in our lib folder. So, if you go into here into common, you'll see there's bundles in here, have this universal module definition bundles. These are actually the scripts that are going to be loaded. What'll end up happening then is as a result of this mapping of app to app and rxjs to the lib folder and @angular to the lib folder, now in not only knows where to go find things as we import, but it also knows where to find the Angular scripts and that's kind of where this packing type of thing comes into play. Now, this is one of those files that normally you don't really have to touch. You go find a good example out there that'll get you started, put it into play in your application and you're ready to go, but I like to talk through it because some people maybe have seen it, but haven't actually take the time to explore what this actually does. So, this is what allows our imports and our exports. After you're using web pack or another type of module loader, then yeah, you're going to have different configuration of course, but this'll be specific to SystemJS and the way that works. So, once again we do our mapping here. We tell where the Angular scripts are. We then tell it the starting point which is our app folder. That then had it configured main.js. Once this gets compiled down to ES5 as the startup folder or the int file and then that kicks off all the imports which then loads all the other stuff, Angular core, Angular platform browser dynamic and all the other types of things. So, that's a quick at the way module loaders work and what's nice about this you won't see any other scripts. That's it. We have our helper scripts for Angular. We have our module loader code here and that drives the entire application.
Angular Modules, Components, and Services
Let's take a look at some of the Angular modules components and services. They're going to be used in the app to ultimately communicate with our Node.js Express restful service on the back end. So diving into the public folder we have our root module called app module and this is going to be the main bucket I like to call it. It's going to hold the other modules that are reusable throughout the app. Now, before I go into more details here, let's jump back into main ts and this where we actually bootstrap app module in and that makes everything in the bucket available then to use. So, going back to app module, there's a few custom things that are being used. First off, we have a root component and you'll see that that's being declared right here and then we have some routing components. We'll go into that in just a moment and I'll show you what's going on there. Now, in addition to that we also have a core module which you're going to see is where I like to put my singletons and then any functionality that's just generally shared, but that can be created multiple times, I call that my shared module. So, I have very consistent approach I like to take. My singletons go into a core module whereas my reusables could be reusable components or pipes or directives or something like that, go in my shared module. You'll see that down here actually in the comments. So, we declare everything, we bootstrap the root component and that kicks things off. Now, let's take a look though before we wrap up here at some of these shared and core module features as well as the routing. So, let's first go kind of a top down approach. Let's go into the routing. Now, there's many ways you can do routing. This is a really simple app as far as routes go. So, I didn't make a separate module for the routes. I took a more simplistic approach that's pretty straightforward. So, I import the standard router module. I import components that are going to be used with these routes and then I have an interface that's going to be used right here for two properties and all this interface does is says that I have to have two properties, one called routes and one's called components. Now, in addition to that we define the routes. You'll notice that I have a customers root route here and then I have customers with an ID route parameter. So, really basic, but there's some other features like a customers grid and customers edit you'll see that are imported up top, and the reason I want to point that out is you'll notice I'm exporting this app routing which has these two properties. So, first off I feed these routes into my router module for root. That's pretty standard. So, these then become the root routes. I have a fall back route that if none of these match, it's going to redirect back up to my root route, but then I also export the components that are associated not only with the routes, but any child components that these may use, and I'll get back to why that's being used in just a moment. Now, if I had a more complex scenario, then I generally like to make a routing module, but in this case, it's kind of overkill, at least in my opinion. So, by simply exporting this custom app routing object with my two properties, I have everything I need and I really don't need to create a separate file just for a routing module. All right, so now that you've seen that, let's go back to app module. So, we import that routing file. We import the exported app routing item. That allows me to get to routes. So, there's my four root routes right there and then I'm also declaring all the components in one kind of statement. Now, the reason that's really nice is all the imports that were back in here, don't have to be duplicated in the module file. Otherwise, I'd have to import them and then list all those in the declarations array. By doing it this way, I don't have to do that. Now, I could've just as easily made a routing module and done the same type of thing. Then we could just import that module here and it would've declared the components. So, either way it works. All right, now the shared module. Not a whole lot in here actually, but we have a little bit. So, we have we saw earlier as the app was running a way to filter data as the user types. Well, that's potentially useful throughout an application. So, I made that shared. We have a pagination control. Now, that's also sharable. In this app it's only used once, but it could be used as the app grows if it did. We also have some pipes to capitalize data, trim data, trim off spaces, things like that. Well, those are certainly reusable, and then the rest of this is just defining these in my module. So, here's my shared module. I do all my imports of these reusable items. I declare them, and we're good to go. Now, some of these like filtered text box component uses ng model the directive. So, I'm importing you'll notice forms module because I need to be able to get to that, but aside from that we just simple declare these. Then we export these as well to make sure that any importing module can also get to these. Now, we know the importing module is our app module. So, we import that and there's our shared module. So, now all that functionality is going to be available to any of these components here. Now, the final one is where we'll spend quite a bit of time actually. We won't touch necessarily the shared code a whole lot, but if I go to core. This is my singletons. So, this is my services that I really do only want created once, and the main service we're going to start building now is data service. I won't go into to this in detail here, but this is what's ultimately going to interact with the Node.js Express restful service and so, you'll notice my rxjs imports, my http import and those types of things. So, if I go to the module for this core module here, you'll notice that I'm importing the standard suspects up here, ng module, but I'm also importing http module, because of course we want http functionality here and then all of my singletons are being defined as providers. Of course, we have to have our provider so the injector service can then inject these into the different components and maybe other services. Now, I also have something unique going on and this is a very custom solution, but I want to make sure that nobody else, no higher up level modules have defined any of these. I really want them to be singletons. So, you'll notice I have this ensure module loaded once guard, and what that's going to do is there's a little bit of code here on this core module to actually check have any of these other items already been loaded. So, it's going to check to make sure that core module is only loaded one time and that one time would be here in app module, right there. Now, what this will do is using some kind of trickery that I have in here. This will go in in this base class and I'll let you look at that one if you're interested, but it will ensure by walking up that core module's only loaded one time and that would mean if core module's only loaded one time, then our providers are only defined one time and therefore we can guarantee singletons for our different services. Now, this is certainly optional and given that this is not a super complex app, certainly overkill in this example, but in a larger scale app, this is something that's nice and it'll be available in the app if you'd like to check out some more code there, but that's all our singletons. Those get loaded back into here and that's where we're going to spend quite a bit of time is in this core module. Now, the last piece to show you that's in here is we need to load our customers. We have edit capability and we have the grid capability, and so, that's all going to be done with our various components. So, you'll notice that I have a customer edit component, a customers component which then loads a customers grid component and the filter text box and paging and things like that. So, we'll start to dive into some of these as well as move along throughout the course. So, that's how everything's organized as far as the Angular code goes. So, we've seen how the module loader works, we've seen the different levels of modules that we have. We have our root module, our core module for singletons and our shared module and then my routes and we declare all the components right here that we're going to be using. So, what we're going to do moving forward in the course is I'll start to build out the get type of data request to the server and we'll show how to build the server piece and the client side piece and the service and then use that component. Then, we'll talk about how do we update data, how do we insert data, delete data and all of those different things.
Summary
In this module, we've seen the overall project structure that was initially generated using express-generator and we learned about some of the key folders and files used in the application for the restful service and for the Angular part of the overall application. We've also taken a look at how npm modules are used on both the Node.js side and the Angular side. How the application has a more convention-based routing feature that actually looks in the controllers folder to determine the routes that are to be used for the restful service and then we also looked at the different Angular modules, the custom modules that are being used in the app such as the core module, the shared module and how those are used in the root module. So, moving forward what we'll be doing now is dissecting the individual pieces of the application and building out that code. So, we'll talk about how we can get data into the app. That'll be our next topic, and then from there we'll talk about different ways we can work with manipulating that data.
Retrieving Data Using a GET Action
Introduction
This module is all about learning how to expose data through a RESTful service, and then how we could consume that data using Angular Services, and even data-bind the data into our templates and components. Now we're going to start off with a look at the different GET actions we need for the apps. We'll learn how to get customers, get a single customer, as well as how to get states. We'll also talk about how we can make GET requests with an Angular service, and we'll talk about observables again, and review how those are going to be used and the role they play. From there we're going to switch gears to using the Angular service to consume the data, get that observable back, and subscribe to it in a component, and then render the data in a grid. And then we'll wrap up by looking at some different techniques that can be used to render a single customer in a form. We're going to talk about a template-driven approach, and a reactive forms approach. So let's go ahead and get started by building out pieces of our RESTful service.
Creating a GET Action to Return Multiple Customers
One of the first things we need to do is enhance our RESTful service to return customer data to whoever calls into the service. Now for this app, it's going to be Angular, but technically it could be any type of client, capable of using HTTP to call into this service. So I'm going to show you some code that'll map a route to a function, which'll then call in to MongoDB, get our data, return it as JSON, and then later, we'll jump into the Angular2 code, consume that data, and then display it. So let's go ahead and jump in, and see how we can do some routing here. So earlier I mentioned that the application has a convention-based routing approach. It looks in this "controllers" folder, and the subfolders are put together to create these routes. So we'd have api/customers, or api/states, or api/tokens, and we'll be talking about all of these as we move along through the course, but in this one we want to focus on this file, which is at the root of this route, api/customers. Now you'll see, this is just an ES2015 class, nothing' special, I could've even just chosen to use regular functions, but it's going to be responsible for accepting a router. This is passed in as the router does its convention-based routing, and then mapping incoming routes to functions, and then the functions will be our actions that return the data. So we have MongoDB, and although I'm not going to write the code for that part of it, since this course is about RESTful services and Angular, I do want to show you the basics. So if I go into the "models" folder, you'll notice I have this customer.js, and it's importing the Mongoose module that I mentioned earlier in the course. Now this is one of many modules you could use to query MongoDB, but Mongoose has this Schema property, and/or object you can use, and we're also importing another model object that's related to Mongoose here for a State. And this is really how the data's going to be stored in MongoDB, so how the fields are going to be laid out, so for a given order I'm going to have a product, price and quantity. For a customer I'm going to have firstName, lastName, email, and then some complex types, a State, that could have an id in it. In fact I can show you right here, an id, abbreviation and name, whereas the customer, you'll see, is kind of the normal customer type of fields, plus a state object, and you can have an orders object, an array of orders, which is our orders schema. So this is kind of how you can use Mongoose to define the structure of the data that's going to be stored in the database. Now what you'll do from there is you'll take that schema, and then plug it into a Mongoose model, and this is actually how a query, a collection that'll be called customers as it gets created in MongoDB, but this is actually how we're going to query the database, through this. So that's kind of the first thing you do with Mongoose, is you set up your schemas and your models, then you can write some code to actually query those models. So the way we do that is through the lib, and our library of modules here has a CustomersRepository, and I can do things like get customers. Now this is going to import our customer model, you'll notice I then use that to get the count of the customers, and also find all the customers. This little object literal here means, "I don't have any type of query I'm doing', "as far as a 'where' clause, a predicate," so it's going to grab all of them. Now assuming it works, this is really what we're after. We want to return to the caller of this getCustomers, the number of customers, and the actual customer data, the array of customers. All right, so that code is already in place, now what we're going to do is use that code in our customer controller that handles the incoming routes, and creates this RESTful service. So now that we have the schema, and a way to actually query the model and get the data back from the database, we can come into here, and first thing we need to do, we need to import our repositories. So I'm going to call this first one "customersRepo", and we need to to up a few folders, we got to get back up to the lib. So we're going to go up about three levels here to lib/customersRepository. All right, now later in the course we're also going to use a states repository. We don't need it right here, but I'm going to go ahead and add it, so this would be "statesRepo" and "statesRepository", and that'll just grab a similar type of object that is capable of just querying all the states in the US, for instance. And then finally for error handling, I'm just going to log to the console to keep it very simple. You could certainly add more robust loggers if you'd like, but I'm going to use a Node.js util module to do some of the logging. You'll see where that's used in just a moment. All right, so that's kind of step one, now if you're new to this, you'll notice that means I'm not going to write any data access code at all in the CustomersController, and that's good, especially from an architecture standpoint, because now if the database, for whatever reason, changed, and we have to rewrite the queries, or whatever it may be, I'll never have to change the CustomersController code, the code that's going to actually serve up the JSON per say, assuming the interface of the data stays the same. That's a good thing, we're isolating ourselves from the actual data access. So now what we can do is, really this CustomersController, the root route it's designed to handle is the folder structure, api/customers, that's what the router I talked through earlier will create for us. So it's going to create this api/customers route. Well, when that route is encountered, I want to use customersRepo to go get the customers, and return those. So the way we can do that, is we can say, "Hey, when the router sees a GET request from "the client, to api/customers," now this is just an alias, this means the root of this router, which is api/customers, "then I would like to call getCustomers." Now I don't have that yet, but we're going to come down here and we're going to make a getCustomers that takes a request and a response, like that. Now I could just do that, but I want to make sure that when this gets called, it's with the proper "this", since we know in JavaScript, "this" can be a little bit fun sometimes. So I'm going to bind the call to the current "this". By doing that, I'll make sure it's called with the proper context. Okay, so that's kind of the first step. Now from here, we need to use our customersRepo. So the first thing I'm going to do is just log that "Hey, we made it in here." So we'll just log out getCustomers, and now we want to use our customersRepo to getCustomers. Now I'm going to use an arrow function to handle the error and the actual data we get back, so we'll use the ES2015 arrow syntax, and in here, I now need to check if we have an error. Now if we do have an error, we're just going to log it to the console, and I'm going to use the response object's JSON function. Now if you're new to that, this is how we can actually return JSON using Express, it's an Express feature. So ultimately I want to do this, I'm going to just go "return nothing" if we do get an error. Now I certainly could return an object literal with some error object, but we're going to keep it pretty simple, and just keep all the error logging on the server side. So I'm going to log out "console.log", we'll say "getCustomers error: ", and this is where I'm going to use that util. It's a nice way you can write out the error object to the console, it gives you a little more nice insight into the error, if you haven't seen that before. Now in this particular app, this isn't actually going to get hit, but we should always handle that, which is why it's in here. All right, let's get to the good part though. Now if it works and we get data, then I'm just going to do a little logging that says "getCustomers" is "ok", that way it's kind of easy to follow, and then we use response.json, and this time I don't want to return null, I want to get our data object here, and it's going to have a "customers". Remember there was a "count" and a "customers"? Well I'm just going to return the "customers". Now later in the course we'll see where that count is used for some paging operations, but for now we're going to return all the customers. Okay, so we're ready to go there. So now we have a way to handle api/customers, that's what this represents. It's going to call getCustomers, we make sure it gets called with the appropriate context, and then we're going to use our customersRepo. So again, notice I have no idea that this is actually calling MongoDB. It could be PostgreSQL, it could be SQLite, it could be SQL Server, who knows? And that's what I want, I don't want my routing controller here, my action, to know anything about the database. Thin controllers in other words, keep everything very slimmed down. All right, so let's save that. Now later as we move into the UI side with Angular, we're going to need to get states, and this controller's already done, but notice I'm going to do the same thing. I have a constructor, this would be api/states, that's what this guy represents, and it's going to call getStates, and that uses a statesRepo, same exact pattern. So once you get this pattern down, you're going to do the same thing over, and over, and over. Kind of a single responsibility type of approach, where in your lib, or whatever folder you decide to create, you put your different repository objects that query for different database objects, and then your routing code, which in my case is these controllers, is simply going to be responsible for calling into that to get the data. All right, so we're good to go there. We now have a way to get states, and we have a way to get customers, now does it work? Let's try it, so let's go in to our terminal, and I'm going to run this locally, again, you could also use the Docker option I showed, but we're going to do "mongod" to start up my MongoDB database. You can start up another terminal in the root of the project, or I just use a tab here to do it, and I'm going to run "npm i" first off. Now I've already run that to save on time, but make sure you install the dependencies. And then we'll go ahead and run "npm start", see what we get here. All right, don't see any errors, so that's good. Now I could pull this up in the browser, but my tool of choice by far, to test out my RESTful services, is Postman. So I already have this up, and I've already typed in the route to this api/customers that we just created, and if real quick though, if you're new to this, I mentioned it earlier, but this is a free tool. You can go to the Chrome Web Store, and just go search for "Postman" and install it, and then once you start it up, you can now type in paths, you can do GET, POST, PUT, all of the fun stuff. So we're going to do a Send, and looks like it worked. Beautiful! Let's try out the api/states that I showed you, that was already done, and all right, excellent. And it looks like we already have our states as well. Now we are going to work with, if we do customers/some id, in fact here's one, if we go back to our customers. Let's go grab that id right there, which is probably the same one I just showed you. Send, okay, now that didn't work. Notice it redirected us, actually back to the homepage. Okay, so we got a problem there. Well we're going to be fixing' that in the next section. But for this particular section, our job is done. We now have created a RESTful service API for the api/customers route, which calls our getCustomers, calls into Mongo, and gets our data, and then uses the express response JSON function to return that customer data back to the caller.
Creating a GET Action to Return a Single Customer
Now that we've set up the RESTful service to return multiple customers, let's take a look at how we can return a single customer. To handle returning a single customer, we need a customer id. So we already have the route setup to handle api/customers, but I need to add another child route here that handles api/customers/, and then I'm going to make a route parameter. Now this is something, again, that's provided by Express, the router that's part of Express, and we can just put a colon, put the name of the route parameter, and then we're kind of off and running, and now later I'll show you how we can pull that off and get to it. So let's come on in and we'll map this to a getCustomer, and then I like to add the "bind" I mentioned, just to make sure the context is set appropriately. It's not actually going to be needed here, but it's something I like to follow. All right, so let's add a getCustomer that takes a request and a response, and we're going to do a similar thing here, so I'm just going to grab our logging statement to save a little typing, and once we do that, we can start to get to work here. So the first thing I'm going to do is, I'm going to grab the id, and the way we can do that is go into the request, go to the "params" property, and then go to id. Now I'm just going to assume that it is passed, but we certainly could add more code to say if it's not passed, throw an exception, or assign it to zero, or something like that. Otherwise it's possible we could get an undefined, or null reference type error somewhere, but we'll go ahead and keep it pretty simple. Now we already have our customersRepo, so I'm really after the same type of code that you'll see up here, but I'm just going to change it a little bit, so let's come on up, I'm just going to copy that down, change this to "getCustomer", and now I need to add some code to handle the id. So we already have the id, I need to pass it as the first parameter. So I'm going to pass id here, and then we'll give it the callback if it's able to find the customer. So we'll change this real quick to "getCustomer", and then I'm going to return the actual customer that we get back. So I'm just going to rename this to "customer", since that's what we're going to get, and we would return that customer. All right, so same type of premise as before, we're going to use our customersRepo to get that Customer, let me jump in there really quickly to show you that code. And we're going to use this Customer model to findById, it's one of the built-in functions on the model. There's the id that we passed in here, and then there's our callback that's going to get invoked right here, and we'll hopefully get back the customer, or we're going to get back an error, one of the two. All right, so assuming this works, we'd get back a customer, so let me go ahead and save that. Now I already have my console still running from the previous example, notice it keeps restarting. So let me open up Postman again, let's go back to all our customers again, looks like that's still working. Let's try to grab this first customer now, so we're going to say customers/, and I'm going to put the id, and let's Send that, and looks like it works, all right, so that's great. Let's just double-check, let's grab one more, let's go down to another customer, or maybe this guy right here. So we get back Jesse it looks like, and there we go, Jesse Smith, and we're good to go there. So looks like we're working, so now we have the ability to return customers, and a single customer by defining our routes, and then mapping those routes to our functions. So now we have the, at least "get" functionality, at least the core "get" functionality for the app ready to go. We're going to enhance this a little bit later, but we have enough now that we could start to move into the world of Angular, and call this service.
Making GET Requests with an Angular Service
Now that we have a RESTful service capable of giving us customers and a single customer, it's time to integrate Angular with that Node.js Express RESTful service. So the first thing we're going to do here is go into our public area, because I want to work with our data services already in this public app. So if I go into public, app, core, core again, I mentioned earlier in the course, represents my singleton objects. I only want a single instance of anything in core. You'll see I have this data.service. So the first thing I'm going to do is get HTTP setup. Now, as a quick review, if I go to core.module, you'll notice that I've already imported HttpModule, and then I've added that to the imports, and so that'll make the HTTP client object available to my data service, and I can inject it. So let's go back to the data service, and let's import Http, and I'm going to grab a few other things we're going to be using throughout this particular service as well, so I'm going to grab a Headers, which we'll get to later, Response object and RequestOptions, and we'll talk about the Http and Response now, later we'll talk about Headers and RequestOptions as we move through the course. We're going to grab that from angular/http. All right, so now that we have that, I also need to work with observables, and I talked about, at the very beginning of the course, the role of observables, and how really they're like an array of data, stream of data into the future, and although HTTP calls only give me one value, you can think of that as getting back an array of one item. So I need to setup my observables, now this is not the most fun stuff to type, so I'm just going to grab a snippet here, and we'll talk it through it. So first off I import Observable from rxjs/Observable. If you recall in public, we ran a gulp task to get this app up and running in the first place, and the gulp task automatically had the lib folder added. Now if you don't see that lib folder, then you're going to want to go back to the console, and run that gulp command, which is a copy command you'll see here, "copy:libs", and that will make sure that your Node modules get copied in to your lib folder. Otherwise, when we try to reference rxjs/Observable and @angular, if you don't have this lib folder, then you wouldn't have these different folders that we need. So I already have that, so we're pretty good to go there. All right, so I'm also importing some operators. I have map and catch, now map is going to allow us to map the incoming response to a callback function, and catch is going to allow me to actually catch errors, of course. Now I also have a way I can add a throw capability, a throw function to Observables. Now I'm going to jump down here, we're not going to talk about it a lot, but I have a little handleError, and you'll notice at the very bottom, once it builds up what the data is, and also right here, I have this Observable.throw, and this'll throw an error, but it'll throw it as an Observable, that way whoever subscribes to the Observable can also get to the error in kind of a normal way. And so that's a little callback error handler that we have, that we're going to be using here in just a moment. All right, so those are some of the initial imports I need, we have our Angular imports, and then we have the Observable, and our main things are operators we're going to be using. So now that we have that, I need to inject the HTTP object in, so I'm going to make a private option here, call it "http" of type Http, and that'll handle our dependency injection, and because we've already imported HttpModule, the provider for this object will be, of course, available for us. All right, so the next thing we need to do, is we need to work with getting customers, and getting a single customer. So I don't currently have a function for that, but we're going to add it, so I'm going to add a getCustomers, and it's going to return an Observable of an ICustomer array. So I'm going to say "ICustomer array" here. So we're going to use a generic from typescript to say "Yeah, I'm going to give you back an Observable, "whatever subscribes to this, but inside of "that Observable, I'm going to have this ICustomer "that you can actually work with and use." Now right now, ICustomer's actually not known, okay, and if I go into my shared area here, you'll notice I have an interfaces.ts, and this is my ICustomer. So you can see some of the different properties it expects, but of course, I need to actually import that. So we're going to come on in and import that as well, so I'm going to actually import several from this interfaces file that we're going to be using throughout this DataService, and we'll grab that from, move up a folder to shared/interfaces. All right, and that'll allow me to give, kind of a strongly-typed response type to whoever calls this getCustomers, so we'll go ahead and make that. All right, now inside of here I want to be able to make an HTTP call, and I could hard-code the actual URL. What I like to do though is come in and put a base URL, or something like that, that's a string, and this'll be to the api/customers. Now you'll recall that that matches, of course, exactly with what the RESTful service has, and so that's actually what we're going to call on the RESTful service here. So now I can come on in, and I can go ahead and return an Observable by calling http.get. We would like to get the baseUrl, call up to there, but because we're working with Observables, a stream of data over time, I'm going to map the response we're going to get back, and in this case we're going to just call it "res", and that's going to be of type Response, that's why I imported that earlier. And we're going to map that into a function. So let me do an arrow function here, and this'll be our map, and before I actually do the semicolon, recall that I imported the catch operator, so of course, you always want to be able to catch errors as well, and that's where I'm going to use the handleError that you saw down below. All right, so we're now setup to get to the response. Well, what I want to do is get my customers, so I'm going to say "let customers = response.json", that'll parse the JSON data in the response, and give me back the customers. But the customers have some orders, and what I need to do is, the server's not doing some totaling for the orderTotal. Each customer needs an orderTotal I want to be able to display, and that might be used as the app grows for instance. So what I'm going to do is grab the customers that we're going to get back, but I actually want to call this calculate function, "calculateCustomersOrderTotal", and as you can see, that's just going to loop through each of the orders, and update this total property, pretty basic. So what I'm going to do is pass in my customers here. All right, so we're going to manipulate the data before I actually return it to whoever subscribed to getCustomers here. All right, so that'll kind of get us setup for that particular piece of functionality, and then we can go ahead and return it, okay. So now we're starting to use our Angular functionality. So we have an Angular service called DataService, we saw a little bit of this earlier, it of course has the Injectable decorator on it so that we can handle injecting HTTP, and that it works. We do all the imports of whatever we need, in this case Http and Response, and then I'm using some interfaces here as well, in this case, ICustomer. We've also imported Observable so that I can use that as a return type, and I can use it to throw errors if I need, and then I have the map and the catch. So anytime you work with rxjs, you are going to be importing specifically what you need. It is possible to import everything it offers, I would not do that, because that imports a tremendous amount of scripts, so just import the things you need, like you see I'm doing here. All right, so there's our getCustomers. So now a component could have DataService injected into it, which we'll get to later, and then it can call getCustomers, and that'll return the customers data that we need. Now we also need the ability to return a single customer, so let's add that. We're going to do, an id would have to be passed in, of course, as a string. This is also going to return an Observable of, in this case, one customer, ICustomer. All right, now this one will be very similar to what we see above, we're going to return the Observable by saying "http.get", we're going to use that baseUrl that we defined up above, but I'm going to pass the id. And I could've done the ES2015 string interpolation here, but I think this is just as easy as that option, so we're going to go ahead and just leave it like this, and then we come in and we're going to map the response. So we'll map that Response object, and we need to, of course, get the JSON, parse that. Now this is going to be a very simple example, so I don't need to run the calculateCustomersOrderTotals in this one, but of course we'd also want to handle catching errors, so we'll just do the same thing, we'll call handleError, and so we should be good to go. So we have all the imports we need up here, we have the baseUrl that we're going to call, we've injected HTTP, and now we're going to use HTTP to actually call into our RESTful service that we created earlier, get those customers, update some order totals for each customer, and then return them, so we're doing' a little bit of clean up work before the component that's going to call this service later actually gets the data. And then we've also added, of course, the capability to get a single customer. Now before we go too much further and wrap up, let's see how we're doing compilation wise with our typescript. So I still have my console running that's loading the RESTful service, and also running the typescript compiler, and if we look, kind of down here at the bottom, it looks like some customer-edit-reactive and customer-edit-component. They both are looking for getStates on DataService. Now it says a "Property of 'getStates'", but in this case it actually means a function. So we need to add a getStates, and if you remember, I showed that we had a getStates on our RESTful service, so let's go ahead and do that, pretty easy. Now that we have already seen HTTP, it's really just the same thing. So we're going to say "http.get", I'm just going to give it the URL here directly, because we only use it once, and then we're going to come on in and we're going to map this again, we'll grab the response, and you can see the repetition now going on here. Pretty straightforward, pretty easy, and we're going to map this, just grab the json again, and we always want to handle catching the error, so we'll say "handleError". Now I want to be specific, although I don't have to return what this is going to give us, which is an Observable, I do want to be specific like we've done up here, but I have another interface called "IState". So if we go back into the interfaces, IState is very, very simple, abbreviation and name are only required. Let's go ahead and add that as the return type here for our getStates. So we'll say ": Observable of IState", and this is going to be an array. All right, and we'll be in business. So we now have a getStates, returns an Observable of a state array, and we have a capability to do that. So let's save it, let's go back to the console, and all right, now it looks good. You'll notice that compilation completed, there was a file change detected, which I just saved, and then it actually updated that, and so we're pretty much good to go. So the last major piece here is, we now have our DataService, which at least has our initial get operations, but I need to add DataService into my core.module. So my core.module is all my singletons I mentioned, so I'm just going to import DataService, we're going to grab that from our local folder, data.service, and we need to add DataService as a provider, so I'm going to say "DataService", and that way when some other components need DataService, we can inject it, it'll look at the providers here, and know what to do. So let me save that, let's go back to our console here, and everything looks good, all right. So we have several file changes occurred, and we're still good to go. All right, so that's a walkthrough of now calling the getCustomers, the getCustomer, and the getStates get operations, or actions, that are up in the Node.js Express RESTful service, and then how we can actually use Observables. So now we're going to keep moving forward and start working with this data we've now retrieved.
Displaying Customers in a Grid
Now that we have a service capable of calling into our RESTful service, using HTTP to get our customers and our states data, we need to take that data and bind it into our data grid that you saw in the application, that's what we're going to work through here. So I'm in a folder called "customers", this is my feature folder, for our customers feature, and I've opened up the customers.component. Now as a quick review in the routing that we explored a little bit earlier in the course, we had a route called "customers" that goes to customers.component, so that's where I'm at right now, is I've opened up the customers.component.ts file. Now this is a pretty standard component, there's nothing really special about it per say, we import all our dependencies that we need, we have our Component decorator, we implement OnInit, which I like to do to make sure I don't have any typos with my ngOnInit function, and then this is really what's going to kick things off. This is where we're going to get our customers from our DataService. You'll notice though that first off, I haven't imported DataService, and I haven't injected it, so that's the first thing we're going to do, and then we're going to use it to get our customers. Now the UI that ultimately is going to render the customer data, it's going to need the ability to, not only get the customers, but also handle filtering the customers. So you'll notice I have a customers property here, and I also have a filteredCustomers. Now filteredCustomers, you're going to see, is actually what's going to be bound into the UI, but if the user undoes a filter, removes a filter, I want to it to quickly be able to get back to the original set of customers. So this customers here will never be bound to the UI, but it'll store the original collection of our customers, so we can kind of undo the filter, and display all the customers. Now I could go back to the server and, when they undo the filter, make an HTTP call every time, but it seems a little bit unnecessary unless you expect that your data on the server is changing a lot. All right, so the first thing we're going to do before we move on to filling these properties, is I need my DataService, so let's go ahead and import that. All right, that'll take care of importing it, and then we need to inject it. If you remember earlier, we added a provider for DataService into our core module, so now we can inject it and use it. So we'll say "private dataService of type DataService". All right, so we're good to go there. DataService is now available, when this component gets initialized, getCustomers gets called. That's going to call down to here, and now we need to subscribe to the Observable we're going to get back from our DataService, so let's go ahead and do that. So what I'm going to do is now add in our code to call our DataService, call that getCustomers, and then subscribe, and then I'm also going to show you a little error handling along the way. So we'll say "Hey DataService, "I would like to getCustomers." We know we're getting back an Observable, if we mouse over that, you'll see "Observable "of ICustomer array" is what we're going to get back. So I'm going to say "let's subscribe." Now I'm going to get back some customers, we'll say "ICustomer array," because we know we're getting back that, and I'm going to make my callback function here, that's where I'll do our arrow function. Now I'm going to add a little extra piece. I could stop right there, but if there's an error, we probably do want to log that. So if you put a comma, you can actually add a little error handler, and I'm going to do something very basic here, and just log the error, but you could certainly add something more robust, and then if you want a function to run, kind of every time, a "Hey do this every time" type thing, you can also come down and do the following. And actually, before I do that, since I'm not going to end it there, let me get rid of that, and we'll do a console.log, and I'm just going to say, "getCustomers was called," it retrieved customers, or maybe it got an error I guess, and then we'll end our parens here for our subscribe. So now we have a way to have a success callback, that's our first area, an error callback, if there's an error as we subscribe, and then a "Hey, let's just write this out "every time to the console, so we can get "some visual feedback here in the console, if we'd like." Now what I need to do is take these customers and assign them up into the individual properties up here. So let's go ahead and do that, pretty simple. So we'll say "customers is the same as filteredCustomers," at least when it first loads, and those are both equal to customers, and that should take care of it. Now let me save, go back to my terminal window, and looks like some changes were watched for, and I don't see any errors there, so it looks like we're pretty good to go. All right, so that's kind of the first stage. We now have customers that are available. Now if I go into the template, you would probably expect that the template for this component must have something that binds to filteredCustomers, well let's go look. So this is the template, and you won't actually see filteredCustomers in here anywhere except for right here. So I could've but the grid functionality, certainly right here, but I decided to build a child component called "customers-grid", and we'll look at that next, but it has an input property called "customers", and that's actually what accepts our filteredCustomers. Now to reiterate, customers, back in the customers.component, is the raw data we get. filteredCustomers is either the raw data, or the filtered data, because the user could interact with our UI of course. So we're going to send this guy down into our child component, and that's going to have a property we'll look at in a moment called "customers". All right, so let's go ahead now and let's see what we have going' on in that component. So here is my customers-grid.component, and if I open it up, you'll notice I have an Input property, so I've imported that. And Input property, if you're new to this, is basically a way to pass a data-bound property from a parent down to the child. And so now I'm saying, "Hey, you can pass me "something of type ICustomer array," and I start off with just an empty array. Now it doesn't do a lot more than that, it does have some sorting capability, I'll show you the basics of that as we move along, but other than that, nothing' real fancy here. Now one thing I do in this scenario where I have Input properties, the only time this would ever need to be checked for the change detection mechanism that Angular2 has built-in, is if the Input property changes, I don't have an output event, I don't have anything else special, I just want to detect this and re-render the UI for changes if the customers changes. Now if the customers change, then certainly I would like to push those changes out, so you'll notice I'm actually using a changeDetection mechanism, or strategy they call it, of OnPush. Now that's certainly not the default, which is just Default if you put nothing, that would mean it always gets checked for changes. We're only going to detect it for changes in this example anyway if this property is changing the data, the array changes for instance. So that's a nice little performance characteristic you can add when you have these child components that only have Input properties, and you only want the change detector to have to worry about this if that Input property changes. Now other than that, it does a little bit of sorting. There's a sorter service I have that can sort the customers as they click on the header for the data grid. I won't go into that here, but that's all in the code. I also have something called a "TrackByService" that's being injected, and I'll talk about what that does here in just a moment as well. All right, so now that we've seen that, let's go ahead and leave it as it was. Let's go into our customers-grid.component.html, and you'll see this is a pretty standard set of table tags. Now I could've used divs or whatever, but this was tabular data, so I went with just a table-type approach. So you'll notice up top that when the header rows are clicked, I call the sort function that you saw back in here, that calls in, passes the property to sort, and that calls the sorter service, and then it actually sorts the customer data. So you'll see that in action as we move along here. Other than that, all I'm doing in the table body is simply rendering some rows for all the customers, so pretty basic. So all I'm going to do here to get the data loaded, is we need to add our ngFor directive to loop through those customers in the Input property. So let's go ahead and do that, let's do an ngFor, and I'm going to say, "let's make a customer variable "as we loop through, of customers." I'm going to add a trackBy, and we're going to be tracking by the customer. Now let me show you a little bit on the trackBy real quick, so if we go into the core, and we go to the trackby.service, you'll notice that there's this customer call here, that's the one I just wrote the code for. It always passes in the index of the item we're looping through, and then the object we're actually looping through. Now I'm saying that I would like to uniquely track each of the items being added by the customer's _id, this is something that comes from MongoDB, it's the unique identifier. So if you're new to trackBy, this is a great way, if you have data that's being added and removed, or modified in any way, in a table, or divs, or whatever it may be, by adding a trackBy you can really enhance the DOM manipulation. Instead of having to kind of delete all the rows, and then re-add them every time, it can just selectively update the appropriate rows as needed, so it adds some efficiency here. So trackBy is the object injected into my component.constructor, and then customer is the actual function I just showed you, that returns the unique identifier. I could have said the index, zero, one, two was the unique identifier, and that would work too, but since every customer has a unique identifier, we're going to use that. All right, now you'll see I'm already using this a little bit, so I render the customer.gender to render the image, and then what I'm going to do for the rest of this is just grab some snippet code to kind of overwrite what I have in here currently, and I'll paste that in, and all I'm going to do is bind in the firstName, I'm going to run that through a capitalize pipe, which is a custom pipe I have. If you're interested in that, you can go into the shared, pipes, and learn about a capitalize pipe there. I also have a trim pipe in there. But we'll write out the firstName, the lastName, the address, the city, the state name, and there's the orderTotal we talked about. If you remember the DataService would give us an orderTotal. All right, so we're kind of ready to go there. We now have said that what we want to look at, which is our customers, our customers, of course, represent our Input property. That's being passed in through the parent, really it's just filteredCustomers, and then we hopefully are off and running. So let's go back, and don't see any errors here, so that's a good start. So let's go ahead and open this up in the browser, and I already have this open to 3000, let me refresh, and it looks good. Now you'll see that all the customers are being displayed. I have no pagination, no paging at all going on right now, I don't have a lot going on for clicking on these. Let's try out the filter though. Okay, it looks like that is working correctly, and then I mentioned their sorting capability, and it looks like that's working correctly. So we now have successfully retrieved the data from the customers RESTful service that we have with Node.js and Express, we did that with our DataService, DataService was injected into our customers.component, and now we're kind of off and running. Now we're going to do quite a bit of enhancing of this, but this is a good start. Now let's move into the actual form so we can edit our customers.
Displaying a Customer in a Form
Our next step in this process is to grab a single customer from the RESTful service, and integrate it into an Angular form, and that's what we're going to look at in this particular section. So if we go back to the browser we can click on a customer currently, and if you look down at the very bottom, you'll notice that a customer ID is being passed, that's the unique identifier from MongoDB, and when I click on it, it does navigate to the route, but it looks like we have some broken aspects here, so we're going to fix this and retrieve that customer and display it, and along the way I'm going to show you some of the different form features that are available when it comes to working with Angular. All right, so let's minimize that and come back in. I've already opened up the customer-edit.component.ts, and the html. Now this is very much like any component you'll open, I import the dependencies I need. You'll notice DataService is already available in this case, because we've already seen that, and it's already being injected, so we're good to go there. But I also have some other things we're going to talk about really quickly, like getting to the route parameter, the colon ID. If we go back to the routes, you'll notice I have this "customers/:id", so that we could load CustomerEditComponent, and that's what we're going to do here. So I need to be able to grab that off of the route, we're going to talk about how to do that, and then we'll grab the customer and display it in the form, and work a little bit with a template form. All right, so if we come on down, I have an initial customer, this'll be used a little bit later, as we do insert operations. We have the DataService as mentioned, but I want to jump to here. When we initialize the component I'm going to grab the route, and this is called an "ActivatedRoute", you'll see it's imported from angular/router, and this represents the current route that we're on, and what I'm going to do is say "Hey, "let's go that route, grab a snapshot of "the current route parameters named 'id'," and then that id will be the value that we have from MongoDB hopefully, assuming that it's passed correctly, and if it doesn't equal zero or something else like that, then we're going to say this is an update operation, and that we're going to need to get a customer now, based on that id, and that's what we're going to be after. Now it also triggers a HTTP callback to the server to getStates, because those are now going to be used in the form, there's a dropdown you'll see, and that code is already hooked up, so we call dataservice.getStates, subscribe to the states, and we simply bind those to the states property, so pretty basic. So now what we need to do is we need the ability to get our customer. So we saw how to write the RESTful side of this, let's now use the DataService that has a getCustomer function as well. So we're going to come into our dataService, and say "Hey, let's get a customer "based on the id," and of course we want to subscribe to that value, so let's subscribe, and I'm going to get back a customer hopefully. I've already imported the interface for it. And then I'm going to do a little bit of tweaking of the data here, I'm going to do a little cloning, and we're going to do it a quick and dirty way, but before I do that, let's add an error handler, and we'll just log out the error. All right, so that'll take care of subscribing, and then just logging out an error if we do happen to get one. Now what I'm going to do here is, I'm going to clone the customer, so that if they kind of leave, it doesn't mess up any other parts of the system. There's a quick and dirty way to do this, which, it works. I'm going to just stringify the existing customer we get, and then I'm going to assign it up to a customer property, and you'll see that customer property right here, we're going to override the default value, you'll see right there. So let's assign that to JSON.parse(cust), and again, the only reason I'm doing this is by making a copy of the customer, now any changes I make won't affect the original one that was passed in. Now in this case it won't matter, but if I was doing dirty checking, things like that, it may matter, and this'll allow us to just get a true copy of the data. There's certainly other ways to do that, but that's a quick and easy way. All right, so now we should have a customer bound into this property here called "customer" up top, and so we're good to go there. So we have a way to get the customer based on the id that's passed in, we plucked that off the route, we have a way to load the states, subscribe to that. Of course, and I haven't really mentioned this up to this point, but because we're using a built-in Angular Observable, that HTTP does, we don't have to worry about unsubscribing, it'll take care of that for us on both of these, so we're good to go. All right, so the next phase is, let's come into the component, and we actually want to work with a form, and I'm going to show you two ways to do forms in this app. This first one is a template-driven approach, and then we'll also look at a reactive forms approach. So for a template-driven approach, you end up putting more code into your actual template, very little code related to the form actually goes in to here, we just get the customer, bind it, and then the rest of the data binding happens inside of the actual template itself. Now with the other approach I'm going to show you, it's kind of reversed. But in this case what I'm going to do is come up to the form, and we need to hook in some Angular features. So for instance when they submit it, I'm going to use the ngSubmit directive, and I'm going to bind that to a function that you would've seen back in the component class, called "submit", and I'm also going to add a local template variable, let's just call it "customerForm", since that's what it is, and I'm going to bind that to the ngForm directive. Now that's going to give us the ability to check if the form's valid, invalid, if it's been touched, if it's dirty, those types of things. Now, why am I doing this if you're new to it? Well first off, this'll make it so when they submit, it doesn't do a full page postback. This will let Angular intercept the submission process, and that's just simply going to call back to submit, and then we'll talk more about that later as we get into our put and post type operations that we'll be working with on the RESTful side. This is being added simply so we have a way to get to all the details about the status, or state of the form. Again, we can check if it's been touched, or interacted with in other words. We can check if it's dirty, meaning the data has changed. We can check if it's valid or invalid, and so on and so forth, really nice. Now other than that I'm using a bootstrap CSS class, and I'm telling the browser, "Don't do "any of your validation features." Now the next thing we're going to do, and I'm only going to do this on one of them, because it's a very repetitive process in the template form world. We have an input, but right now we don't know what property that's bound to, but you can probably guess, it's going to be First Name. So I'm going to come in, and first off we have to put a name attribute in this world, so I'm going to say "name", and we simply put the name that I want this to represent, "firstName", that's the property I'm ultimately going to bind to. Now to do the data binding we're going to do the input and output with an ngModel, so some people call this "banana in a box," or "football in a box," whatever you like to call it, but of course the square brackets mean data's going to come in, the parentheses mean data can go out, so we simulate a two-way data binding, and I'm going to bind this to customer.firstName. Now I also need to know if this ngModel, which is bound to firstName, if it's been touched or is dirty, or is valid or invalid, and the way we're going to do that is by making a local template variable called "firstName", and assign it to ngModel. So this is literally just going to be an alias for our ngModel directive, it lets us get to some of the properties and functions if I wanted to. And then I'm going to say that this is required. Now the reason we're doing the name, is that's a requirement, first off. You need to used that when you're working with template forms, and input controls. We're doing ngModel for the two-way data binding, to bind to firstName of the customer, and then we're doing this hash, or #firstName, the local template variable, so that we can get to ngModel functionality properties and functions. So an example of that is with my error message. We're going to hide this if firstName is untouched, because they haven't interacted yet with it, so there's no reason to show an error, or it's valid. Now if it's any other condition, if it's been touched, and then they find that it's invalid, then "First Name is required" is going to show. And so this'll let me get to the touched, untouched, valid, invalid, dirty, pristine, those types of things, and this firstName here? This actually represents that guy, right there. All right, so that's kind of how we can hook in. Now there's a lot more we could do, but you're going to see that all of the different form tags, let me give us ourselves a little more room here, are going to be the same. So for Last Name I have a name, I have an ngModel that binds two-way, and I have a lastName local template variable, and then it's doing the exact same thing here. And this would certainly be an opportunity, potentially, to write a reusable component or something, to show and hide the error message. Same thing here, I have gender on a radio button. We'll run this in a moment, I'm doing the exact same type of thing you'll see. The difference here is "name" is going to be the same, because it's a radio button, so I only want you to be able to select one of them. We have an email, an address that are the same, a city, and then State's a little bit different because it is a select, so you'll notice I'm binding to the customer.stateId, which is something that comes back from the database, and the name of "state", and it's required, but to actually get the options, I'm using this ngFor to loop through the states that we got, you saw the states property in the component, and then I'm going to use an ngValue directive, and we're going to bind that to the state's id, and that'll basically hook up that to the stateId here, so that if they've already selected a state for a customer, it displays in the dropdown. Now other than that, we have some functionality down here which we'll get to later, to show and hide a deletion message, and do things like that, but I do want to show the button to submit here. You'll notice it's disabled if not customerForm is valid. So this is a nice and easy way to use the customerForm local template variable I defined right here. Again, that's just an alias for ngForm, and all we're doing is saying, "I would like "to disable that button if it's not valid." Why would you be able to submit the form, you know, if they haven't filled everything out. Let's go ahead and save our work here. Let's go on back, now that we have our component, let's start from the beginning, so let me load this. Refresh to make sure we picked up those changes, and let's try to navigate to Marcus, all right, perfect. So now notice that we see the ID up top, I showed you how we can grab a snapshot of that, pluck it off the URL, we then go to the RESTful service with our DataService in Angular2, that loads the customer, and then we updated the customer property, which is then bound using the ngModel directive to each of the text boxes, and things like that. Now later we'll talk about how to make the Update, and the Delete, and things like that work, but hey, we have a good start. We have our states are loading, the selected state for each customer looks like it's working. If I cancel, I can go, this should show "California" for instance, so let's look, and it looks like that's working. So we're off and running here. So now we have all the get operation code in place. We have our customers, we have our states, and now we're able to select that single customer, so now we can start to move forward to other aspects, but before we do that, we're going to look at another option for building out forms.
Converting to a 'Reactive' Form
In a previous section I showed how we can take data from a component, and bind it into a form using a template-driven approach. Now in that particular approach we're using ngModel to do the data-binding, and get data in and out of the form, but the template-driven approach isn't the only game in town, we can also use a Reactive forms approach. And so what I'm going to show you is just a quick look at what that type of code would look like. So going back into the customers folder, in addition to the customer-edit.component which has our template driven approach for forms, I also have a customer-edit-reactive. Now for the customer-edit we used ngModel, so if I go down into our shared.module, we needed FormsModule to be imported to get to ngModel. You'll also notice that I've imported ReactiveFormsModule though as well, and this is going to give us this alternative approach for binding data, and getting data in and out of our forms. So if we go into the html, you'll notice some different things going on up top. We still have an ngSubmit, now the way the submit is being called is a little bit different, so I'll talk about that, but we also have this new directive we're binding to called "formGroup". Now this gets us into our reactive forms, so before I dive into the form in more details here, let's go into the code for the component, and right up top you'll notice that I'm importing some reactive forms objects. We have a FormBuilder, FormGroup, and Validators, then I also have some custom validators in this ValidationService. Now if we move on down, everything looks very similar, until we get right here, so first off, we have something called a "FormGroup". Now customerForm is my variable, it's of type FormGroup. Now this is an object that's going to have all the different form controls that I want to bind into the template, but we're not going to be doing it using ngModel with this approach, so let me jump on down to ngOnInit, and I'll show you. So first off, we still have to get our customer based on the id from the route. We still need our states for the dropdown, that part doesn't change, but you'll notice this call to buildForm. Now this is where we get into our reactive forms approach. So what I'm going to do is use the FormBuilder, which you'll see is injected right here into my constructor, and this is going to allow me to build a group of form controls. Now I could actually new up a form control instance, but this is a shortcut way to give an object literal, and then these are the names of the different controls. So I have my firstName, lastName, gender, and my, kind of standard things I need in the form. Now you'll notice that the value here in this array, the first value is going to be, "Do I want to assign a default value to this form control?" I do, I want to say, "Take whatever customer "firstName is, and bind it." Now when it first loads, customer firstName's just going to be empty, and you'll see all of these are empty, but once we get the customer, we'll update that. So this first value will be, what's the default value, and then you put a comma, and then you can define as many validators for this particular form control as you would like. Now most of these are just required, except for email. You'll notice email, I have an array of validators, and it's not only required, but I have an email validator. Now that just does a regular expression check, and makes sure it's a valid email address. Now the rest of this all looks the same though, you notice it's kind of very repetitive. Now what's nice about this is, I'm able to define, not only all the validators and default values, but all the form controls in code, so I could actually build these up dynamically if I needed to. Now I don't need to in this case, but I could. Maybe you have to do a questionnaire, and a lot of the form control data's in a database, and you don't want to hard-code what that is going to look like into the template itself, you want to make these form controls, and then have validators based on what the database says you should have. Well, we can do that here. Now what's going to happen is, once we get the customer, I'm going to call this.buildForm again, and now customer's actually going to have a value for firstName, lastName, gender, assuming it was found, and then we'll go ahead and use that and bind it into the form. Now we also have a way to get the value as they submit it, so when they pass in the value, this is going to pass in a FormGroup I'll show you in a moment, we can also check not only the value, and get to that, but we can also say, "Is this valid?" Now we'll talk more about this code a little later as we get into the PUT and POST operations, so we'll need to handle that separately as we build out our RESTful service. Now that's about it, this is the key part of the reactive forms, you actually build up these form controls, define any default values, and define any validators. Now what I need to do is, this.formBuilder.group, this actually builds a FormGroup, you'll see that up top there in the IntelliSense, so this is of type FormGroup, it's a group of form controls. Now what I need to do is hook that into the form, and the way we do that is using the formGroup directive, we bind it with our square bracket syntax, and then we bind it to that property I just showed you, customerForm. That is the definition of all the form controls. Now that's the first step. Now, what if things get really nice with this reactive forms model is, notice how clean my input tag is. I don't have to put a name, I don't have a local template variable, I don't have to put ngModel, I just put formControlName, and this firstName here actually is referencing that entire control, right there. It's not actually referencing the customer firstName, it's referencing this firstName, which is a control, and that references the customer's firstName, and has the validators. So notice I don't even have to put required on this, it's going to be added automatically through this reactive forms model. So this is really clean now, and that's the case for all of these, they're very, very simple. You'll notice all these form controls going on down, in fact, even the select is very simple. Now I still do have to loop through all the states and things, but other than that, it's very, very similar to what you saw earlier. And everything down below is pretty much the same. Now, what's different though, is notice if we go, for instance, to the First Name error message here, so if I scroll over a bit we have "First Name is required", now this is a little bit longer, but it's only because we don't have to put the local template variable, so it's actually kind of nice. I'm saying, "Let's go to customerForm," which is exposed to me as a variable I can get to throughout this form, "go to its controls collection, "go to its firstName control," which again is this guy, right here, which has this "required" on it, "and see if that control has been, "if it's untouched, or if it's valid." Now likewise if I go to the very bottom here, to where the button is submitted, I can also go to customerForm and see if the form, as a whole, the FormGroup is valid, and if it's not, we can disable the button. And then we'll talk about some of these other aspects as we move along in the course. So this is the reactive forms approach. You use the formBuilder to build up a FormGroup of controls, then you use the directive here, called "formControlName" to actually bind to the name of that control that's been defined, and then it kind of takes over from there, and handles the data binding. Now the last piece is, you don't have the two-way data binding here with the customer. So customer is not automatically going to get updated as they type into the text box, as it did with the template-driven form and ngModel. Instead what we're going to do is we're going to pass the customer form, the FormGroup of the controls, into submit, and then I've already shown what happens there. When submit is called, we can then destructure some of the properties it gives us access to. I can get to the actual value of the form, and that allows me to get to the different values like the zip, the first and the last name and those types of things, and I'll show how that's used a little bit later. And then I could also check if the form is valid or not. So this is a totally different approach, but this is another option in Angular2, and definitely a worthwhile option to explore. Now there's other courses on Pluralsight that go into more details, this is certainly not a forms course, but now you've seen both techniques for working with data that comes from our Node.js Express RESTful service.
Summary
We've made a lot of great progress so far. We now have a RESTful service that's capable of accepting GET requests up to the service with Node.js and Express, and we can return our customers, a single customer, and some states. We've also looked at an Angular service, and how it can provide reusable functionality, and use HTTP and observables to call up to the service, get that data, and then through observables, provide that to components in the application. And we've also looked at how we can data-bind our data into our components, such as our grid, and how we can use different form techniques, including a template-driven approach and the reactive forms approach. So now that you've seen how to get the data from the RESTful service, and integrate that into Angular, let's move forward and see how we can start to modify that data.
Inserting Data Using a POST Action
Introduction
As you're working with data, you'll reach a point where you need to insert that data into some type of a data source. So in this module we're going to talk about posting data and how we can handle a POST operation in our restful service and how we can actually send data through a POST action up to the server with Angular. So we're going to start off by talking about the RESTful service again, and we'll first create a POST action. I'll show you how we can define that route, and then hook it up to a function that'll get called. Which then will take the Customer's Repository you've seen up to this point, and use it to insert a customer into the database. From there we're going to then switch to the client side, and we're going to use the Http client in Angular to post a customer up to the newly created route that we're going to be dealing with. We'll talk about how we can then use that service in our template driven form. And we'll also revisit the Reactive version of the form. So we'll get some reuse going with our data service class. So let's go ahead and start things off in this module by first creating our POST action in our Express RESTful Service.
Creating a POST Action to Insert a Customer
Let's start things off by learning how we can build a post operation, or action, into our Node.js Express RESTful Service. So then later on, Angular can send data up to the service, and then the service will take that data and insert into MongoDB. So earlier we talked about how we can add begin actions into our API customers route, and what we're going to do now is handle the case where a client wants to post some data in the body of a message, and then we're going to need to write some code to extract that data out and work with it. And that's what we're going to look at in this particular section. Now a POST operation normally causes the page, if you're in a web browser anyway, to reload entirely, of course. So when I say POST operation, in this example, I'm talking specifically about an Http call that would be made from the client up, and then in that Http call, in the body, the data would be posted. So the way this would start out is on our router, we need to add the POST operation. So we can say, hey router, when a post comes into our root route, remember our root route is the API/customers, then we would like to call some type of function, and in this case it's going to be Insert customer. And then, as mentioned, I always like to bind it to this to make sure the proper context is always being used when the function is called. All right, so that's our first step. Pretty simple. Now before we go right Insert customer, let me go ahead and just put the shell for it down here. Let's go ahead and first talk about what is going to go on behind the scenes, as far as inserting that data into the database. Now as a quick review, we talked about schemas and models with MongoDB, and we talked about that there's a Customer Schema. Well, you've seen the form up until this point in the course, and pretty much this info up to here is what's in the form. So really what we're after, is we want to get that data that's going to be posted up, and then shape it in a way that matches the Schema. Now, that's going to be pretty easy because we have a model that uses the Schema under the covers, we've talked about how that actually makes that data shape in a certain way in MongoDB, and that includes inserting the data. So we're going to be using this Model Object here in just a moment. Now the code that actually does the insert, just like with the git request, the Selects, is the Customers Repository and there's a States Repository also going to be used here. Let's just on down to in this Customer Repository to the Insert Customer Function. Now you'll notice it takes the actual data, which is the body of the message, it takes the state, we'll talk about that in a moment, and then of course your callback. Now the bulk of the code is really right here, though. You'll notice I take the Model Object, in my model, my customer here is the actual model that I just looked at with the schema. And that particular object, and this goes for any mongoose object, that's a model object has a save function. So we can save it, that would give us back the saved customer, we check for errors, or we simply return the customer here. Now you'll notice, I'm actually grabbing the data, though, that was passed in the body of the request messes that came up to the RESTful service, and then that's forwarded into here, and I'm grabbing that and moving in the first name, last name, email, into the model logic properties. Now, there's multiple ways you can do that. This is probably the easiest way to do it. And these are just the properties that I need to be able to do an insert. You'll notice there's no orders here, because orders are something that, for an actual customer, you can have orders or maybe you're a new customer, you don't have orders. So that's why I don't have any orders there, but you'll notice this is all the form type data being mapped into the customer. And then we simply call save, and we're done. It's pretty straightforward. Now there are multiple ways you can do inserts and updates and things like that in MongoDB, but the save happens to be one of the easiest ways and it works very well for our purposes here. So that's actually what's going to happen behind the scenes, so now we need to write the code that can interact with that insert customer function. So what we need to do first is, I would like to come in and get the customer state, because the state is going to be stored along with the customer. So first thing I'm going to do is, let me just do a log like we've been doing, and we'll log out that we're in this particular function, that way it's easy to follow, especially while you're still developing the code. All right, now what I'm going to do is I'm going to take our States Repository, which is up above. We imported that. And I'm going to call it getStates. Now in the request body, that's going to be all the data that's posted up, you're going to have all the customer properties, well one of those is stateId. So I'm going to pass that in, and then that's going to give us back a state, as long as it's able to find it, of course. All right, now I need that because I do want the state, the object itself, that model, to be associated with the customer. Now I want to also emphasize is in MongoDB, I don't have to do that. Obviously that means that customers, if they're all in, for instance, Arizona, then they'd all be duplicating that state object. There are ways you can separate out and reference collections, but we're going to keep it pretty simple and just nest that state with each customer. All right, so what we're going to do here is the kind of standard code, so I'm going to grab our little air handling code to save on some typing. I'm going to write out that, hey we got an error, and we used that Utel inspect again to write out the error. And then notice I'm going to return a JSON object here, and we give it a status of false. Give an error, state wasn't found. And then, obviously, we weren't able to insert the customer so nothing was returned there. Now the next step is, if we did get a state there's no error, we need to come in to customer's repo and do insert customer, and then I'm going to give it the entire body, we saw that earlier, I'm going to give it the state, it's going to be associated with that customer, and then we have our callback function. We'll have our customer here. All right, so the next thing we can do then is, again, handle the error. So let me go ahead in this code, I'm just going to grab, because it's pretty straightforward code. And so we'll handle the error again. But if it did work, we'd hit this part, and notice we're going to say status is true, there was no error, and I'm just going to echo back the customer. And the reason for that is this customer we get back from the save operation in MongoDB, is going to have the updated customer id. That underscore id you've seen a few times. We don't really need it in this particular case, because once they insert, you're going to see it's going to go back to the grid and load the fresh set of customers, but maybe you wanted that for whatever reason. I'm going to leave it in here, just in case you ever wanted to play with it and get that customer id. All right, so we're good to go there. We now have our Insert customer ready to go, and we're going to first get the state, assuming that works, we'll then go ahead and call in a certain customer, pass in the state and the actual data. Again that maps the data into the customer model object, saves it, and then hopefully gives us back a customer here. So that would be our routing, going back up to the top here. We have our post requests handled, so if they post up to API customers, we call Insert customer. And then the rest is taken care of mainly by the Repository Objects, or modules that we imported up top. All right, now, how do we know if it works? Well let's go on back, and we won't know by running the app. Actually before I do that let's go to the console and see if we have any errors. Nope, looks good. Looks like it was able to retrieve data. I don't see any errors here on the server side, so that's a good start. But how do we know that the insert operation itself is actually working, because right now the client side of the code isn't ready to do that yet. So to test this out let me go to post man, and I've already loaded up the route, and you'll notice I've changed this to a post. And I have some data, so you'll notice raw is selected. Now this is a great way to test out your POST operations, later we'll talk about a PUT operation, and you've already seen me do gets or selects. So what I can do now is POST up a customer. So this is the raw body. And I can hit send, and now if we scroll down, all right, great this worked. So you'll notice that I have status is true, no error, and then here's the actual customer that was inserted into the data base. There's the id of the newly inserted customer, doesn't have any orders but does have a state. You'll notice. In this case Alabama matches, that's the state id. If you look down here, it has a state id of one. And so it looks like it works. So we are on our way. We now have a RESTful service operation that can handle a POST request, and it looks like the insert is also working in the MongoDB. Now we need to move on to the next step of the operation, and have the client actually post the data up to the RESTful the service.
Making a POST Request with an Angular Service
Now that we have a RESTful service capable of handling POST requests, let's enhance our Angular app, and add some code into our service that's capable of posting a customer up to the RESTful service. So going back into the code, I've opened up the app for folder, and I'm back in the data service TES file. Now, earlier we saw how we can inject Http in the constructor, so it's already available, as well as all my observable imports. We're pretty good to go here, as far as getting set up. What I need to do, though, is add the ability to insert. Now this is actually going to be pretty straightforward to do. There's not a lot of code we actually have to write here. So we're going to start by adding an insert customer function. And it's going to take the customer, of course, that we want to insert. So I have an Icustomer interface I've already shown, and we'll use that so we get some strong typing, and then I'm going to return observable of, and I'm actually going to return a customer. Now we need to add some code that returns the observable, otherwise you can see we're instantly getting an error here, saying you don't have a return type. Now from here it's very similar to what we've already done. I'm going to come in and return an observable by calling Http., but I'm going to use the POST. We're going to POST the data up to the server, and in this case I'm want to go to the API/Customers. And if you recall we have a base URL that already has that route defined in it. Second thing I'm going to do is give the customer that we actually want to POST in the body of the message. We'll give that. Then we want to map that data that comes back. So I'm going to map the response into a callback function. Like so, and then, of course, we always want to catch any errors. So we already have our handle error. So what I'm going to do in the map is extract out the data. Now as a quick review, if we go back into the controller, and insert customer, you can see that if it works we'll hit this else block. And I'm going to return a status of true, no error, and hopefully the customer, assuming it all works. So what I want to get to is the customer because that's what whoever calls this is ultimately expecting to get back. So first thing I'm going to do is just create a constant representing the data. So let's parse the JSON by pulling the JSON function. And then I'm just going to log what's happening here on the client side. So we'll say insert customer status, and we can write out the data status property that I just showed, which should be true in this case. If it works. And then I'm simply going to return data.customer. All right, so now we're in business, and we're able to get to that specific data. And then what the caller's really after, though, is the insert customer. They might want to get back to that data to modify it, they might want to get to the Id, just really depends on what you want to return. I could have just returned the Id potentially. A lot of times I'll do that. But in this case, I'm going to say, hey I'm going to give you back the customer, and it's up to you to do something with that customer. Now that's all we have to do in the service to now get this data posted up to the server, get back that customer, and then extract that data out, simply by parsing the JSON and then getting to the appropriate property. So now we're ready to go on the data service side. From here, we need to integrate the call into this insert customer into our component.
Modifying the Customer Form to Support Inserts
Now that we have an Angular service capable of issuing POST requests up to the RESTful service, we need to integrate that service in the call to our insert customer function into our component. So we're going to look at the customer form component that we saw earlier in the course, and I'm going to show you how we can add some insert capability to it. So going back into the code, here's the insert customer that we looked at in a previous section of this module. And we know we're going to get back a customer, but, of course, I have to send up a customer in the first place. So we're going to capture the data in the form, and then we're going to call this insert customer which will then handle posting that to the server. So I'm go into my customer's feature form, and open up customer edit component. And this is already going to have the data service injected into it. So we're ready to go there. We used this earlier for our getCustomer. And now what we need to do is add some code to handle the insert operation. Now I have a submit, and as a quick review, if I go back to the form, we have our ng submit directive as bound to the submit function. Now, because we're using ng model, in this template driven type of form, the customer will automatically be updated as they type and lose focus on the text box and things. So all we need to do is grab that customer and push it to our service, which then calls our RESTful service. So coming back into here, I need to know, though, if I'm doing an insert or if I'm doing an update. So the way I'm going to do it, in this example, is say if the customer has an id, now underscore id would be an id for MongoDB. Then this would be an update. So we'll come back and add to that in a later section. Else we want to come in and we'd like to add in the code to insert the customer. Now this is pretty easy, we already have the data service so we can get to that. And we already have an insert customer on that. So all I have to do is pass it to customer. And then, of course, we need to subscribe to the observer. Now I'm going to get back a customer we know. So we'll say ICustomer here as well. And now I need to check, what do I want to do. So if we got back a customer, I'm going to keep this pretty simple here. And actually add my arrow syntax. Then we're going to come on in and say, let's send them back to the grid. So if we got a customer, I also injected a router. Let me show you that up top here. So we have our router that's being injected, and I'm going to programmatically send them back and navigate to the root customers route. So I'm going to come on in and we'll say customers. And that'll send them back to the grid page that you saw. Now else, if we don't get that back, we probably have a problem. So I'm going to come on in, and I'm just going to write out an error message of unable to add customer. Now I'm only getting back a customer from the service, but this is where you have to decide, do you want to return the error data all the back to the component or not? That's kind of on you. The only problem with that is, if the server returns some more detailed error info, we generally don't want to just display that in an error message. In fact, in general, in production, you don't want any detailed errors coming back from the server. So we need to just be careful on how we handle that. So in this case, I'm just going to say hey if we don't get back a customer, something went wrong, and we're just going to write out and let them know, hey we're unable to add the customer. Now they can contact the help desk, or whatever it may be, and we can check the logs and things like that to see what happened. Now that's all we would have to do. Now we can also come down, and if the subscribe and the observer we're coming back doesn't work, we can add in an error handler here. And in this case, I'm just going to go ahead and we'll log that to the consul if we get an error. So nothing really fancy in this particular example. But! I'm going to put an any there. This can be any type of error. This will allow me to log the error if we get one, but if all works as far as getting back the observable, if there's a customer then hey we're great. The customer should be inserted so let's send them back to the grid, else. We'll go ahead and just write a simple message. Now the error message, we haven't really talked about that, it's just a simple property, and it's used towards the bottom of the form. I'll show you that down here. And so you'll notice we have an error message that'll be displayed right here if it's available. So real simple example there of logging the error. Now that's all we'd have to do then. So when they submit. Let me go ahead and save this. When they submit, because this would be an insert, we wouldn't have an id on the customer. In fact, the customer, when it first gets loaded, you'll see id is kind of purposefully left empty here. And so in this case it'll be empty. So that won't qualify. That'll hit our else block. We then call our data service, it handles all the POST operation. We simply subscribe to the observable. So let's go on back to the browser here, and what I'd like to do is try it out. So we have an Add New Customer you can see. Let's go ahead and just insert some test data. Now before I do that, I want to show you the data service. So I'm going to set a break point in my sources, and let's come on in to insert customer. We're going to make sure that the customer gets passed in properly. Let's also try to set one here when the data hopefully comes back from the servers. So let's input some just test data. And select a state. Let's hit insert. All right, so here's our customer that was sent up. So you'll notice we don't have an id right now, that's correct. We have our bogus test data. But it looks like that's pretty good. So let's move on. Now here's the data that came back. So we got status true, perfect. And we have our customer. In fact, I can mouse over this one, and you can see we now have an id, and that would be new id. Now what it should do then is send it back with a router to the data grid page. So let's try that out. And it looks like it did and we scroll on down here. Somewhere down here we'll have test in here. So we're good to go. I have a couple from trying it out earlier. So there we go. We have now an example of posting data up to the server, and then we have our RESTful service bill tab to extract that data out of the body of the message, and then it can work with it to insert it in the MongoDB.
Exploring the 'Reactive' Form
The template driven form in the application now has insert functionality. So let's switch gears to the reactive version of the form and see what we would need to do there to get it to support inserts. So earlier we had a submit in the template driven approach, and we checked if there wasn't a customer id then we go ahead and insert this customer. Now we can do the same thing in the reactive. So if I go into that it actually looks very similar. We come on down here to the submit. There's a little bit of code in here already. Now with a reactive one, the customer's not being bound directly, if you recall. Very different than the template driven approach that uses ng model and has that two-way data body. With the reactive, we're going to get the value of the different fields in the form, and then it's on us to do something with that. Now I'm just going to pass that along. In fact, I'm just going to paste in the code here for the else, and we're going to do the same call we did with the template driven one, but notice this time I'm passing the value. Now I'm doing a little bit of fix up work here to say if we have a customer id, well whether we do or not, let's go ahead and assign it to the underscore id of the value. And I'm also setting the zip because the form doesn't actually capture the zip. Although you could certainly modify that. Now what I'm going to do is just simply pass up that value, and then, from here, it's identical to what we saw with the template driven approach. We call data service insert customer. It's just that we're passing an object that implements ICustomer, but it's not actually the customer object. It's the data values, and it just so happens those values match up with the ICustomer interface. Let me save this. And now what we can do if we want to run the reactive form, you'd actually have to change the routing a little bit. Right now you'll see it's set up to hit the customer edit component. So I can just comment that one out, and we can switch it to the customer edit reactive component. Save that. All right, so now when I navigate to the route we'll be hitting the reactive form and you'll see that already loaded the data, but, of course, we want to do add. So let's do an add here. And let's do, I don't know, test2 or something like that. We'll put in some fake data. Now you'll notice in this case the button's still grayed out. That's because I accidentally didn't click quite right on the gender, so you can see that's working correctly now it's lit up. We'll go ahead and insert. Go to the very bottom. And there we go. There's our test2, but this is actually being driven by the reactive form now. So you can see that one of the beautiful things about services and Angular is, first off, we're getting reuse. Now you wouldn't have both forms obviously. You would have one or the other. I'm simply showing you the different techniques you can use in your Angular applications. But as you start to work with these forms, now you can choose which one do I want to use, and regardless of the choice, you can go ahead with the data service that you have and reuse that functionality.
Summary
In this module we saw how we can create a POST action in our Node.js RESTful Express Service. It can be used to perform an insert operation in the database. We also saw how Angular's Http client can be used to then issue a POST request, send up with customer, RESTful services processes it, and then we get that insert operation going. We also saw, along the way, how we can handle errors and deal with those types of things that may come up. Now one of the things that you really saw, as well, was Angular's two services are great for reuse. Now we had two types of forms, and yes, you would only pick one, of course, in a real lab. We had the reactive and the template driven, but both of them are able to reuse the Angular service, the data service that we had. And whether it's calculations, or business rules, or Http calls, services provide a great way to work with reusable code.
Updating Data Using a PUT Action
Introduction
We've seen how we can get data from our RESTful service and even how we can insert data, but we haven't looked at updating data. And that's what we're going to do in this module. This module's all about issuing and working with PUT actions, or PUT requests, that are going to flow up from the Angular application to the NodeJS Express RESTful service. Now, as we move through the course, we're going to start off by talking about how do we define a PUT request in our Express type of service. So we'll talk about that and it's going to be very similar to what you've seen up to this point, in fact, the concepts are almost identical. So it's pretty quick and easy to work with. From there, we'll move back to the Angular service and we'll add the ability to use the HTTP client to call up and make the PUT request to the RESTful service. We'll then go into our template driven form and go into the component code and see how we can then call from the component into our data service. And then we'll explore our Reactive form again and enhance it slightly to also handle the ability to update a customer and do the PUT request to the service, which then would get that data up to the RESTful service. So let's go ahead and get started by talking about adding a PUT request into our RESTful service using Express code.
Creating a PUT Action to Update a Customer
In order to handle update operations on the server side and get data updated in the database, we need to add a PUT action, or operation, into our RESTful service. And that's what we're going to take a look at in this section. So earlier we came into the controllers API customers and in this customers controller JavaScript file, we added an insert customer. Well this actually is going to be very similar to what we're going to do to handle an update operation, in fact there's only a few things we really need to change in here. So what I'm going to do is go ahead and just copy this, and then we'll tweak a few things and add a few things here or there, but it'll save us a little bit of typing. So first things first, we probably want to call this update customer. And we'll change our log statement to update customer. Now, I'm going to show you that we can also log additional info, we didn't do this for the insert, but I'm going to do a little bonus feature here. And, we're going to say that, let's write out the request body. And so we can come into here and just say req.body. And what that'll do is allow us in the console to actually see that data that's going to be updated. And we could do that with the insert operation as well, but sometimes that's helpful when you're in debug mode and just want to see the raw data that the servers actually getting. Of course, you could also set break points in the code and handle it that way too. Now we still need to work with a state. Each customer has a state associated, so we're going to pull that state ID out of the body, we're going to get the data back for the state. So if we don't have an error, we'll go ahead and leave that. Then, we want to hit this code. Now, if we go into the customers repository, you'll see that we do have an update customer and it takes the ID of the customer, the actual body, you can see the state and then our callback to get the data back. And then, it ultimately is going to save that customer in the Mongo db. Alright, so all we need to really do is call our update customer, so let's go ahead and add that. And then you saw it first off takes the ID, we're going to grab that from the URL. So params is going to allow us to, as we showed earlier, grab the route parameter called ID and then we'll pass that along. We still need the request body, we still need the state, and we still need our callback function. Now in here, if there is an error, we probably want to change this to update customer, and write out the error. And then we would, of course, say update failed and pretty much everything stays the same there. Otherwise, we'll come on down in here, we'll say update customer okay, and then we're going to do the same thing. We're going to return the customer. So there is enough here that we can't necessarily just re-use exactly the previous code, but with a few tweaks it's very similar. And that's pretty much it. Now that will automatically allow us to have an end point, but we don't have a way to call this particular end point right now. So as we've seen before, we need to come on in and work with the actual route. So we need to add a PUT operation. So POST was for insert, now we're going to do a PUT. So we'll go ahead and do a router.put and as you saw, the PUT has a route parameter for ID, so we'll go ahead and put that in. And then we're going to bind the current context of this to the update customer. So we have that, we'll bind it to this. And it looks like I missed an R on router, so we better add that. So let's open up Postman and I've already loaded up a POST that we saw earlier. So this POST already had a body, but in this case, we're going to be updating an existing record. So, we do need the body but we also need an ID so we can work with this. So what I'm going to do is, first off, let's do a get and let's go find an ID that we actually want to update. And I'm just going to kind of grab most of what you're going to see here. So we'll grab kind of from here on up. And, let's go now back into our area up here, we'll do a put. And then we're going to have to pass and ID, which I'll do in a moment. But let me come to body, we're going to do a raw, I'm just going to paste this in and then end our object literal. Or really in this case our JSON data. We'll go ahead and leave all these, we don't need the state, that's going to be found dynamically because the client won't actually have the full state, at least in the way this is being passed. The ID that you're going to see here, we can leave that but we're going to actually grab that ID from the route parameter you saw. And so, now let's change Marcus to Marcus Marcus or something like that. And so we'll POST up this customer, and see how our end point actually handles it. So let's hit send here. And, it looks like it worked. So we got back the customer, we have Marcus Marcus and same ID, of course. Alright, so that looks good. Status is true, no error. Now, to really prove it worked, we probably should go back to all the customers here, and we'll do a send. And it looks like Marcus Marcus shows up, so perfect. So, of course, we could go back to the PUT if we want to fix this. Go back to the body, change it back. And now we can do a PUT operation again up to the server. And what we get back should just be Marcus. So it looks like our RESTful service is now capable of handling a PUT request. So now we can move forward to the client side and start calling this.
Making a PUT Request with an Angular Service
Our RESTful service now has a way to handle PUT requests that come up to the service, so now we're going to switch our focus to the client side, and add the capability to make a PUT request from an Angular service. So, in a previous section of the course, we talked about how we can do an insert operation with a POST. And you're going to see that doing something like a PUT operation, which is really an update in this case, is pretty much the same type of thing. Now, of course, we're not going to use POST, we're going to use PUT, but everything else is very, very similar. Let's go ahead and add this. So I'm going to make a new update customer and this is going to take a customer object of type I customer, and then it's going to return observable, as usual. So go ahead and do an observable of, and then we can return whatever we'd like here. Now we'll return observable of I customer. Alright, now in here, all we have to do is simply do our HTTP PUT, so we can do our return HTTP. And this will look really similar, but what we're going to do is we need to pass the URL, so we're going to add a little slash here, and we're going to add customer._ID which is the Mongo ID. Now the second parameter is going to be our data, and that's going to be the customer, that's very similar to what you'll see up here in the insert. So really no change there. And then, we could add other things, options, and we'll talk about that a little bit later. For now though, we're going to come on in and we're going to add our map and we'll add our response again, and then we're going to add a little bit of custom code in here, we'll come back to that, and then we'll add our catch. We'll call our handle error. Let's first off grab our data, so we'll say const data, and we're going to parse our JSON again, just like up above. And I'm going to do a log here just so we have something to refer to when we do run it later if we want to. So I'll say update customer status, and we can write out the data.status. Now if you remember, we get back a status, an error and we get back the customer data. Alright. And then, we're going to return data.customer, okay. So that's why we have an observable of customer just like we had up here. So you could see that this is a very, very similar piece of code to what we had up above, and we could probably even work with automating this a little bit more, but we'll break it down piece by piece here again. So, we return the observable, but this time we do a PUT. Now a PUT, of course, only works when we're doing a HTTP type call. Of course, you can't do PUT with regular forms in the standard web world. But in this world, you can. So if you haven't used PUT before, this is our way of saying, hey, I'm not doing an insert, a POST, I'm going to do a PUT operation. So we go ahead and add that customer on up there. Then we do the same thing. From here, you've already seen this, we parse the JSON, do some logging and then return that actual customer here. And we catch the error. So that's really all we have to do. So now we can move to the component level and we can consume this update customer function.
Modifying the Customer Form to Support Updates
Earlier, we enhanced our Angular service to support a PUT or an update, so now what we're going to do is consume that update customer function that we added in one of our components, so that we can actually handle the update as the user edits a form. So before we jump into the component, I want to emphasize one thing, and this has been mentioned a few times but it's important to address. We're doing some really basic logging in our data service here, and this is an opportunity where we might even have another HTTP call where we log some of these messages back to the server. So we'd have to set up a separate RESTful service for that, but we could certainly do it. Now the reason I'm mentioning this is, in my opinion, the service is really the place that should be logging whether it's local or calling back to the server with the data. The information about what happened, in this case with the PUT request, I want the component to either get a customer or not get a customer. It's really up to them do deal with that. But at the service level, we want to be very specific about what happens when things break and what happens when things work. Now in this case, I made the decision just go ahead and return the customer, but you may say, "No I don't want to do that, "I want to return the raw data, for instance." and, that would certainly be a valid option, now the component would have to know to go to the customer property, but they would have access to get to the status and the error message. Now, that's something you would have to debate and determine in your own world and own applications, how you want to handle. But, I'm going to go ahead in this example, and just keep it as is, and we're going to return this I customer back. So now what we're going to do is back in our customer edit, that we've seen, we already have the functionality to do an insert customer. And so we're going to do this same type of thing. When they submit the form, the submit function gets called here, if they have an ID on the customer, then that means we already have an existing customer and therefore we probably don't want to do an insert, we want to do an update. And so now we can call into the code and actually do this. So we're going to use our data service that's already been injected. We'll call our update customer and we're going to pass the customer that we have up towards the top here of our component. So this will actually be, not this instance of the customer, but if we had a customer earlier when we get it, that's what would be displayed in the form and that's what the customer would represent, of course. Now we're going to do a very similar operation to what you see down here, actually. In fact, I could probably cut and paste most of that, but we'll go ahead and type this one out. So I'm going to subscribe, and this is going to get me back, as we just showed in the service, an I customer. So we'll go ahead and add our arrow function here for our callback for the subscription. And then we can also have, I showed this a little bit earlier, we'll take that out and we can have kind of an error function at the bottom of this, where we could do some additional logging that might be just specific to the component itself, though. So we'll just do a console.log error. Now, obviously, the error logging here is pretty basic, but this is where you could take it to a whole other level and you could from here call back to the data service which then logs an error. But I think the data service, because it already knows if there's an error or not, should be responsible for that. But, you know, that is very subjective. So in here we'll say if we did get a customer back, then that's a good thing. Because if you recall, the RESTful services, if there's an error does not return a customer. So we'll go ahead and do the same router navigate, and we're going to navigate, basically, to the root type of route, the customers. Alright, that'll take care of if it works, now if it doesn't work, we'll put our else and we have this error message property, let me just scroll up to that as a reminder. We have this error message property that's actually bound into the UI with a component. So we're going to go ahead and update that error message with our error message. We'll just say unable to save customer. Okay, so now we have all the code we need to consume the update customer function that data service provides, we subscribe to that observable we get back. If we get a customer back that means things are good. We're going to go ahead and navigate back to the grid, the home page, if you will. Otherwise, we're going to go ahead and log some type of an error, and in this case it'll actually display it though, to the UI. And now we're ready to rock and roll here. So let's go to the form itself. And let me refresh to make sure we pick up all the changes. Let's go back to our Marcus Hightower here. Alright. And let's just do Marcus2 and maybe Hightower2. Come on down, it's an update. Go ahead and save it. And looks like it worked, but, I always like to double check. Let's refresh, yep, looks like it took. And we'll go ahead and fix it back. Alright, so our update is working. Beautiful. Now, all that's happening for the update button, earlier we saw an insert button, but I have up here in the component an operation text. Now, it defaults to insert, but when we get the customer, if we have an actual customer with an ID on it, in other words, the route up at the top has that ID which I'll show that in a moment. Then we're going to change that operation text to update, and that's all I'm doing to dynamically change the text and the button. So if we come down to the button itself, you'll see down here we have our submit button and it simply binds to the operation text. That way I don't have to have two buttons for an insert or for an update. Now, the other thing we're doing is as we run this, of course, we have our routing. So you'll notice as I click it, there's our route parameter ID. And, of course, that's how I'm determining to change the values. So if we go back into here, I grab a snapshot of the params, we talked about this earlier, if it's not a zero or basically some other item, if I do an insert, I always pass a zero up there that's why I'm checking for zero. But if it's not, then we're going to go ahead and change it, update it and get the customer. So, that's why the button is changing very easily between update and insert and things like that. So there we have it. We now have a submit function that's all filled out now. If we have an ID, we can do our PUT to the server, our update. Else if we don't it's an insert. Now we still have some new functionality we're going to add into this later, but we're starting to make some good progress now.
Exploring the 'Reactive' Form
The final piece of code we're going to explore is enhancing the Reactive form to also support the update capability that we now have available on our RESTful service. Let's jump on into that and explore what we can add there as far as code goes. So, as with the template driven form, you'll see that we have a submit and we talked earlier about how in the Reactive world, you can get access to the actual value which is the different form control values and whether the forms valid or not. And we'd already added the ability to do an insert. Now you'll see this set up in this type of form is identical to the template driven that we did earlier. With the submit, I check if there's an ID. If there is, we're going to do our PUT request to the service, otherwise, we're going to go ahead and do our POST, our insert. Now to make this part work, we can come on in and I already have some code here because it's very similar to what you saw earlier. So we're going to do the same thing. We're going to call into the data services update customer and pass in the value. Now in this case, again, the value is of type I customer, so we're really passing the customer, it's just slightly different in how we do it with the Reactive world. And then, we're going to get back some data. Now, previously I was returning the status. Now if you remember, we have the ability to get back the status, the error and the customer. But, I mentioned earlier in a previous section in this module, that I like to have the component kind of be in the dark, as neutral as possible about errors and things. And so, instead, what we can do is we can return the customer again and you'll see this is pretty much identical to what we did down here with the insert. And that way, the components only worried about if it gets a customer or not, the service itself will take care of logging and things like that if there's any errors as it communicates with our RESTful service on the server side. Alright, so now that we've seen that and added that code, let's go on back to our form. And I'm going to reload it back from the home page here. And right now this is the template driven. So let's go back and what I'm going to do is come into the routing, we'll come on down here to our app routing, and right now you can see our customer edit component. Let's go ahead and change this. And we'll comment in the customer edit Reactive. Save this, and reload. And we should see the same type of functionality. So now we'll click here, now it's the Reactive form. We'll do update and let's refresh just to make sure it took. Looks like it did. So you can see that whether or not you choose the template driven approach or the Reactive, the code itself for interacting with the POST or the PUT, or whatever it may be type of request to the service, doesn't really change much. What changes is, obviously, in how you write the form and how you work with that form. But it's kind of good to know both approaches and that way as you work with these, you can see that the code itself is very similar actually. So that's a quick exploration of the Reactive form for editing our customers.
Summary
In this module, you've seen how we can work with data updates. We started by talking about creating a PUT action with our NodeJS Express RESTful service so that we can update our data in the database. From there we learned how we can use the HTTP client and Angular service to call HTTP.PUT, get that customer up to the service and then perform that update operation. And then we saw how that service is then reusable again across our template driven form and our Reactive driven form. And really the code there was very, very similar between those two different form styles. So up to this point in the course, you've now seen how we can create GET type of actions and PUT and POST, but we haven't talked about deleting data. And that's what we're going to work with next.
Deleting Data Using a DELETE Action
Introduction
In this module, we're going to look at how we can add DELETE functionality into the application. So we'll work on DELETE functionality, of course, on the server side and the RESTful service, and then we'll go back to the Angular application and add DELETE functionality there as well in our data service that we have, and in our different forms. So as a quick overview, we'll start off with a DELETE action added using Express, we're going to create a route that takes an ID, and then we'll map that to a function that's going to be called, which will then handle deleting that customer from our MongoDB database. We'll then take a look at how we can use our Angular service to issue a DELETE request using an Http client. From there, we'll then modify our customer form to support deletes, make that delete request, which then calls the RESTful service. And then we'll also explore our Reactive form, and see how we can get that going with the DELETE operation as well. So let's kick things off again by starting on the server side, and getting DELETE functionality into our RESTful service.
Creating a DELETE Action to DELETE a Customer
In addition to handling GET, PUT, and POST operations, our RESTful service can also handle the DELETE action. Now this again is an action that you wouldn't use with a standard web app, with a form tag and things like that, but when it comes to different clients calling up to the RESTful service, we can let them specify these different types of actions. And in this case, we're going to focus on how to work with DELETE. So going back into our API, customer's route, and the customers.controller, we've already added several GETs and the ability to insert an update. So now we need to add a little bit of code so that we can handle our DELETE operations. So we can do that the same type of way. First thing I'll do is, let's come down below the update that we already added, and let's add a deleteCustomer, and it's going to take our request and our responses again. Now this particular DELETE operation is going to have to have a route parameter, we have to have the ID, of course, of what to delete. So, we'll go ahead and do that by calling into our CustomersRepository, I'll look at that in just a moment. But let's come on in first, and we can say console.log, like we've been doing, and we'll say deleteCustomer, just so we can know when it's called. And then we're going to use the customersRepo that we've been using throughout the course, so let's go back to that. And if we come on down here a little ways, you'll notice that we have a deleteCustomer, and that simply uses our Customer model to call remove based on the ID that's passed in. So we need to grab in the controller, the ID, pass it into here, and then it will take care of handling the DELETE operation. Alright, so that's going to be pretty easy actually, most of the work's done for us. So we're going to say, customersRepo.deleteCustomer, and we need to grab the ID off of the route params, we've done that before, so that's going to look like this, .params.id, and in this case I really don't have anything that's going to be passed back except for potentially an error, so I'm going to make my arrow function for that. And inside of here, now we'll handle if there's an error. Now, so we'll do like normal, we'll say, if there's an error, we'll go ahead and do a little bit of logging, and let's go ahead and log out something like, deleteCustomer error: and I'm just going to grab what we have right up here, so we're going to do the same thing. Alright, and that'll take care of that piece. Now in this case, I'm just going to return a simple status code. We certainly could return the error and all that, but either the DELETE worked, or it didn't, and the server side would log any errors that occurred, of course. So in this case I'm just going to say, let's just return a status, and the status here would be false. Now if it works, in our else, then we're going to do a true, so let's go ahead and just get that out of the way. And we'll do true, and we'll be kind of good to go on that particular aspect. Alright, so now that we have that available, we need to test if this works or not. So first thing, let's do our log again, and we'll say that our deleteCustomer ok worked. Now we have the ability to, first off, call deleteCustomer, we'll log that out, we'll then pass the parameter, which we're going to have to make in a moment, for the ID, into this deleteCustomer. If it returns an error, we'll go ahead and log it, and it just returns a status of false, otherwise we'll say true. Now, if we wanted to return a custom error, remember we had an error property, you'll see it right up above here, and we can certainly add that. So we can say error:, you know, 'Delete failed'. Now that's not going to give too much info, that's why the false in this case is probably all we need. But if you want to return more, we certainly could. Okay, so that kind of takes care of our deleteCustomer. So now we need a way to call this when the route comes in, so we'll come back up to the top. And we'll, on our router, say, when there's a delete, and it has an ID on the parameter here, on the URL, let's call deleteCustomer, and then we'll bind it again to this, just to make sure that the proper context is calling it. Alright, so now we have our two ways to GET, we can get all customers or single. We have a way to insert, we have a way to update a particular record, and we have a way to delete a record. Now, as usual, we need a way to test this. So let's go ahead and open Postman, and we'll give that a shot. So I've already issued a GET request, you'll see, to bring back all of the customers, so I'm going to scroll down to the very bottom record here. And in this bottom record, we'll have some kind of fake sample data. So you'll notice we have this James Dan, which is a record we're going to delete. So I'm going to grab this, and as we know, this route now has an ID route parameter, so we're going to put that up there. Change this to a DELETE operation, and this should now hit into our DELETE route. So let's go ahead and try it out. Alright, so we got back "status": true, that's good. Let's go back to the GET. Let's actually on the GET though try to get by ID of the same ID I just deleted, and you'll notice we get back null, we don't get back anything. So looks like the DELETE operation did indeed work. So you can see that the code is very, very similar for all of these, whether it's a GET, POST, PUT, or DELETE. Similar concept, but now we have the ability to perform these different CRUD, Create, Read, Update, and Delete operations, and you can see that also in our controller, if you will, for our RESTful service, everything is staying pretty tight, pretty small. We have thin functions, we don't have a lot of code in there, and we're going to delegate off as we've been doing the entire course to our repository layer. So that'll get us started, creating the DELETE action that's going to be performed on the RESTful service side. Then we need to add that into the Angular side. So we'll move to that next.
Making a DELETE Request with an Angular Service
Our Angular service is progressing nicely. We have support for GET, PUT, and POST operations, but we don't have support for DELETE yet of course. So we're going to add that now, and you're going to see that the same exact methodology we've been following throughout the course is going to be employed, so this is pretty simple, you'll see. So in the data service, we've seen our GETs, we've see our POSTs, and we've seen our PUT, but we don't have our DELETE. So let's go ahead and add that quickly. So we're going to add a deleteCustomer, and we'll of course need to know the ID that we want to delete. We need to pass that up to our RESTful service, that's a MongoDB ID, so it's going to be a string in this case. And then we're just going to return an Observable here, and the Observable is just going to be a Boolean. We have that status that's going to come back, so we'll go ahead and return that. Alright, so we have our observable a Boolean, and we're kind of ready to go, but we don't have anything returned, so let's go ahead and do that. So we're going to do http.delete this time, and I can really just grab this particular section and tweak it to save a little typing. So we're going to pass in the ID, of course, so we'll grab that api/customers, add on the ID that's going to be passed up to us, then like usual, we'll go ahead and do our .map. So we'll get back our Response. And in this case, the Response is going to be very, very simple, we're just going to parse that JSON, and return the status code back. Then we'll add our .catch as well, we'll do our handleError. So very, very simple operation, especially compared to some of the others we did. But we pass in the ID, we pass that ID on the URL, the RESTful service, of course, will then pick that off using the params option on the server side, and we're using the Http client's delete operation, or delete function here to do it, and then the rest is really the same as what we've been doing before. I'm just going to grab the status this time and return that back to whoever it calls. So now we're all set up for a DELETE operation, you can see that's a pretty simple one to add into our Angular service. So we need to add the code into our components that can call this now.
Modifying the Customer Form to Support Deletes
Now that our Angular service supports a DELETE type of action, let's go ahead and modify our template-driven form to support DELETE. So back in the CustomerEditComponent we've worked with several times throughout the course, we already have the GETs, and we have the ability to do our submit for our UPDATE, or our INSERT, but we don't have a DELETE at this point. We have a little delete option down here, you'll see it towards the bottom. But we don't have anything in that, so we're going to fix that. So the first thing I'm going to do is, when we delete, I'm going to go ahead and say, if this is called, we're going to get this event object, and I'm going to take that event object and make sure that we don't bubble it up. So we can do that by saying event.preventDefault, and you'll see that, actually, right above as well. If you haven't encountered that before, it just ensures that no parents also get the event. It kind of cuts it off, so it's not going to move on up, and it'll make sure that nothing else fires. Now the next thing I'm going to do is call into the database service, so this'll be pretty simple, and very similar to what we did for the GETs and the INSERT and UPDATEs. We're going to call our deleteCustomer that we just added earlier, and I'm going to pass in the customer's underscore id, which is the MongoDB property. And then we're going to go ahead and .subscribe to the observer. So, very, very similar, we know we get back a Boolean. And we'll make our arrow function here. Alright, now, before we go too far, I want to also add my err. We'll say that's an err of any, or you can leave that off in this case, either way. And we'll just log that. Alright, so now what we need to do is really very similar to what we see up here. In fact, I'm going to grab this code, paste it on down, and we don't have a customer, we have a status. We're going to say, if the status is good, if it worked and we're able to successfully delete the customer from the server and the database, let's go ahead and navigate back to the homepage, we've seen this a couple times. Else, let's write out, 'Unable to delete', our 'customer', and then let me add my missing paren right there, fix that. So now we're good to go. We have a DELETE operation that can be called, but we're also going to need to add a little bit of code into the template, to make sure that we can confirm, do you really want to delete this record. So I'm going to show you what we're going to do there. So we're going to jump to the template for this component in just a moment, but let me show you something up here on the properties first before we move too far. So you'll notice this deleteMessageEnabled, and this is going to be something that's going to be set through the UI, through the template, and I just want to call that out right now because you're going to see it here in just a moment. Alright, so what I'm going to do now is, we have the DELETE operation in place, let's go to the template, and there's a little area here for some delete code. Now, I could pop up a modal dialog, and those certainly work fine, and I think that's what most of us are used to. I'm going to show you a little, maybe more simple technique that I actually like better, because with a modal dialog, the user has to move their cursor somewhere else, maybe far, far away, it could be up at the top of the screen, for instance, from where the actual delete button was. I'm going to show you how we can add in not only a delete button, but how we can also confirm, do you really want to delete this, without actually using a modal dialog, but it'll still get the job done. So I'm going to go ahead and grab a snippet that I have here rather than typing it all, and we'll talk through this. So I have just a div, and you'll notice in this div, I'm only going to show it if we have a customer._id, because if we're doing an insert, it would make no sense to show a delete option. And, deleteMessage is Enabled. Now I already showed you that, that goes back to this property right here, which is false right now. So when this first loads, if there's a customer ID, and deleteMessage is enabled, which it's not right now, then this'll be hidden, of course. Now all we're going to do here is have some buttons, we're going to have a button here, that it's going to have a Yes, and if they click that, that's going to call into our delete. We'll then pass the event object in. Otherwise, if they click No, we're going to set the deleteMessageEnabled back to false, you can see. Now, in order to set deleteMessageEnabled to true in the first place, the user needs to click on a delete button. So I'm going to add another little snippet in here, and this will be our delete button. So again, if we have a customer ID, it's not an insert, and it's not enabled, the delete message is not enabled, which would be the case when this first loads, then when they click, and we bind to the click event, we're going to set that to true, the deleteMessageEnabled. That of course is then going to show this, now it's going to be up to the user to click Yes or No. If they click Yes, then we kick off the process we just added earlier, and we call our DELETE, that'll call into the Node.js RESTful service, and we'll be off and running, and can delete, and then hopefully go back to our homepage in this app. Alright, so we have that all ready to go. We have our delete functionality in our template now, we have our delete code, we have our service, and then we have our RESTful service with the route that should handle integration with MongoDB. So let's go back into our application, let me refresh now. And let's just click on a customer, we'll go down and see if we have any test ones. You'll see that I have a bunch down here. So we'll go down to test. Looks like we have some data, so that's good. And you'll notice Delete shows up. Now, if, just to show you, if we hit Cancel, and Add New Customer, notice Delete does not show up. That would make sense, and that's all we're doing in the template I showed. It's either showing or hiding the Delete button based on if there's a customer ID. Now in this case, I do want to delete, so let's go on down and we'll go find the test data. Alright, so we can edit it, or we can hit Delete. Now, normally when you hit Delete, you'll see a lot of apps pop up a modal, and again, there's nothing wrong with that. But I kind of like not having to move my cursor very much at all. And so if I hit Delete in this case, you'll notice it hides everything else. It's right where my cursor was, and then the user can select Yes or No. Now if they hit No, that just resets the Delete option, back to false, and we're back to where we were. But if they hit Yes, then this of course should call our deleteCustomer, which calls into our service, which calls into the RESTful service and passes the ID. So let's hit Yes, and we got redirected. Now I have a bunch of tests in here though, so, you know, who knows? There is several, but we can actually clean up all of these very quickly now, and you'll see everything's working. Let's delete this last Test. Alright, and we're good to go. So this is a really nice way in my opinion to let the user delete a record, and confirm or deny that, but not make them really have to jump around the page much, and, you know, click on a modal dialog or something that maybe pops up up here, or over here, or wherever it is. But you know, that's all very subjective to how you like to do your UI. I happen to like to keep the user in the general area where they can either hit Yes or No, and you know, then it's up to them what they want to do. So there you go, there's an example now of a template-driven form that, now we have all the CRUD operations. We can insert a new record, we can obviously edit, and update, and then we can also delete that record as well, and so we're getting pretty good here on our template-driven form. Now, of course, we have our other option, which is, if you wanted to choose the reactive forms, we need to enhance that as well, because you would choose one of those in your app. So let's go ahead and look at that next.
Exploring the 'Reactive' Form
If you wanted to get the delete functionality available in the reactive version of the form, then we can literally take the same exact code that we just did for the template form and just move that over to the reactive form, and it would be ready to go. So let's take a look at that real quick. So back in our template-driven form, we added our delete. And we have this same delete function already in the reactive, so I'm going to go ahead and just copy this code, move over to our reactive, and you'll notice the same delete is here, and just paste that in. That's literally all we would have to do, and then, of course, that's going to call the RESTful service, so there's really no other chains that we have to do there. Now if we go into the template of the reactive form, it's also identical to what you saw earlier. We have this deleteMessageEnabled, if that's true and there's an ID, then that means they've clicked the Delete, and they can then click on Yes or No, that then calls our delete. And then we have the same exact delete button that'll only show if there's a customer ID and not deleteMessageEnabled. And then that will set that particular property to true, and start this process of approving or denying the delete request. So on the reactive side, the code itself for both the component code and the template code is really identical to what you saw with the template-driven form. And if you wanted to get this going again, you simply have to come into the routing, comment out the template-driven one, start this up. And now we can come on in and refresh, I'll come on down here to one at the bottom, like Test2, there's our Delete. And we can hit Delete, and there we go. Now the reactive form is also handling our DELETE operation. Again, another example of reuse of code in our application, and I want to re-emphasize, of course, you wouldn't have both these forms. I've said this a few times. This is just to show you both types of forms, as we're integrating Angular, into our RESTful service.
Summary
At this point in the course, you've now seen the complete CRUD operations integrated into the RESTful service and the Angular application. You've looked at the GET, the PUT, the POST, and now we've looked at how we can create a DELETE action. We've also seen how Angular's Http client also supports DELETE actions. And we've taken a look at a different way of allowing a DELETE to occur, rather than showing a modal, which is completely valid, of course. I showed a different technique where we could just show the Yes or the No for the deletion right there inline in the page, and minimize the amount of cursor movement that the user has to do. Certainly not the only option, but a different one, and it shows off some of the Angular features with data (mumbles), and easily showing and hiding sections of a page. So at this point, we have our CRUD operations wrapped up, but we still have some more to work on. So we're going to talk about some additional bonus features in the next module.
Data Paging, HTTP Headers, and CSRF
Introduction
In this module, we're going to take a look at headers and the role they can play when it comes to working with data and also some security features to prevent different types of hacker attacks. So we're going to start off by talking about how we can add a paging header into our RESTful service so that the response that comes back can say the total number of customers available, even if only a handful of customers are retrieved by the client. That way we can start to build out some paging functionality, access the headers in our Angular service, and then build a component that can handle paging, and I'm going to show first off how we can add the paging support from a code standpoint, then we'll talk about how we can add a custom paging component to allow the user to select which page of records they'd like to access. From there we're going to talk about something that all RESTful services and really any service that allows users to change data should have in place. We're going to first talk about CSRF, Сross-Site Request Forgery, and explain what it is, and then I'm going to talk about how we add in some functionality to block these types of attacks, using a node.js module called csurf. From there we're going to talk about how we can access a csurf token in Angular and how Angular supports using CSRF tokens and working with them out of the box. I'll show you how to get all of that going and how it works. So let's go ahead and get started by switching to our RESTful service and see how we can add some paging functionality.
Adding a Paging Header to a RESTful Service Response
Currently our application displays all of the customers as the user goes to the homepage in Angular, and what we're going to do now is add some functionality into our RESTful service that will allow paging operations to occur. So we're going to make it so that a client, whether it's Angular or another client, could pass up the number of records to skip and the number of records to take, the top. Then what we'll do is use mongoose to call mongodb, do a paging operation there, and then return back those customers to the client, and we're also going to set a header that represents the total number of customers. So let's jump into the code and I'll show you how we can do this on the RESTful service side. So we've already seen our getCustomers, and this method currently gets all of them, so we don't really have any paging operations at all going on here, we're just grabbing all of those particular records. Now, what I'd like to do is change this and add a new route up top so that in addition to getting all of the customers we can actually get a set of paged customers. It's going to look like this. I'm going to come in and say router.get, and then we already have our api/customers and I want it to be /page, and then we can pass in two route parameters. One is going to be how many records do we want to skip, and then how many records do we actually want to grab from the remaining. So we're going to come in and use the colon syntax very much like here, and we're going to first say :skip, :top. Now, top is really the page size but in SQL, a lot of SQL languages will have a top command to grab how many records you would like. So we're going to go ahead and pass that in, and then this will bind to a new function we're going to make, and then we'll do the bind to this again. Okay, so now we have a way to have a different route that's going to call this getCustomersPage and we need to make that. So we're going to do something similar to what you see up here, but now we're going to use a new customers repository function that I have available. So let's look at that first, and then we'll come back and make our getCustomersPage function. So in our repository I have a getPagedCustomers and notice it takes the number of records to skip, the number of records to grab, the page size, and then of cause the callback. So what I'm going to do is first off get the total number of records and we do some logging here. So we use a mongoose function to call a count. Once I have that, I'm then going to do the pagedCustomers, and so we're going to call find. We don't find anything specific though, grab all of them, but we're going to sort by last name, we're going to skip a certain number of records based on what's passed in, and then we're going to limit or page those records, grab a page size. Now what I'll return to the callback is the total count, because we need that if we're going to do paging, especially on the Angular side. Once we get into our pager component we need the total number of records. And then we'll return the paged customers, that's what the customers will represent. So this is the mongoose way of actually doing some paging operations. It's pretty easy to read, kind of reads like a sentence if you read from top to bottom. Now we can come on back and let's add our function down here for the getCustomersPage. This is going to be very similar to what you see above, we'll just use that different repository function. So we call this getCustomersPage, and what we'll do in here is first off I'm going to do my standard logging, but we need to grab the route parameters, the skip and the top. I already have some code for this to save a little typing and we'll talk it through. So I'll do our standard logging just so we can see what's being called, and then what I'm going to do is go to the params and grab the top and the skip and just assign those. Now, at this point these aren't numeric and they might not even have values, so what I'm going to do is say if the top or the skip is not a number, let's go ahead and give some defaults. We could certainly throw an error instead but I'm going to try to be helpful to the caller. Otherwise I'm going to use a little JavaScript trick that we've seen earlier with a plus to convert a value into a numeric value, and so that will convert these into numerics, and that's actually what mongoose and mongodb want as we do the paging operation. Now the next thing we're going to do is use the customersRepo and we're going to call now into our getPagedCustomers. So we go ahead now at this curb, and this will be very similar to what we've seen before, but I'm going to show one new feature that we haven't seen. So we're going to call getPagedCustomers, we're going to pass in our skip and our top and our callback. Now notice in the callback which will get us our data, which has our count and our customers, I'm actually going to set a header representing the total number of customers. Now, I could certainly return that total number with the actual paged customers here. Often times it can be cleaner to use headers in this scenario to pass back the total number of records, and that way the client really only has to worry about the paged customers, and if they want to get to the total, they can read from this header. Now, the header can be named anything you want. I always start my custom ones with X-, that's a pretty common technique you'll see. But you could literally name it whatever you want, but in this case Angular is now going to need to know about this header name and you'll see that a little bit later. So we're going to pass in the data count and that's how we can set a header. On the response it's going to go back down to Angular from this RESTful service. Now aside from that it's really the same code that we did up with getCustomers. If we have an error, we're going to log it and return null, otherwise we're going to log and just return the route customers. So different techniques can be used here certainly, but with the header we can kind of keep the total number of records out of the route data, instead let the client choose if they want to get to that. Alright, so let's go ahead and save that, and let's go now back into our console, make sure that everything looks good. Okay, I don't see any errors there. And now what I'm going to do is jump over to Postman, and we know that we can get all the customers, that's currently working. But let's see if we can just get one or two customers. So we need to go to our route. So I have /page, and then let's go to what you see right here, I have preloaded page, and let's skip zero and grab two, or take the top two. So let's send those and there we go. So we get Michelle Avery and there's the end of Michelle's orders, and then we get Ward Bell, and we're done. I have to scroll down to see, but notice we get two. Now I could say skip zero but grab 10, and now we'd have 10 records. You can see that we have quite a few more records now. This will allow us now to page our customers. So we have all this now going, and going back to the code then you can see it's very, very easy to set headers with no js in our RESTful service so that any client can now get the total number of records. So now that we have this in place we need a way to display those page records, and we'll start moving into that in the next few sections in this module.
Accessing Headers and Data in an Angular Service
Now that the RESTful service is capable of paging customers and returning the header with the total number of customers available, we could switch our focus to our Angular service, call up to that RESTful endpoint, get those customers and make them available to any components in the app that need them. So going back into our Angular data service. We already have the ability to get customers and we've been using that throughout the course to display those customers on the homepage of the app. What we're going to do now though is switch to paging the customers. So we're going to come on in and add a new function here and we're going to call this function getCustomersPage. Now it's going to take the page that we're on to be the number zero, one, two, three type of thing, and the page size which is really our top, how many records do we want to grab. And then from here we're going to call into the RESTful api, so we need to make a URL. Now because I have a need to embed multiple variables into a string to compose the URL, I'm going to go ahead and use ES2015 string template functionality here. You're going to see that right now. So I'm going to say we want to make a get request, but instead of using the normal quotes, apostrophes, or quotes like this, I'm going to use the tick which is an ES2015 feature, and we're going to embed the URL this way for the baseURL that'll be our api/customers. Then we can go ahead and just keep typing here and embed the page using the template syntax again, and we can embed the pageSize, and get that going and available. So I didn't use that like down here because when it's a simple thing I think it actually makes it harder to read, but in this case it makes it nice because I don't have to put a lot of pluses and I don't have to get all that concatenation going and available. Alright, so we'll have the baseUrl, which is our api/customers you'll see up top. We're going to concatenate that in with page and then we'll grab the page variable, embed that, and the pageSize and embed that. Because this is going to work with cooperation and observables, we need to do our map, we'll get back our Response object. Now I'm also going to come in and do the standard caps that we've been doing the entire time, so we'll add our handleError. In the map we need to do a little bit of custom things. First off I'm going to grab the customers, we'll say let customers as response.json, that's what we know we get back, either null or the customers. But what I'm going to do is above that grab the total records. Now this means we need a way with Angular to get to that x inline count header that I've mentioned. So we're going to say const totalRecords and it's going to be equal to, and I'm going to convert this into a numeric value, the response headers, and then we can call it get to get into the headers. This is pretty easy to do once you know how it works. We can say x inlinecount, and on the server side it was actually a little more uppercase and spots but it really doesn't matter here. I could match that if I wanted or not. Now that's going to grab that header, convert it into a numeric value, and now we'll have the total records and we also have the customers. Now, with the customers, I need to tweak them a little bit, and that's why I'm doing the let. If you recall earlier in the course, we called calculateCustomersOrderTotal, and that iterates through all the customers and basically adds their order totals up, grabs all the orders and totals. We're going to come in and do the same thing there. So we'll grab these customers like this and just paste that down, and that will take care of that part. And now what I'm going to do is return not only the customers but also the total records to any component that calls into this service. So we're going to put our return and now I'm going to say results is the customers, but the total records is the total records that you see right here that we got from the header. So now we have a getCustomersPage in our data service and any component in the application can now call into this and use it. So that's how we can actually create the functionality to get the header, grab the customers, and then return those. So the next step would be to have a component, call into this, so that we can get these page records, and it, of course, is going to need to pass in the page and the page size for the number of records that we want to grab.
Adding Paging Support to a Component
Let's start to add some paging functionality into our component that's responsible for displaying the customers in the application. So the existing customers component, this is the one that is used for the homepage of the app, already has the ability to store customers and filtered customers, we talked about that earlier. But it also has two properties, total records and page size, and you'll see that we have some default values there. So what we need to do is our data service that we just looked at earlier is going to return the total records, we need to store that here. And then of course page size we're setting to 10, but that could certainly be dynamic, as well, if we wanted. But currently the application isn't using paging. Instead what it's doing is actually coming in and getting all the customers, and that's okay for now, but obviously we didn't go to the trouble of creating that on the server side to not use it, so we need to fix that. So what I'm going to do is come down below and we have a getCustomers and we can go ahead and leave it, but right above it I'm going to add a getCustomersPage, and this is going to take the page of customers we want to get, page one, page two, page three, whatever that may be. Now in here we're going to add the code to call into the data service and we're going to call that new getCustomersPage that we saw. I'm going to pass in the page, but the page, as you're going to see later with the pager component, is going to be one-based. I'm going to subtract one off of that, so we're going to say page minus one, and we're going to multiply that times the pageSize, and that's going to be the number of records to skip, and then we're also going to pass the pageSize for the number of records we want to grab. Alright, now that we have that we can come on in, subscribe to the observable. But what are we going to get back? Well, if we go back to our data service currently getCustomersPage actually doesn't really return anything useful there. It's kind of hard to know what we're going to get back. So what I've done is created an interface called IPagedResults, and IPagedResults is going to be responsible for allowing us to return page results of, and then we can pass ICustomer as an example into that. So let's come into our data service, I'm actually going to change this. We're going to say this returns an observable of IPagedResults, which has a type of ICustomer for the actual value. Now, this currently is an imported. So let's go ahead and come on up here, we'll add IPagedResults there. Okay, so now I'm being very specific that getCustomersPage returns an observable but the observable type is an IPagedResults and the actual results are of type ICustomer. Now by having this, I can return really any type of results. It could be customers, it could be orders, it could be whatever we want, but this provides some nice consistency across the app and it provides some nice intellisense or code help you're going to see as we, of course, type. So now that our data service is more explicit about what's being returned here, let's switch back to here, and now I can say that our response, and we're going to get back from the subscription, is going to be an IPagedREsults of ICustomer. And now that we have that, we can be a little more specific now. I'm going to say, actually I just realized I need to make this an array though because we are going to get back an array instead of one customer. Let's do an array there. Okay. So now that we have that, let's do our error function and we go ahead in here, deal with our error if we had one, and I'm also going to add a kind of do always function, a do. And I'm also going to log some information about the paging just so we know that it was called, so I'm just going to say getCustomersPage, retrieved customers, and then we could pass in the pageSize and all that if we wanted, as well, but we're going to go ahead and leave it as that. Okay, so now we have a way to call the getCustomersPage, we pass in the page that was passed in here minus one so we get back to zero-based, multiply that times the pageSize, that will give us the skip value, and then the pageSize which defaults to 10 in this example. We then subscribe to the observable which we know we're going to get back as IPagedResults of ICustomer array. And now when we get to the response, we can be very specific about the code help, I'll show you what I mean here. So I can say the customers and the filteredCustomers are both going to be set to response, and when I do dot here you'll notice I get some nice code help because of the interface. So we'll do results. Then I'm also going to need to update the total records for the paging we're going to be doing a little bit later so that we know how many pages to show of information, and we're going to grab the response and get the total records, and then we'll be done. So that'll update the properties for the customers and the filtered Customers. Now we were doing that a little bit earlier, if we come on down to this example with the getCustomers. But we now have that available. I'm going to go ahead, since I added the other functions, and take that parentheses out because we close it here, and now we're ready to go. So at this point though getCustomers is still being called, when the ngOnInit gets called. So if we come back up to here you'll notice we have getCustomers. Let's change that. Let's now call into, so we can try this out, our getCustomersPage, and what I'm going to do is pass in a page of one give me the first customers and then of course I'm going to grab 10 of those. So instead of showing all of the customers in the database, now when the component calls the data service it'll tell it, "I just want 10 records," and that then will kick in, load those customers, and will only display those 10. Now we won't have the ability to page through other customers at this point, but we're going to fix that a little bit later in this module. So let's see where we're at so far, let's first go back to the console, make sure we don't have any issues. Okay, the incremental compilation started. Looks like the typescript compiler worked okay there. Let's go back into the app now and refresh. Okay, now we should only have 10 customers here. Alright, you'll see that it ends much sooner, I'll let you count them. But that should be 10. And so we're working now, that's great. Everything else should still work the same, nothing's changed on these. But now we have that part of the functionality in place and the component is calling the data service which then integrates with the RESTful service. But we don't have a way to get to multiple customer. We don't have page two, page three, and so on and so forth, so we need to fix that. That's what we're going to do next.
Adding a Paging Component
The next thing we need to add into the component is the ability to actually click on a page and view those different customers. To do that, we're going to come back into our customers component, but what I want to do first is go into the template for it. Now, in the template we need a way to not only display the grid of our customers as you see here, but we also need a way to page through those customers. Now, in the application I already have some pagination functionality built-in, a custom component, I'll talk about that in a moment. But let's go ahead and first use this pagination component and put it into play. So what I'm going to do is add this pagination. This is the name of the component selector, and that has several properties and an event we can hook into. First off, any time you do pagination you need the totalItems, so we're going to bind to an input property that we look at called totalItems, and bind that to our totalRecords that we saw back here. So we know that totalRecords gets updated, we're going to pass that value to here. So we'll say totalRecords. Now I'm also going to come in and we're going to bind to another one called pageSize, this is also an input property and you've seen that we also have a pageSize in our component. And then finally we're going to use our clicks on one of the pages, I need that as well, so we're going to add a pageChanged, and you'll notice that this is a custom event or an output property that will be defined in this pagination. So we're going to call a function that we're going to be adding here in a moment, we're going to pass the event object. Then we go ahead and add our closing tag. Okay, so that'll take care of adding our custom pagination control, binding the records and the page size into it so it knows how many pages to render in the UI, and then, when a user clicks on one of those we need to call pageChanged, that's going to call back into our custom function that we're going to have that will take care of that. So let's now go in and add this pageChanged back in our component. So let's go ahead and write above the getCustomersPage, and we'll just say a pageChanged, so this is going to be pretty simple. We're going to get the page and this page is going to be one-based, that's why earlier I showed you we're going to take whatever is passed into here and subtract off one. So we go ahead and now pass that along to our getCustomersPage. Whatever page is passed in, it then subtracts off one, multiplies the pageSize, and calls our service. Okay, so now we're good to go. We now have a custom pagination control in play. We've bound to its input properties, into an output property, we can now be notified when the page changes, and we're off and running. So let's try it out first and then we'll talk about the pageChanged. So let's refresh. It looks like we got our records back. But now at that bottom you'll notice I have a little custom pagination control. You'll notice that it starts with Michelle Avery, now we'll go to page two, looks like we now have Elaine Jones, page three, and then of course I can move one by one if I'd like, and if we wanted we could also put this up top, move it up maybe instead of the bottom, but go ahead and leave it here for now. So that's an example of the paging. Now, to make this paging component was actually pretty straightforward. It's really just a template and some code. So the template itself is pretty simple. I'm using some nav features from HTML5 and I'm just embedding a ul, and the ul is then going to have lis, and these lis will ultimately represent the pages. Here's where I do an ngFor, and I loop through all the pages which I'll show you in a moment. When one of the lis is clicked, we're going to call an internal function in the pagination component here that's going to pass the page and the event object, and then I also handle setting some CSS classes like active to change it as the user clicks. Now, the other lis would be move back a page or move forward a page, and you'll notice that we either disable those or enable them based on if they're at the end or the beginning, just depends on where the user's clicking here. Alright, so if we go back into the code for this, the important part with this pagination component is that it has two inputs and one output. So you'll notice I have a get and a set, so we're using some ES2015 features here, and the input, any time the pageSize is going to be retrieved, we're going to return it from some private members we have. We have a pagerPageSize and a pagerTotalItems up here. And then any time one of these properties is set, we're going to call update. Now, that way if the pageSize changes or something else changes on the external world, we can be notified we can call update, and the update's actually going to take care of rendering our pages. So we'll go in, we'll add our pages, the pages then get rendered using this li, we loop through those pages, and that's actually what renders one, two, three, those types of things in the pagination component. Now, just as a heads up, there's plenty of pagination components out there. This is a custom one just so you can have it and you can see the process. I won't go through all the code, but do want to talk about a few other things. So we've talked about the inputs to set the pageSize and the totalItems. Now that of course is what allows us, if we go back to our customers component, to bind to totalItems and pageSize. Those are two input properties. Now, if we go back to the pagination component here, we now also need a way to disable and we need to handle the click, so that would be an output property. So you'll see we have a pageChanged, that of course is what we're hooking to in our customers component, and that's an EventEmitter. Now, the EventEmitter is just passing a number and that number gets passed up back into our customers component, which then calls and uses the data service. Alright, so there's our two inputs and our output so we can get data into this component and then also raise events to get data out of the component. Now, really the rest of this is just determining what to show on the previous and next as we move forward. If we go back into the template, you'll notice that as they click we call changePage and there is also a previousNext function you'll see for both the beginning and the end options. So if we go back into the component code, you'll see previousNext is going to determine which direction we're going and basically track what page we're on. Because if we're at the very beginning then I don't want the ability, if we go back to the app here, if we're at the very beginning this should be disabled. There's nowhere to go to. You don't want to go to zero or minus one, of course, so you want to disable it. And of course, if we're at the very end we want to disable this one. And so that's really what's happening with this previousNext. It's determining what direction we are and where we are, and then as changePage is clicked we'll either enable or disable the previous and the next based upon where the user is in the pager. Now there's a lot more we could talk about with this, but I'll leave it in here. There's also UI bootstrap and some other options out there that have pagination controls I mentioned, so there's certainly some third party Angular modules you could just include and not even have to write any of this. But I wanted to include a custom one so you could at least explore and see how this works. The beauty of it though is now all we have to really know about from the external world is this right here. We have the component selector and then we have our two inputs and our output and we can certainly add more and make it more robust. But that's the actual functionality that's driving our paging and now we're able to page through these different records you can see.
CSRF Overview
HTTP headers provide a great way to pass data from a RESTful service down to an Angular client, and then of course we can also use headers to pass data backup. And so that can be used with things like paging and other types of operations. Now, there's another way headers can play a really critical role though, and we're going to talk about that here, and this is with something called CSRF attacks, or Cross-Site Request Forgery attacks. Let's first clarify what is CSRF exactly. So as mentioned, it stands for Cross-Site Request Forgery, and although you'll normally see CSRF, I've also seen XSRF, as well, used in documentation and presentations and things. So both of those mean the same thing. Now, this is the process of a user visiting both a good site and a bad site, and the bad site kind of hijacks the user session, and so we're going to talk about how that works here. So here's an example. Let's say that the user is on their laptop and they've opened up a browser and logged in to some bank site yourbank.com. Now, this could be any site really, but we'll just use a bank as an example. Now let's assume that when they logged in they now have a user session, a session token that's now available, and the browser maybe has access to that, maybe it's a cookie, for instance, that could be set. Well, through an email or visiting a forum or through some other type of enticement, a hacker could try to entice the user to visit their site. Now, normally this would be through maybe a fishing attack where when they visit it, it looks just like the bank site, but of course it's fake. And so what will happen then is the user visits the badsite.com, whatever that is, in a separate tab or a window, and what can now happen is that page that gets served back which the user thinks is real, but of course it's not, so this page comes back here. That particular page can have some code in it that can then take that user session, the session token, and then issue a request back to the bank site, or whatever the good site is. And so this is a case where the user doesn't even realize they've gone anywhere bad, everything looks like the bank site. But under the covers the fake page that came back is now taking over, kind of hijacking if you will, the user session because everything that's going to run is going to run in the user's browser as they load that page from the bad site, and then it calls over to the good site. Now, how would that work exactly? Well, there's actually several ways a hacker could do this, but two of the kind of common ways you might see are you could have a form tag in the bad page, the fake page that comes back from badsite.com, whatever that is, and it could have an action that is actually linking over to the trusted site, whatever that is, my bank or the site that you're trying to go to, and call in some operation there, and it's a post you'll see. Now, the user could either click that button or we could even automate submitting the forum for the user by doing the script that you see, document.forms go to the first form and then submit it, and that would be one technique we could do. Now, another thing is maybe the page that was from the bad site actually had some type of an Ajax call, and if that was enabled on the trusted site, then we can start doing put requests and delete requests and post requests and you can do all kinds of things that are bad. Now, this of course would assume that the hacker knows something about the API, maybe they've started hitting them themselves through their own account and they've started to poke holes and they're figuring out the API. And that's pretty easy to look at as you just look at JavaScript and how it's calling. And there's even other techniques, but these are kind of the main ones you'll see, when the user visits that bad site, they get back some type of page loads in their browser that then uses one of these techniques to send a fake or malicious post, put, delete type of request over to the good site, the bank or whatever it may be. So this can actually be really bad and something that a lot of people aren't aware of, but it's something you should absolutely shut down on your RESTful service side, and then you're going to see that the nice thing is Angular can play very nicely. Now where do headers fit in? Well, headers are going to be the main way we're going to shut this down, and so we're going to talk about that as we move forward. So let's first talk about the node.js RESTful side, and we're going to talk about a module we can include in our express server that can help shut down CSRF attacks. Then after that we'll talk about how Angular can participate.
Adding CSRF Functionality with csurf
Now that you've seen what CSRF is and the type of attack that can occur, let's talk about how we can shut this down on the server side, especially for our RESTful service. I'm going to introduce a module that's very popular in the node world called csurf and I'm going to show you how we can use this to generate a token that'll help validate requests and make sure they're coming from the proper client. So going back into server.js you'll notice that I have this csurf module import and I have a variable I just called csrf. If I go down to where the ExpressMiddleWare is initialized, down in here, we have the standard suspects, but I also have this commented out code, and right now a Cross-Site Request Forgery attack would be possible from a different domain if somebody went to a bad site and didn't realize it, because I don't any way to validate where that request really is coming from. Now, you can always go in and add MiddleWare to make sure that it just comes from a specific domain. In this particular app, I actually don't have the ability to call into this RESTful service using something called CORS, Cross Origin Resource Sharing. So another domain in the browser wouldn't really be able to call into it anyway. So I may go ahead and comment this back in, and this is now going to use the csurf module function to say that cookies should be enabled. Now, what this is going to do is two things. Number one, it's going to set a cookie that's going to go down to the client, but then as that cookie comes back it's going to compare it to a header that the client actually needs to set that matches the same token that's in the cookie. Now, what's different about this? Why couldn't a hacker then set the header? Well, because you can only set the header from the client when you're in the same domain as that server. So now an external site can't hack their way into getting the user to call them and then make an Ajax or Http call, because they're not going to be able to set this header, and I'll talk about that in a little bit more detail here. So that's the first thing, I enable the csurf module. That adds up to the middle ware. Now I also add a little custom middle ware here and the csurf module adds this csrfToken function to the request object, so I grab that token and I set it in nodes locals. Now locals are something that can be made available to things like templates, so if I was using pug or one or the other templates out there, handlebars as an example, then you would have access in that case in the template to this custom property called _csrf, which is the token. Now, that's not actually being used in the app because we're just serving up from an actual webpage, let me close this, and we're just heading index html. But if I did switch this to use some templates, we could also access the token in the template if we needed. Now, what's really important here though is I'm setting a cookie with a very specific name and you're going to see this name as something Angular actually knows about. I'm purposely setting the CSRF token that csurf will generate into the cookie, and this name again is something Angular is going to know about. Now, let me go ahead and do that. Let's go back to our console, make sure we don't have any issues. Okay, it looks good there. And now let's go back into the browser, let me refresh, and I'm going to run off to Inspect. A get request I can make from anywhere, I'm doing a get request just from here. So let me go over to the Network tab, and when we run this we'll see that we have our get request that's made here and that of course just gives us the actual data that we have, so there's our customers. Now that I'm not too worried about. What I am worried about though is, if we go add it, well, let's click on this one and let's see actually what happens. So you'll notice we did get a customer back, but let's go into the headers and see if anything special shows up here. So first off, if we look down here a little away, you're going to notice this xsrf token was set as a cookie and this was done by that custom middle ware, and here's our token. Now, when it comes to making requests then back up, the client side is now also going to have to set a token, and so it turns out that Angular looks for certain things to retrieve this token. It's going to get that cookie and then send it back up using a header, and again only someone from the same domain as the server can set the header, and so that prevents other, especially bad, sites from setting this. So now, if a bad site tries to do this, they might have access to the cookie potentially with a request, but they won't be able to set the header if they use JavaScript or form tag or whatever it may be because they're actually running that code from a different domain. So now that we've seen the server side, let's talk about what Angular does in the next section and see how it handles setting the header and reading the cookie.
Using a csurf Token in an Angular Service
Now that the csurf token's been added into the node.js service and has the ability now to set that token automatically, we need Angular to be able to set a header that includes the token value it's going to get. Now again, it's going to get that from a cookie that the server side's going to set. Angular will then set the header and then the server, once the request comes in, will compare that header to the token in the cookie. If they don't match, it's going to throw an error. If they do match, it allows it to proceed. So as mentioned, I like to enable the csurf module on every project I have because it'll prevent these types of hacks. So now that we've seen that, let's jump into what Angular does with that token. So if we go back into the server side code, I mentioned that Angular looks for a very specific cookie name called XSRF-TOKEN. If it finds it, the value for that cookie is then going to be set as the header and then everything just works. Now this happens just out of the box. If you go read the docs, you'll see that XSRF support is just built-in natively to the HTTP client. However, you have to make sure that the server you're calling sets a specific cookie. Now to prove that, I'm going to go ahead and just name this XSRF-TOKEN2, go ahead and save. I should have restarted the server, looks like it just finished, and now I'm going to go back to the application and refresh it. Now, this should have just said a cookie, I have cleared all cookies prior to this, and let's say we have this Michelle2 again, and I would like to come in and change it. Now before I hit Update, I'm going to go to Inspect and go to the Network tab. Now let's come on down and do an update, and up, looks like we got an error. Now if I come down to the console, it says that we have some forbidden invalid CSRF token. Now, what just happened there is Angular didn't see a cookie that it knew about. If we go into here and scroll down, we're going to see right here that we have this XSRF-TOKEN2. Well, Angular doesn't know about that and so it never set the header, therefore the server, when it checks as the request comes in, says, "Well, I got the cookie value back, "but I didn't get the proper matching header value." And that's why we get this error. Now, to make this work of course I need to come in and probably clear out some cookies, so let me do that just really quickly here. And now if I go back and change it to XSRF-TOKEN without the two, restart the server, give that a moment, and then let's refresh, let's actually just go back to the homepage. Let's go ahead and inspect. We'll go to Network, and now let's try to update. Now Angular knows about the XSRF-TOKEN cookie and so when we hit Update, it's going to set the header, that now just went back, but this XSRF-TOKEN, this was actually set and this particular value is now going to match up with the value on the server side. In fact, you'll see there's actually the cookie right there and there's the token that was set. And so now we're good to go. It knows about the cookie coming in, Angular set the header and it all works. Now, you might ask the question, "Well, that's great, Dan! "What if I don't have control over the server? "What if I'm not the one actually setting this?" Maybe it was called, XSRF-TOKEN2 or something like that as an example. Well, the good news is you can override it in Angular. I'll show you a quick example. If I go into my core module, this is the one that loads up all our singletons we talked about earlier, you'll see I'm actually importing something called an XSRFStrategy, and then I have this CookieStrategy. Now, what I'm going to do is override the default provider for the XSRFStrategy to use a custom CookieXSRFStrategy. Now, if it was called XSRF-TOKEN2, then this first value represents the cookie that Angular would look for. The second value is the default value of the header that it's going to set, and that's a header that csurf and other modules out there typically know about, in this case csurf definitely knows about it. So, I could uncomment this and then I could make the token two value for the cookie actually work. It would read that cookie and then set this header, and then the server side would validate the cookie against the header. So this is a way that you can actually override the default. Now, I don't need this in the app because I do have control over the server, and so I just set it to what Angular looks for anyway. Now, of course, it goes without saying that if we're going to allow post, put, and delete request that you're going to want to provide authentication. Now, because authentication is very specific to apps and companies in general, I'm not going to add anything like that here. But even if authentication is enabled, just keep in mind, as I showed earlier, a bad site could potentially do a CSRF attack, and that's exactly why we've now talked about the importance of the header, the cookie that goes down, and why you want to prevent CSRF attacks from the server side.
Summary
We've covered a lot of information in this module. We started off by talking about how headers can be used to transmit and send information from a RESTful service down to a client and vice versa, and we looked at how, for instance, a record can or can't go from our service down to Angular and how Angular could send tokens for CSRF attack prevention from the client up to the RESTful service. We also looked at a pager component and how it can be used to provide pagination services in a reusable way across an application, and then went into CSFR attacks, Cross-Site Request Forgery, and talked about what they are and how we can shut those down by adding some functionality into the server, in our case we added the csurf module. Finally, we took a look at how Angular has built-in support in the HTTP client to take advantage of csurf prevention, and it can read that cookie that's set by the server, grab the token, and then set the header that goes back up to the server so it can validate the token.
Course Summary
Course Summary
This course has been all about integrating an Angular application with a Node.js Express RESTful service that talks with MongoDB. The overall goal of the course was to show how data could be moved from a database to an Angular client. As the user changes the data in the application, we examined how to insert, update, and delete that data, and how those different types of operations could actually be performed. The course started out by talking about key technologies used in the sample application. This included an overview of RxJS and the key functionality it provides, as well as Observables, and how they can be used to work with asynchronous calls made by an Angular application as it retrieves data and how we can subscribe to those Observables. From there, we jumped into the sample app and looked at how it can be used to page and then modify data, we looked at updates and deletes and inserts, and really the full CRUD operations set of actions that can be performed. On the server side, we looked at how the application can be used to create RESTful endpoints. We talked through that process of creating get, post, put, and delete routes that a client could call into, and we added code to handle calling MongoDB to perform those CRUD operations and return the appropriate response to the client. We also looked at how Angular services and the HttpClient can be used to make async calls to the RESTful service and retrieve data. The Observables returned from the Angular service were the subscribed to by Angular components to display and capture data. The role that HTTP headers can play in an app are also discussed. Headers were used to page data and revamp CSRF attacks, and along the way, you saw how components could subscribe to Observables and then render data in the user interface using child components. This included discussing input properties such as the customers properties shown here, and we also looked at output properties. You also saw different form techniques that can be used in Angular, including the template-driven approach and a reactive approach and the differences between them. Well, that's a wrap on the course. I sincerely hope you enjoyed going through it as much as I enjoyed creating it for you, and that you were able to learn a lot along the way. If you'd like additional information on these technologies and others, feel free to visit codewithdan.com, and I also tweet a lot about these technologies, so feel free to follow me @DanWahlin. Thanks for taking the time to watch, and please do check out my other courses on Pluralsight.com.
Course author
Dan Wahlin
Dan Wahlin founded Wahlin Consulting, which provides consulting and training services on JavaScript, Angular, Node.js, C#, ASP.NET MVC, Web API, and Docker. He is a Google GDE, Microsoft MVP and...
Course info
LevelBeginner
Rating
(56)
My rating
Duration4h 17m
Released30 Jan 2017
Share course