0:00
[MUSIC]
Now that we have completed updating the server site,
it's time to move on to the Angular Client.
For you're convenience I have provided you with the gate helper repository
that contains the final version of the Angular Client.
That is able to communicate with our rest API server and
then render the radius views for our client.
So I have taken the angular application that we developed in the second course
of this specialization and then modified it to update it to use Angular 4.3.
In addition I've updated it to use the Angular
material beta 11, and also updated it to use the HTTP
client which comes as part of Angular 4.3.
So you will see that the code is modified from what you
have accomplished at the end of the Angular course.
We will take a brief tour through the code a little bit later.
Now, from git repository, you will clone the git repository to your
computer and then start up your Angular client.
And then see it communicating with our server set.
Let's see the details next.
5:15
to the right corner you see the login button has now turned into logout,
and the user's name is indicated here.
So whoever is logged in is indicated here.
You could also in principle replace this with the image of the user.
Now for that you need to do more modifications to both the client and
the server in order to support the image display here.
But at the moment I'm just showing you how we can
easily display the user information here.
So this required minor modification to the header component where I will be able to
retrieve the user name from a service called the [INAUDIBLE] service,
which we will talk about in a short while.
So once the user logs in, then if you now click on My Favorites,
you will notice that there's nothing in My Favorites for the user.
Obviously because the user has not yet chosen any favorites.
So let's now go to the Menu, and then in the Menu let me select one item.
And then we will add this dish to our favorites,
so going down below here you see the heart symbol there.
Click on that and you will see that this would be added into the favorites.
And the fact that this has been added to the favorites is indicated by
the change in the icon here from a unfilled heart to a filled heart.
Now if you go to any other dish you will notice that this
has an unfilled heart, which means that this is not yet among our favorites.
So let me add in one more item to My Favorites.
And then let's add a third item to My Favorites also.
So now you will see that if I now
go to My Favorites, you will see a set of my favorites being displayed here.
So you saw that I just added these three dishes to My Favorites,
and so these are being displayed here.
So this is tracked by using that favorites in point on the silver
side which we have implemented as part of your last assignment.
So if you have done that assignment correctly,
then this part should work as expected.
Now, we can also modify My Favorites.
So for example, in the right corner here you see this Delete toggle here.
So let me turn that on.
And so when you turn that on, you immediately see that three red
crosses appear at the bottom of these three items in My Favorites.
When I click it off, then they disappear.
So this is one way of Turning on the Delete buttons on your My Favorites.
So let me go ahead and delete one of the items from My Favorites.
So when I click on the button, you notice immediately that that item is
deleted from My Favorites and immediately disappears, and
My Favorites gets updated, and you see the resulting value being shown here.
At the same time, this Delete toggle is turned off, so
that the Delete buttons are no longer visible.
I can always again turn on the Delete buttons by clicking on the On and
Off, here.
9:38
Lets take a brief tour through the Angular code that I have supplied for
you in the GitHub repository and also see how we have modified parts
of the code in order to implement the updated Angular application.
So if you go into the package.json file here,
you would notice that the newer version of the Angular
application now has been updated to use angular/core
4.4.5 and also the Angular material.
Right now, I'm using 2.0.0-beta.12, and the cdk 2.0.0-beta.12,
and angular/flex-layout 2.0.0-beta.9 here.
And so you see that I am using the newer version of Angular
within this application.
This also means that I can make minor changes to the code, so that this
code is not exactly the same as what you get at the end of the Angular course,
but has been updated to use the newer features of Angular 4.
Let's begin our journey with the services folder here.
And in the services folder,
let me draw your attention to the dish_service.ts file as
an example to illustrate the minor changes that have been made into the services.
Now, in the DishServices, earlier, we had used the HTTP, which is part of Angular.
But now, with Angular 4.4, the new HttpClient has been supplied.
The HttpClient is an updated version of the http, and
that is what I am employing here in my application.
Now, the HttpClient will automatically return
the incoming reply information in the form of JSON.
So it expects the server side to send JSON data by default,
and which is the case with our express server that we have just built.
So that's why slipping in the HttpClient into our
services in our Angular application is fairly straightforward.
And you see that here, instead of using the HttpClient, I am simply
saying HttpClient here is refusing HTTP there.
Now, notice that in the getDishes() method, for example,
I'm just saying return this.http.get(baseURL + 'dishes').
I am no longer processing the body of the response message
exclusively because by default, the response message is
expected to be in JSON format by the HttpClient.
So that automatically take care of extracting the JSON data and
then passing it back to my various components.
Now, the error, of course, is still handled by the processHTTPMsgService,
as we did it in the exercise for
our Angular application in the second course.
So those are minor changes that you will notice in the various
12:54
services that we have implemented in our angular application.
Now, in addition, you will notice that there is a new service that I have
introduced here called Auth.Service.
The Auth.Service takes care of all the authentication-related actions for
the Angular application.
So within the Auth.Service, you would immediately notice that
I have a set of information that I have configured here.
And since you already know Angular,
you should you be able to easily process whatever is returned here.
Note in particular that within the AuthService itself,
I am storing information like, for example, the tokenKey which is the Key for
the local storage where I am storing the JSON Web Token.
And also some additional variables here where I am
tracking the username and where I am authenticated,
and also keep track of the JSON Web Token here.
14:02
Now, let's begin by looking at when the user logs in.
So when the user logs in, then this function called
the logIn will be called in our AuthService here.
And when the logIn is called in the AuthService,
this will be passed in a parameter called user which contains the username and
password as part of the user JavaScript object.
So at this point, I am doing an http.post to the baseURL + 'users/login'.
And note also that here, I am supplying the AuthResponse as the qualifier here.
The AuthResponse is nothing but an interface that I have implemented here,
at the top, here.
So this interface essentially specifies the information that is going to come
back as my authentication response from the server side, but
structure of the JSON data that is coming back from the server side and
the corresponding JavaScript object.
So you notice that when we updated the server, we make sure that the server
is sending back the status, the success, flag, and the token in the string vection.
So that information is obtained in here.
Now, when I am doing a post on that, I am passing in the username and
password to that post on this /users/login endpoint.
And when the reply comes back, from the reply, from the response,
the response message itself will contain, as we saw,
the success, the token field, and also the status message here.
So from the response message, I am extracting the token and
then passing it into this function which I implement here, local function here,
called storeUserCredentials.
And so that will be returned to my application And will be stored
in my client-side into the local storage.
And then, from this function, I am returning this information back to
that calling function from where I initiated that login process.
So this mean, I will be indicating to my login
component that the login was successful.
And I will also pass in the username to my login component which then will pass
that information onto the header component.
And the header component uses that to reflect
the username onto the toolbar at the top there.
And also, we catch the error here.
So this is a very simple implementation of how we perform the login.
Then you do the logout.
Notice what I do when the user calls a logout.
When the user calls a logout,
I just simply destroy the user's credentials which includes throwing
the JSON Web Token that I have obtained when I logged into my application.
And then, some additional helper functions that I implemented here called
getUsername, isLoggedIn, and getToken which will be useful from my other
17:24
applications, other components, and services.
So now, let's look at some of the helper functions that we have implemented here.
So, the loadUserCredentials will retrieve the credentials from the local storage.
So you notice that here, I am calling localStorage and then saying, getItem.
So the localStorage here is using the web browsers local storage that is supported
by standard web browsers.
And storing the information there and then, retrieving this information there.
And then from there, the credential information if it is valid,
Windows credentials will be setup here.
So, all these variables that I've defined here will be initialized with
the appropriate information after being retrieved from the local storage.
Now similarly, the storeUserCredentials
function that I've implemented here is called from the login method.
And when the credential information is passed in,
that information is stored in the localStorage at this point with that key.
And then, the useCredentials, basically,
sets up all the variables that I have in the AuthService.
So it sets up the token, it sets up the username, and
then it sets up this authenticated function here.
So notice that the username itself here, I have declared it as a subject,
which is nothing, but an observable here.
So that is why, whenever I say, sendUsername here,
I say, credentials.username.
So, this.sendUsername implemented right at the top here,
notice that this where observable value is sent back.
So that's why, this.username.next.
So, the observable will send back the name that is supplied
as a parameter to whoever has registered themselves to observe this observable.
So, this observable, I'm going to be observing this from my header component.
And so that whenever the username changes either from undefined to a given username,
or vice versa, then I can update my toolbar in the header
component to reflect whether the user is logged in or logged out.
So that is setup by using this useCredentials.
Now the destroyUserCredentials, basically,
sets the authentication token to undefined.
It clears the username and inserts the isAuthenticated to false and
then, removes this information from my localStorage.
So it's basically throwing away the JSON Web Token at this point.
So that is how you log out a user.
So once the JSON Web Token is lost, the user can no longer authenticate himself or
herself on the server-side because the token is no longer available to us.
So that's how we implement the log out function within our application.
So, take some time to go through the AuthService
here to see how I have implemented the various functionality.
Now, by this time, I'm sure you are very
familiar with how Angular applications are implemented.
So it should not be that difficult for
you to understand how this code is implemented.
Now, one more function that I would draw your attention to is the checkJWTtoken
here.
This function can be called at any point to check and
make sure that our JSON Web Token is still valid.
So this is where I am sending the get request to users/checkJWTtoken.
Recall that we implemented this route on the server-side in the users.js file.
And so, from there,
we would be able to verify whether the JSON Web Token is still valid or not.
If the JSON Web Token is not valid then, we could destroy the user's credentials
and then, expect the user to login in again.
If the JSON Web Token is valid then, it's okay and we can proceed forward
with allowing the user to recognize that we are logged in.
So, even if you close your browser, and then re-open the browser, and
then re-open your Angular application, if you had logged in earlier, and
the JSON Web Token was saved into the local storage, it can retrieve from there.
And then, your login status will be restored within your Angular application.
If the JSON Web Token is expired then, we will not be allowed to login.
So, every time you refresh your Angular application in your browser,
or reload your Angular application in your browser,
we're going to be checking the JSON Web Token to make sure that it is still valid.
If it is not valid then, the user will be cleared out and
so, you will have to login again.
If not, then the user's information is retrieved from the local storage and
then, initialized within my Angular application.
And periodically, if at any point in time, your server responds
23:15
So now, in addition to AuthService, in the services folder itself,
you will see this file called auth.Interceptors.ts file.
So open this, and you will see that here, I have implemented HttpInterceptors.
Now, what these HTTP interceptors do?
This is supported with the HTTP client, which comes as part of Angular 4.4.
What the HTTP interceptors do is they can intercept outgoing request messages,
make modifications to the request message before it is sent out.
Similarly, they can intercept incoming response messages.
And then, modify the incoming response message before the responses handed over
to the Angular application.
So, through interception.
So how does this interceptor work?
So to make this interceptor work, we implement
24:15
extending the HttpInterceptor, so here, I have implemented the AuthInterceptor.
So what does this AuthInterceptor do?
This AuthInterceptor is basically capturing outgoing request.
So to capture an outgoing request, you call this function called intercept.
And then this will give you access to the request and the next.
So you could chain in a bunch of interceptors, one behind that, if you so
choose to, so that they can process the outgoing requests, one after another.
If you choose to, what this intercept does
is it gives you access to the HTTP request message.
So when I get access to the HTTP request message,
you will notice that here I am injecting the authService.
Now, unlike the way we were injecting services into components,
here I am showing the use of an Injector.
An injector is part of Angular Core, so
using an injector you can inject services or
other components into other services or components.
So here you see that I am injecting the authService in here by using this.
Now, one other reason is that if I directly inject the service into
my constructor, it'll double up circular dependency between the intercept and
the authService, and that will cause your code not to work.
So, this is a workaround to the problem so that your interceptor, because I need
the authService in order to get hold of the token from the authService.
And the authService in turn depends on this interceptor, so that's why in order
to break the loop I'm explicitly injecting the authService in this case.
Now, this is something that I figured out by trial and error.
I initially went ahead and simply injected authService into the constructor,
and then found that Angular was not compiling the code,
when I figured out that there was an error there.
And then after doing some Google search,
then found out that this is an alternative way of how hthe same thing.
And this works out much better for our application.
So once I inject the authService, from the authService, I get hold of the token.
And then notice what I am doing here.
Here I'm saying clone const authReq req.clone so
they will clone the request, and then we will set up in the headers so
we will say req.headers.set authorization.
And then notice what I'm setting of the authorization here to be,
bearer +, authToken.
So in the authorization header, I'm setting up the bearer and authToken here.
So that is how I am setting up the, Authorization
header in the outgoing request message in my Angular application, so right there.
And that's how I ensure that all outgoing requests will have
the authorization header set up before they are passed to the server side.
And then after that, we'll simply pass it on to the next interceptor,
if it exists, or on to the outgoing queue so
that the request message will be sent out to the server site.
28:00
Similarly, I have another interceptor that I'm going to have implemented here.
This interceptor intercepts any unauthorized reply messages that
are coming back from the server site.
So if the server replies with a 401 unauthorized reply message So
at that point, again, same thing I have set up the authService here.
And then here, inside there, then I'll say, do handle if error.
So this is where I will get hold of the HttpEvent here.
But HttpEvent is a lower-level Incoming
lower level object than a request.
But that allows us to get access to the incoming reply message, and then so
we'll check to see if there is an error.
And that if error is an instance of HttpErrorResponse,
and if the error status is 401.
So which means that I have just detected that the server send back
a 401 error message.
So which means that there was some authorization problem on that server site.
Then at that point I will check the JSON Web Token to make sure that
the JSON Web Token is still valid.
If it's not valid then I will discard my credentials, and
expect the user to log in all over again.
So that way, I will ensure that if my JSON Web Token expires
in the process of trying to fetch data, that it will still be intercepted by here.
Because if the server responds with a 401, I'll intercept that, and
then clear out my JSON Web Token and they expect the user to log in all over again.
We can also re-direct the user to the login page if we want to but
with the Angular application, it's a bit more complicated to do that and
I didn't want to confuse you by doing all that.
Instead I'm simply logging out the user at this point and then destroying
the user credentials, so that the user will be expected to log in at that point.
For simple handling of how we
inject the authorization header into the outgoing request and also intercepting
the 401 unauthorized messages that are coming back from the servers site.
So, you see how these additional changes need to
made in your Angular application in order to make it work with your server site.
31:07
components in there.
Which allow you to deal with the intricacies of how your client and
server will talk to each other.
In particular, note how the headed component has been updated
to reflect the users login status in the toolbar at the top.
That is, again, another interesting change that they have made to
the header component in our application.
So I'll leave that as an exercise for
you to figure out how that has been implemented.
Very simple code there it should be easy for you to figure that out.
So with all these changes, now my angle of client is able to interact with my server.
Let me again show you how we can post some comments to the server,
and then see the comment immediately reflected into the dish.
So again going back to our application, we can now go to the menu and
then pull up any dish here and I can post comments to the dish here.
So, I would immediately set up the, Rating here and my comment value here.