Learn Angular 9 with Tailwind CSS by building a banking app - Lesson 4: User registration
Tags: angular, tutorial, beginners, typescript
Published: 2020-06-10 15:19:01

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

---

For almost three weeks, we are creating an Angular 9 fintech application together, step by step. 

We've already gone through the <a href="https://www.blog.duomly.com/angular-course-building-a-banking-application-with-tailwind-css-lesson-1-start-the-project/">setting the project and creating a login form template</a>, then we've created <a href="https://www.blog.duomly.com/angular-course-building-a-banking-application-with-tailwind-css-lesson-2-login-form/">the logic for our login form</a>, and last week we <a href="https://www.blog.duomly.com/angular-course-with-building-a-banking-application-with-tailwind-css-lesson-3-user-account-balance/">displayed user data in the template.</a>

Today, it's time for lesson 4, where we will handle user registration. 

If you didn't start with me, feel free to go through all the lessons until now. Or you can get the code from the previous lesson and jump straight to this lesson. Here's a link to our Github repository for this Angular Course.

<a href="https://github.com/Duomly/angular9-tailwind-bank-frontend/tree/Angular9-TailwindCSS-Course-Lesson3">Code for lesson 3</a>

There's also one more thing you should know. We are building a backend course along with this frontend Angular Course, so you may use them both to create a fully working app. Here's the link to the backend <a href="https://www.blog.duomly.com/category/golang/">Golang Course</a>.

In the meantime, we are also creating <a href="https://www.blog.duomly.com/node-js-course-with-building-a-fintech-banking-app-lesson-1-start-the-project/">a Node.js Course</a>, but it's still a few steps behind.

And of course, as always, here's the video version of this lesson.

{% youtube ef7npQfx77w %}

So, open the code in your favorite code editor, run your backend, and let's start with user registration in Angular 9.

###1. Create a new component###

Let's start by creating our registration form. In the beginning, we'll use <a href="https://cli.angular.io/">Angular CLI</a> to generate the register component. 

```bash
$ ng generate component register
```

When it's ready, we need to visit <a href="https://tailwindcss.com/">Tailwind CSS</a> and get the form code!

###2. Building registration form template###

We are going to build a form that is similar to our login form, it'll be almost the same, just we need a few more fields, like email and confirm password.

Let's open the `register.component.html` file, and let's create the following code.

```html
<div id="register-container" class="flex container mx-auto items-center justify-center">
  <div class="w-full max-w-xs">
    <form class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
      <img src="../../assets/logo.png" class="logo" />
      <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">
      </div>
      <div class="mb-4">
        <label class="block text-gray-700 text-sm font-bold mb-2" for="email">
          Email
        </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="email" type="email" placeholder="Email">
      </div>
      <div class="mb-4">
        <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 leading-tight focus:outline-none focus:shadow-outline" id="password" type="password" placeholder="******************">
      </div>
      <div class="mb-4">
        <label class="block text-gray-700 text-sm font-bold mb-2" for="confirm-password">
          Confirm 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="confirm-password" type="password" placeholder="******************">
      </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">
          Sign In
        </button>
      </div>
      <div class="flex items-center justify-between mt-4">
        <p class="inline-block align-baseline text-sm text-blue-500">Already have an account? 
          <a class="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800">
            Sign in
          </a>
        </p>
      </div>
    </form>
    <p class="text-center text-gray-500 text-xs">
      &copy;2020 Banking App by Duomly. All rights reserved.
    </p>
  </div>
</div>
``` 
Okay, now let's open the `register.component.scss` file and place there the following styling.

```SCSS
#register-container {
  min-height: 100vh;
  min-width: 100vw;
  color: white;
  position: relative;
  background-image: url('../../assets/background.png');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
  .logo {
    max-height: 60px;
    margin: auto;
    margin-bottom: 30px;
  }
  .notification {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
  }
}
```

Great, when this step is completed, it's time for setting the route for our component and make it visible.

###3. Setting the route###

To set up the route for our new component, let's open the `app-routing.module.ts` file, and we need to import our newly created component.

```typescript
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuardGuard } from './services/guards/auth-guard.guard';

import { LoginComponent } from './login/login.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { RegisterComponent } from './register/register.component';


const routes: Routes = [
  { path: '', component: LoginComponent },
  { path: 'register', component: RegisterComponent },
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuardGuard] }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```
When your Routes look like in the code above, we will add links in the LoginComponent and RegisterComponent. Let's start from the `register.component.html` file, where we are going to send user to the login form if he or she already has the account.

```html
      <div class="flex items-center justify-between mt-4">
        <p class="inline-block align-baseline text-sm text-blue-500">Already have an account? 
          <a class="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800" [routerLink]="['/']">
            Sign in
          </a>
        </p>
      </div>
```

Now, we will do a similar thing, but we will add a link that will allow users to go to the registration form to set up the account. Let's open the `login.component.html` file, and let's do small refactoring. 

```html
      <div class="flex items-center justify-between mt-4">
        <p class="inline-block align-baseline text-sm text-blue-500">Don't have an account? 
          <a class="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800" [routerLink]="['/register']">
            Sign up
          </a>
        </p>
      </div>
```

Great, now your login and register forms should look like below.

![Duomly - Programming Online Courses](https://dev-to-uploads.s3.amazonaws.com/i/3mzj2532rbv8phov1w4y.png)

Now, we will start creating the logic for our registration feature.

###4. Handling inputs###

It's time to create the function which will save the input values from our registration form. Open the `registe.component.ts` file, and let's start with defining the following values. 

```typescript
export class RegisterComponent implements OnInit {
  username = '';
  email = '';
  password = '';
  confirmPassword = '';

  constructor() { }

  ngOnInit(): void {}

  onKey(event: any, type: string) {
    if (type === 'username') {
      this.username = event.target.value;
    } else if (type === 'email') {
      this.email = event.target.value;
    } else if (type === 'password') {
      this.password = event.target.value;
    } else if (type === 'confirmPassword') {
      this.confirmPassword = event.target.value;
    }
  }
}
```
Now, we can add this function to our template. Let's go back to the `register.component.html` and add the function to each input.

```html
    <form class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
      <img src="../../assets/logo.png" class="logo" />
      <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')">
      </div>
      <div class="mb-4">
        <label class="block text-gray-700 text-sm font-bold mb-2" for="email">
          Email
        </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="email" type="email" placeholder="Email" (keyup)="onKey($event, 'email')">
      </div>
      <div class="mb-4">
        <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 leading-tight focus:outline-none focus:shadow-outline" id="password" type="password" placeholder="******************" (keyup)="onKey($event, 'password')">
      </div>
      <div class="mb-4">
        <label class="block text-gray-700 text-sm font-bold mb-2" for="confirm-password">
          Confirm 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="confirm-password" type="password" placeholder="******************" (keyup)="onKey($event, 'confirmPassword')">
      </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">
          Sign In
        </button>
      </div>
      <div class="flex items-center justify-between mt-4">
        <p class="inline-block align-baseline text-sm text-blue-500">Already have an account? 
          <a class="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800" [routerLink]="['/']">
            Sign in
          </a>
        </p>
      </div>
    </form>
```

Our form is updated right now, so we can perform the validation of our inputs.

###5. Validation ###

Before we send the API call to our backend, we have to make sure the values that are passed in the form are in the right format and are saved for our application. Because if you remember the <a href="https://www.blog.duomly.com/sql-injection-attack-tutorial-for-beginners/">SQL injection</a> lesson by my friend, it can be dangerous to our application to send anything to the backend without the check.

Let's open the `register.component.ts` file, and let's create the following code.

```typescript
export class RegisterComponent implements OnInit {
  username = '';
  email = '';
  password = '';
  confirmPassword = '';
  valid = {
    username: true,
    email: true,
    password: true,
  };

  constructor() { }

  ngOnInit(): void {}

  validate(type: string): void {
    const usernamePattern = /^[\w-.]*$/;
    const emailPattern = /\S+@\S+\.\S+/;

    if (type === 'username') {
      if (this.username.length < 5) {
        this.valid.username = false;
      } else {
        this.valid.username = usernamePattern.test(this.username);
      }
    } else if (type === 'email') {
      this.valid.email = emailPattern.test(this.email);
    } else if (type === ('confirmPassword' || 'password')) {
      if (this.password !== this.confirmPassword) {
        this.valid.password = false;
      } else {
        this.valid.password = true;
      }
    }
  }

  onKey(event: any, type: string) {
    if (type === 'username') {
      this.username = event.target.value;
    } else if (type === 'email') {
      this.email = event.target.value;
    } else if (type === 'password') {
      this.password = event.target.value;
    } else if (type === 'confirmPassword') {
      this.confirmPassword = event.target.value;
    }
    this.validate(type);
  }
}
```

To make our validation complete, we have to let users know which fields have errors, and to do it, we will display error messages conditionally. Let's jump into the `register.component.html` file and make sure your code looks like this.

```html
    <form class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
      <img src="../../assets/logo.png" class="logo" />
      <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')">
        <p *ngIf="!valid.username" class="text-red-500 text-xs italic">Username can consist of letters and numbers only and the minimum length is 5!</p>
      </div>
      <div class="mb-4">
        <label class="block text-gray-700 text-sm font-bold mb-2" for="email">
          Email
        </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="email" type="email" placeholder="Email" (keyup)="onKey($event, 'email')">
        <p *ngIf="!valid.email" class="text-red-500 text-xs italic">Your email is not correct!</p>
      </div>
      <div class="mb-4">
        <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 leading-tight focus:outline-none focus:shadow-outline" id="password" type="password" placeholder="******************" (keyup)="onKey($event, 'password')">
      </div>
      <div class="mb-4">
        <label class="block text-gray-700 text-sm font-bold mb-2" for="confirm-password">
          Confirm 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="confirm-password" type="password" placeholder="******************" (keyup)="onKey($event, 'confirmPassword')">
        <p *ngIf="!valid.password" class="text-red-500 text-xs italic">Passwords are different!</p>
      </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">
          Sign In
        </button>
      </div>
      <div class="flex items-center justify-between mt-4">
        <p class="inline-block align-baseline text-sm text-blue-500">Already have an account? 
          <a class="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800" [routerLink]="['/']">
            Sign in
          </a>
        </p>
      </div>
    </form>
```

Great, when this part is done, we need to do some refactoring, as our app is growing and we would like to keep is smart, and comfortable. 

###6. Refactoring###

The thing we will change now is our Login Service. We would like to handle all functions which apply to the user in one service, that's why I'd like to rename it to UserService. You can do it manually or use any dedicated plugging for your code editor. Remember to check all the imports when it's done. 

The other thing which we need to change is our `proxy.conf.json` file. 

Let's open it and change your code to the one here.

```json
{
  "/api/*": {
    "target": "http://localhost:8888",
    "secure": false,
    "logLevel": "debug",
    "changeOrigin": true,
    "pathRewrite": {
      "^/api": ""
    }
  }
}
```
When you finished this, please re-run your application with `ng serve`.

###7. `register()` function###

We can start building the register function in the UserService. Let's open the newly refactored `user.service.ts` file, and let's start by changing the URL value.

```typescript
export class UserService {
  url: any = 'http://localhost:4200/api/';
....
```

We need to make a change in our `login()` function, as we've changed the URL to make it reusable.

```typescript
login(Username: string, Password: string): any {
    this.http.post(`${this.url}login`, { Username, Password }, httpOptions).toPromise().then((res: any) => {
...
    })
}
```
And finally, we can create our `register()` function, which will be very similar to the `login()` functions.

```typescript
  register(Username: string, Email: string, Password: string): any {
    this.http.post(`${this.url}register`, { Username, Email, Password }).toPromise().then((res: any) => {
      if (res && res.jwt) {
        sessionStorage.setItem('jwt', res.jwt);
        this.errorSubject.next(null);
        if (res.data) {
          this.userSubject.next(res.data);
        }
        this.router.navigateByUrl('dashboard');
      } else if (res.Message) {
        this.errorSubject.next(res.Message);
      }
    });
  }
```
Great! It's time to implement our API call in the `register.component.ts` file. Also, let's implement listening for the error in the `ngOnInit()` method.

```typescript
export class RegisterComponent implements OnInit {
  error = null;

  ...

  ngOnInit(): void {
    this.userService
      .errorSubject
      .subscribe(errorMessage => {
        this.error = errorMessage;
      });
  }
  
  onRegister(): void {
    if (this.valid.username && this.valid.email && this.valid.password) {
      this.userService
        .register(this.username, this.email, this.password);
    }
  }
}
```

Perfect, let's add the `onRegister()` function to our `register.component.html` template.

```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)="onRegister()">
  Sign In
</button>
```
Great, it's time for the last step, which is adding the error notification to the template.

###8. Error notification###

In our `register.component.html` file, we are going to add the notification like in the Login Form, which will be shown if there is an error returned. 

```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! The registration is ready, and you can test it!
Remember to have the backend running.

###Conclusion###

If you didn't manage to get the code correctly and have any issues remember that you can check out the code for this lesson at our Github repository.

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

Also, remember to stay updated with our backend courses, <a href="https://www.blog.duomly.com/category/golang/">Golang Course</a> and <a href="https://www.blog.duomly.com/node-js-course-with-building-a-fintech-banking-app-lesson-1-start-the-project/">Node.js Course</a>, where the new features are appearing every week, so we can continue implementing them on the frontend.

In the next lessons, we will be asking for user data from backend and creating the money transfers.

Stay tuned and let us know in the comments what else you'd like to build!

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

Thank you for reading,
Anna from Duomly