paint-brush
How to Reset Password with Node.js and Angular [Part 2]by@haykoyaghubyan
20,115 reads
20,115 reads

How to Reset Password with Node.js and Angular [Part 2]

by HaykOctober 15th, 2019
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

In this 2nd part of our tutorial, we are going to continue our journey of creating reset password functionality. In the 1st part, we completed the back-end with Node.js Express and Node mailer, created an API which will use in this part in Angular. Let’s create a new angular project and run it. We need to create an app-routing. module for navigating needed pages in our site. The names of each rout already makes it easier to understand which rout for what should be used.
featured image - How to Reset Password with Node.js and Angular [Part 2]
Hayk HackerNoon profile picture

In this 2nd part of our tutorial, we are going to continue our journey of creating reset password functionality. In the 1st part, we completed the back-end with Node.js Express and Node mailer, created an API which will use in this part in Angular. Let’s get started.

Creating a new angular project

Let’s create a new project and run it.

ng new angular-reset-password
cd angular-reset-password
ng serve

We are going to have several pages so need to create an app-routing.module.ts for navigating needed pages in our site,

import { NgModule } from '@angular/core';
import{Routes, RouterModule} from '@angular/router';
import { SigninComponent } from './components/signin/signin.component';
import { SignupComponent } from './components/signup/signup.component';
import { RequestResetComponent } from './components/request-reset/request-reset.component';
import { ResponseResetComponent } from './components/response-reset/response-reset.component';

const routes: Routes = [
  {
    path: 'sign-in',
    component: SigninComponent,
  },
  {
    path: 'sign-up',
    component: SignupComponent,
  },
  {
    path: 'request-reset-password',
    component: RequestResetComponent,
  },
  {
      path: 'response-reset-password/:token',
      component: ResponseResetComponent
    },
  {
    path: '**',
    redirectTo: 'sign-in'
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class MainRoutingModule {}

The names of each rout already makes it easier to understand which rout for what should be used. You may also notice that

response-reset-password
includes a
:token

That's the

resettoken
that we send via email in the back-end attached to the URL.
However before creating the components for each rout we need to generate an Angular service where we will use our API from the first part.

Creating an Auth service

ng generate service auth

Let’s update our service file:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

const BASEURL = 'http://localhost:3000/api/resetpassword';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  constructor(private http: HttpClient) { }

  registerUser(body): Observable<any> {
    return this.http.post(`${BASEURL}/register`, body);
  }

  loginUser(body): Observable<any> {
    return this.http.post(`${BASEURL}/login`, body);
  }

  requestReset(body): Observable<any> {
    return this.http.post(`${BASEURL}/req-reset-password`, body);
  }

  newPassword(body): Observable<any> {
    return this.http.post(`${BASEURL}/new-password`, body);
  }

  ValidPasswordToken(body): Observable<any> {
    return this.http.post(`${BASEURL}/valid-password-token`, body);
  }
  }

The last

ValidPasswordToken
is for validating the token and checking if it’s still active. Other ones looks very descriptive. It’s time to create the components.

Creating a Signup component

It’s time to make Signup component functional.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-signup',
  templateUrl: './signup.component.html',
  styleUrls: ['../signin/signin.component.css']

})
export class SignupComponent implements OnInit {
  SignupForm: FormGroup;
  forbiddenEmails: any;
  errorMessage: string;

  constructor(
    private fb: FormBuilder,
    private authService: AuthService,
    private router: Router,
  ) {
    this.buildSignupForm();
  }

  ngOnInit() {
  }
 
  private buildSignupForm() {
    this.SignupForm = this.fb.group({
      username: [null, [Validators.required]],
      email: [null, [Validators.required, Validators.email], this.forbiddenEmails],
      password: [null, [Validators.required, Validators.minLength(4)]],
    });
  }

  onSubmit() {
    this.SignupForm.reset();
  }

  signupUser() {
    this.authService.registerUser(this.SignupForm.value).subscribe(
      data => {
        this.SignupForm.reset();
        setTimeout(() => {
          this.router.navigate(['sign-in']);
        }, 3000);
      },
      err => {
        if (err.error.msg) {
          this.errorMessage = err.error.msg[0].message;
        }
        if (err.error.message) {
          this.errorMessage = err.error.message;
        }
      }
    );
  }
}



As you see it’s just a simple reactive form supported by Angular. We also created

SignupUser()
function for sending the data into the server and creating the user. Let’s create an HTML template for this component.

<div class="container-fluid form">
    <div class="row form-row ">
        <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
            <div class="card my-5">
                <div class="card-body">
                    <h5 class="card-title text-center">Sign Up</h5>
                    <div>
                        <div id="errorMsg" *ngIf="errorMessage">
                            <span>{{errorMessage}}</span>
                        </div>
                        <form action="" [formGroup]="SignupForm" (ngSubmit)="signupUser()">
                            <div class="form-group form-signup">
                                <input _ngcontent-c0="" class="form-control form-control-lg" placeholder="Username"
                                       type="text" id="username" formControlName="username" />
                                <span *ngIf="!SignupForm.get('username').valid && SignupForm.get('username').touched"
                                      class="help-block">Please enter a valid username!</span>
                            </div>
                            <div class="form-group">
                                <input _ngcontent-c0="" class="form-control form-control-lg" placeholder="E-mail" type="text"
                                       id="email" formControlName="email" />
                                <span *ngIf="!SignupForm.get('email').valid && SignupForm.get('email').touched" class="help-block">
                                    Please
                                    enter a valid email!
                                </span>
                            </div>
                            <div class="form-group">
                                <input class="form-control form-control-lg" placeholder="Password" type="password"
                                       formControlName="password" />
                                <span *ngIf="!SignupForm.get('password').valid && SignupForm.get('password').touched"
                                      class="help-block">Password is required and must have more than 4 characters!</span>
                            </div>
                            <div class="form-group">
                                <button type="submit" class=" btn btn-primary" (ngSubmit)="signupUser()">Sign Up</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

It will look like this:

You can style it as you wish. This tutorial is mainly about functional part and we will not spend time on CSS.

That’s it. Let's create a Forgot password component where we should submit our email for receiving a link in our inbox containing a link to new page where we can change our password.

Creating RequestReset Component

Nothing special will be in this component. We just will create another Angular reactive form that will check if the email is valid and then will use RequestResetUser

()
function for sending the data.

import { Component, OnInit } from '@angular/core';
import { FormGroup, Validators, FormControl } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-request-reset',
  templateUrl: './request-reset.component.html',
})
export class RequestResetComponent implements OnInit {
  RequestResetForm: FormGroup;
  forbiddenEmails: any;
  errorMessage: string;
  successMessage: string;
  IsvalidForm = true;

  constructor(
    private authService: AuthService,
    private router: Router,
   ) {

  }


  ngOnInit() {

    this.RequestResetForm = new FormGroup({
      'email': new FormControl(null, [Validators.required, Validators.email], this.forbiddenEmails),
    });
  }


  RequestResetUser(form) {
    console.log(form)
    if (form.valid) {
      this.IsvalidForm = true;
      this.authService.requestReset(this.RequestResetForm.value).subscribe(
        data => {
          this.RequestResetForm.reset();
          this.successMessage = "Reset password link send to email sucessfully.";
          setTimeout(() => {
            this.successMessage = null;
            this.router.navigate(['sign-in']);
          }, 3000);
        },
        err => {

          if (err.error.message) {
            this.errorMessage = err.error.message;
          }
        }
      );
    } else {
      this.IsvalidForm = false;
    }
  }
}


HTML template of this component will be almost the same as for

SignUp 
component. 

<div class="container-fluid form">
    <div class="row form-row ">
        <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
            <div class="card my-5">
                <div class="card-body">
                    <h5 class="card-title text-center">Forgot Password</h5>
                    <div>
                        <div id="errorMsg" *ngIf="errorMessage">
                            <span>{{errorMessage}}</span>
                        </div>
                        <div id="successMsg" *ngIf="successMessage">
                            <span>{{successMessage}}</span>
                        </div>
                        <form action="" [formGroup]="RequestResetForm" (ngSubmit)="RequestResetUser(RequestResetForm)">
                            <div class="form-group">
                                <input _ngcontent-c0="" class="form-control form-control-lg" placeholder="email"
                                    type="text" id="email" formControlName="email" />
                                <span *ngIf="!RequestResetForm.get('email').valid && !IsvalidForm"
                                    class="help-block">Please enter a valid email!</span>
                            </div>
                            <div class="form-group">
                                <div>
                                    <button type="submit" class=" btn btn-primary">Reset
                                        Password</button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

Here is how will it look like:

The last component that we are going to build is

ResponseReset
 
component.

Creating ResponseReset Component

This page will be navigated from your email that includes the URL with token. Let’s get started:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { Router, ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-request-reset',
  templateUrl: './response-reset.component.html',

})
export class ResponseResetComponent implements OnInit {
  ResponseResetForm: FormGroup;
  errorMessage: string;
  successMessage: string;
  resetToken: null;
  CurrentState: any;
  IsResetFormValid = true;
  constructor(
    private authService: AuthService,
    private router: Router,
    private route: ActivatedRoute,
    private fb: FormBuilder ) {

    this.CurrentState = 'Wait';
    this.route.params.subscribe(params => {
      this.resetToken = params.token;
      console.log(this.resetToken);
      this.VerifyToken();
    });
  }


  ngOnInit() {

    this.Init();
  }

  VerifyToken() {
    this.authService.ValidPasswordToken({ resettoken: this.resetToken }).subscribe(
      data => {
        this.CurrentState = 'Verified';
      },
      err => {
        this.CurrentState = 'NotVerified';
      }
    );
  }

  Init() {
    this.ResponseResetForm = this.fb.group(
      {
        resettoken: [this.resetToken],
        newPassword: ['', [Validators.required, Validators.minLength(4)]],
        confirmPassword: ['', [Validators.required, Validators.minLength(4)]]
      }
    );
  }

  Validate(passwordFormGroup: FormGroup) {
    const new_password = passwordFormGroup.controls.newPassword.value;
    const confirm_password = passwordFormGroup.controls.confirmPassword.value;

    if (confirm_password.length <= 0) {
      return null;
    }

    if (confirm_password !== new_password) {
      return {
        doesNotMatch: true
      };
    }

    return null;
  }


  ResetPassword(form) {
    console.log(form.get('confirmPassword'));
    if (form.valid) {
      this.IsResetFormValid = true;
      this.authService.newPassword(this.ResponseResetForm.value).subscribe(
        data => {
          this.ResponseResetForm.reset();
          this.successMessage = data.message;
          setTimeout(() => {
            this.successMessage = null;
            this.router.navigate(['sign-in']);
          }, 3000);
        },
        err => {
          if (err.error.message) {
            this.errorMessage = err.error.message;
          }
        }
      );
    } else { this.IsResetFormValid = false; }
  }
}

Firstly it verifies the token then just compares 2 passwords to see if they match and as the last step it sends the updated password to the back-end. That’s it! We can create a HTML template for it.

<div class="container-fluid form">
    <div class="row" *ngIf="CurrentState=='Wait'">
        <div class="col-md-12  close-form">
            <h2> Please Wait...</h2>
        </div>
    </div>
    <div class="row"
        *ngIf="CurrentState=='NotVerified'">
        <div class="col-md-12">
            <h2> Invalid URL.</h2>
        </div>
    </div>
    <div class="row" *ngIf="CurrentState=='Verified'">
        <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
            <div class="card card-signin my-5">
                <div class="card-body">
                    <h5 class="card-title text-center">Set New Password</h5>
                    <div>
                        <div id="errorMsg" *ngIf="errorMessage">
                            <span>{{errorMessage}}</span>
                        </div>
                        <div id="successMsg" *ngIf="successMessage">
                            <span>{{successMessage}}</span>
                        </div>
                        <form action="" [formGroup]="ResponseResetForm" (ngSubmit)="ResetPassword(ResponseResetForm)">
                            <div class="form-group">
                                <input _ngcontent-c0="" class="form-control form-control-lg" placeholder="Password"
                                    type="password" id="password" formControlName="newPassword" />
                                <span *ngIf="!ResponseResetForm.get('newPassword').valid && !IsResetFormValid"
                                    class="help-block">Password is required with atleast 4 characters.</span>
                            </div>
                            <div class="form-group">
                                <input _ngcontent-c0="" class="form-control form-control-lg"
                                    placeholder="Confirm Password" type="password" id="cpassword"
                                    formControlName="confirmPassword" />
                                <span *ngIf="!ResponseResetForm.get('confirmPassword').valid && !IsResetFormValid"
                                    class="help-block">. </span>
                                <span
                                    *ngIf="ResponseResetForm.get('confirmPassword').valid && (ResponseResetForm.get('confirmPassword').value != ResponseResetForm.get('newPassword').value) && !IsResetFormValid"
                                    class="help-block">Confirm Password does not match with password.</span>
                            </div>
                            <div class="form-group">
                                <div>

                                    <button type="submit" class="  btn btn-primary">Update
                                        Password</button>

                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

Based on condition it shows the right part of the template.

Here is how it will look like:

That’s all! Hope this tutorial was helpful for you.
Also don’t forget to include components in app.module.ts

Conclusion

You can get the full source code here:
Github