Learn Angular 9 with Tailwind CSS by building a banking app - Lesson 2: Login form logic
Tags: webdev, tutorial, angular, beginners
Published: 2020-05-25 13:42:55

This article was originally published at https://www.blog.duomly.com/angular-course-building-a-banking-application-with-tailwind-css-lesson-2-login-form/

---


A few days ago, we published the first lesson of the Angular Course, where we are building frontend for the banking application you could see in the <a href="https://www.blog.duomly.com/sql-injection-attack-tutorial-for-beginners/">SQL injection tutorial</a>.

In the first lesson we started with setting up the project using <a href="https://cli.angular.io/">Angular CLI</a>, implementing <a href="https://tailwindcss.com/">TailwindCSS</a> and creating a UI for the login form.

Today I’d like to go one step further and create logic for the component we’ve created. So, if you were creating the application with me in the previous part, then let’s open the code and start the app. If not, check out the <a href="https://www.blog.duomly.com/angular-course-building-a-banking-application-with-tailwind-css-lesson-1-start-the-project/">Angular Course - Lesson 1: Start the project</a> or check out our <a href="https://github.com/Duomly/angular9-tailwind-bank-frontend/tree/Angular9-TailwindCSS-Course-Lesson1">GitHub</a> and get the code from there.

And of course, as always, we prepare you a video on our Youtube channel if you are more into watching tutorials than just reading them. 

{% youtube EslEnosMyQg %}

On the playlist, you’ll also find a lesson one and other lessons of this course which we will prepare for you.

There’s one more thing, on the backend, I’ll be using the app which you can find in our <a href="https://www.blog.duomly.com/golang-course-with-building-a-fintech-banking-app-lesson-1-start-the-project/">Golang course</a>, so you can create and use it as well.


Let’s crush Angular!

###1. Create logic for login component - handling inputs and validation###

Let’s start our existing project using `ng serve` and let’s open `login.component.ts` file. I’d like to start by creating a function, which will get and save the values from the inputs to be able to use them with the submit function. 

Let’s first define two values username and password, and let’s assign an empty string to those values.

```typescript
username: string = '';
password: string = '';
```

Now, we will create an `onKey()` function:
```typescript
onKey(event: any, type: string) {
	if (type === 'username') {
		this.username = event.target.value;
	} else if (type === 'password') {
		this.password = event.target.value;
	}
}
```
Right now, we need to create a validation for the username filed to prevent SQL injection. My friend showed you how to hack application putting SQL command in the input, and we would like to avoid it so, we won’t allow to send username if it’s different than only letters and numbers. 

Let’s create another value `isUsernameValid: boolean = true;` just under the `password: string = '';`.

```typescript
isUsernameValid: boolean = true;
```
Now, let’s create a validateUsername() function.

```typescript
validateUsername(): void {
	const pattern = RegExp(/^[\w-.]*$/);
	if (pattern.test(this.username)) {
		this.isUsernameValid = true;	
	} else {
		this.isUsernameValid = false;
	}
}
```

And to make it work, let’s place this function in the `onKey()` function.

```typescript
onKey(event: any, type: string) {
	if (type === ‚username’) {
		this.username = event.target.value;
		this.validateUsername();
	} else if (type === ‚password’) {
		this.password = event.target.value;
	}
}
```
The last point in this step is to implement our onKey function in the template and display the error message if username is not valid. Let’s open `login.component.html` and find the inputs.

```html
<form class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
  <img class="logo" src="../../assets/logo.png" />
  <div class="mb-4">
    <label class="block text-gray-700 text-sm font-bold mb-2" for="username">
      Username
    </label>
    <input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="username" type="text" placeholder="Username" (keyup)="onKey($event, 'username')" required>
    <p *ngIf="!isUsernameValid" class="text-red-500 text-xs italic">Your username can consist of letters and numbers only!</p>
  </div>
  <div class="mb-6">
    <label class="block text-gray-700 text-sm font-bold mb-2" for="password">
      Password
    </label>
    <input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline" id="password" type="password" placeholder="******************" (keyup)="onKey($event, 'password')" required minlength="6">
  </div>
  <div class="flex items-center justify-between">
    <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="button" (click)="onSubmit()">
      Sign In
    </button>
    <a class="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800" href="#">
      Forgot Password?
    </a>
  </div>
</form>
```

Great, now we are ready to create a service and make an API call!

###2. How to create service in Angular?###
Let’s use Angular CLI to create `login.service.ts`. For this, we need the following command:

```ng generate service services/login/login```

Let’s open the created service and start from importing needed packages.

```typescript
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';
```
Now, let’s define a contstant called httpOptions, which will be a part of our API request.

```typescript
const httpOptions = {
  headers: new HttpHeaders({
    'Access-Control-Allow-Origin': '*',
  })
};
```
The next step is define our url and pass `HttpClient` to the constructor.

```typescript
  url: any = <your_api_url>;

  constructor(
    private http: HttpClient,
  ) { }
```
Great, now we can start creating a login function. Inside the function, we need to handle the response. If we will get a token, it means that the user is logged in. We are going to save this data to the session storage to keep the user logged in only during the session. 

```typescript
login(Username: string, Password: string): any {
    this.http.post(this.url, { Username, Password }, httpOptions).toPromise().then((res: any) => {
      if (res && res.jwt) {
        sessionStorage.setItem('jwt', res.jwt);
      }
    });
  }
```


Besides that, we need to handle an error message if the login call will return it. For this, we’d use `behaviourSubject` from `rxjs`. Let’s implement it!

```typescript
errorSubject: any = new BehaviorSubject<any>(null);
errorMessage: any = this.errorSubject.asObservable();

...

login(Username: string, Password: string): any {
    this.http.post(this.url, { Username, Password }, httpOptions).toPromise().then((res: any) => {
      if (res && res.jwt) {
        sessionStorage.setItem('jwt', res.jwt);
        this.errorSubject.next(null);
      } else if (res.Message) {
        this.errorSubject.next(res.Message);
      }
    });
  }
```

Let's import `Router` from `@angular/router`, to redirect user after login to the Dashboard view.

```typescript
import { Router } from '@angular/router';
...
constructor(
  private http: HttpClient,
  private router: Router,
) { }

...
login(Username: string, Password: string): any {
  this.http.post(this.ulr, { Username, Password }, httpOptions).toPromise().then((res: any) => {
    if (res && res.jwt) {
      sessionStorage.setItem('jwt', res.jwt);
      this.errorSubject.next(null);
      this.router.navigateByUrl('dashboard');
    } else if (res.Message) {
      this.errorSubject.next(res.Message);
    }
  });
}
```

Before we make it work together we can't forget about adding `HttpClientModule` to `app.module.ts` file. So, let's open it and make sure your code looks like to one below.

```typescript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { DashboardComponent } from './dashboard/dashboard.component';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

Fine, now we can go back to `login.component.ts` file, and let’s create an `onSubmit()` function using LoginService. Of course, we have to import the service and set it in the constructor.

```typescript
import { LoginService } from './../services/login/login.service';

...

constructor(
  private loginService: LoginService,
) { }

onSubmit() {
  if (this.isUsernameValid) {
    this.loginService
    .login(this.username, this.password);
  }
}
```
The next this we would like to add here is error value where we will be listening if error didn’t appear. We will subscribe to error message from LoginService in `ngOnInit()` method.

```typescript
  error: any = null;
...

  ngOnInit(): void {
    this.loginService
      .errorMessage
      .subscribe(errorMessage => {
        this.error = errorMessage;
      });
  }
```
And we are almost there, we just need to switch to the `login.component.html` file and add values to our template.

First let’s assign `onSubmit()` function to our Login button.

```HTML
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="button" (click)="onSubmit()">
  Sign In
</button>
```
And next let’s fill in missing values in the notification element. Also let’s define when the element will be visible.

```HTML
<div *ngIf="error" class="notification bg-indigo-900 text-center py-4 lg:px-4">
    <div class="p-2 bg-indigo-800 items-center text-indigo-100 leading-none lg:rounded-full flex lg:inline-flex" role="alert">
      <span class="flex rounded-full bg-indigo-500 uppercase px-2 py-1 text-xs font-bold mr-3">ERROR</span>
      <span class="font-semibold mr-2 text-left flex-auto">{{error}}</span>
    </div>
</div>
```
And voila. Login almost works! Now it’s time to work on guard which will prevent not logged users from entering the application.

###3. How to create a guard in Angular routing?###

So, at the beginning let’s create a guard file using Angular CLI.

```ng generate guard services/guards/auth-guard```

Now, let’s our `login.service.ts` file, where we are going to create one more function `isAuthenticated()`.

```typescript
  isAuthenticated() {
    if (sessionStorage.getItem('jwt')) {
      return true;
    } else {
      return false;
    }
  }
```
Okey, we can switch to our `auth-guard.service.ts` file. In the beginning let’s import LoginService, Router and CanActivate.

```typescript
import { Router, CanActivate } from '@angular/router';
import { LoginService } from './login/login.service';
```

Next we can set LoginService and Router in the constructor and then let’s create canActiveate() function which will return true if the user is authenticated and will redirect us to the dashboard component and return false if a user is not authenticated.

```typescript
@Injectable()
export class AuthGuardService implements CanActivate {
  constructor(
    public login: LoginService,
    public router: Router) { }

  canActivate(): boolean {
    if (!this.login.isAuthenticated()) {
      this.router.navigateByUrl('/');
      return false;
    }
    return true;
  }
}
```

###4. Creating a dashboard component###

Let’s use Angular CLI to create a dashboard component.

```ng generate component dashboard```

Now, let’s open the `dashboard.component.ts` file and we will create a simple headline there.

```typescript
<div id="dashboard-component" class="container mx-auto grid">
  <div class="flex mb-4 mt-24">
    <div class="mx-auto">
      <h3 class="text-gray-700 font-normal mx-auto">
        Hi User,here is your dashboard:
      </h3>
    </div>
  </div>
</div>
```
Also, let’s add one line of custom styles in our dashboard.component.scss file.

```scss
#dashboard-component {
  h3 {
    font-size: 24px;
  }
}
```

As the last step, let’s add a route for a dashboard component. Please open the `app-routing.module.ts` file and create a new route.
In this route we are going to use the AuthGuard, so we need to import it as well.

```typescript
import { DashboardComponent } from './dashboard/dashboard.component';
import { AuthGuardService as AuthGuard } from './services/auth-guard.service';

const routes: Routes = [
  { path: '', component: LoginComponent },
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
];
```

Now, it’s time to test it! 

###Conclusion###

I hope you were able to create the code for lesson one and lesson two and you have a running login for our application.

Remember to take a look at the Golang course where you can build a backend for this application, so you will have a fully running project. If you don’t have any backend you can easily mock the data.

In the next lessons we are going to get users data to display on the dashboard and create other interesting features.

Stay tuned and let us know in the comments if you like the course!
If you got lost in the code, here’s a GitHub repository with lesson two so you can compare the code and find the bugs.

<a href="https://github.com/Duomly/angular9-tailwind-bank-frontend/tree/Angular9-TailwindCSS-Course-Lesson2">Angular Course - Lesson Two - Github Code</a>

Thank you for reading,
Anna from Duomly

<a href="https://www.duomly.com">![Duomly - Programming Online Courses](https://dev-to-uploads.s3.amazonaws.com/i/psc1z92r8uk34luvdvhc.jpg)</a>