Saturday, October 16, 2021

Compare validator using reactive forms in angular

 Comparing two input values using reactive forms in angular






Step 1 : Validation.ts


import { AbstractControl, ValidatorFn } from '@angular/forms';

export default class Validation {
  static match(controlName: string, checkControlName: string): ValidatorFn {
    return (controls: AbstractControl) => {
      const control = controls.get(controlName);
      const checkControl = controls.get(checkControlName);

      if (checkControl?.errors && !checkControl.errors.matching) {
        return null;
      }

      if (control?.value !== checkControl?.value) {
        controls.get(checkControlName)?.setErrors({ matching: true });
        return { matching: true };
      } else {
        return null;
      }
    };
  }
}

Step 2 : app-component.html

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
      <form (ngSubmit)="onSubmit()" [formGroup]="form" autocomplete="off">
        <div id="user-data" formGroupName="userData">
          <div class="form-group">
            <label for="username" class="text-warning">User Name</label>
            <input type="username" placeholder="User Name" name="username" formControlName="username"
              class="form-control" />
            <span class="text-danger"
              *ngIf="!(form.get('userData.username')?.valid) && form.get('userData.username')?.touched">Please enter
              user name</span>
          </div>
          <div class="form-group">
            <label for="email" class="text-warning">Email</label>
            <input type="text" placeholder="Email" name="email" class="form-control" formControlName="email" />
            <span class="text-danger"
              *ngIf="!(form.get('userData.email')?.valid) && form.get('userData.email')?.touched">Please enter valid
              email</span>
          </div>
        </div>
        <div class="form-group">
          <label for="password" class="text-warning">Password</label>
          <input type="password" class="form-control" name="password" formControlName="password"
            [ngClass]="{ 'is-invalid':  f.password.errors }"
            placeholder="Password" />
          <span class="text-danger" *ngIf="f.password.errors?.required && f.password.touched">Please enter
            password</span>
          <span class="text-danger" *ngIf="f.password.errors?.minlength && f.password.touched">Password must be 6
            characters
          </span>
        </div>
        <div class="form-group">
          <label for="confirmpassword" class="text-warning">Confirm Password</label>
          <input type="password" class="form-control" name="confirmpassword" formControlName="confirmpassword"
            [ngClass]="{ 'is-invalid':  f.confirmpassword.errors }"
            placeholder="Confirm Password" />
          <span class="text-danger" *ngIf="f.confirmpassword.errors?.required && f.confirmpassword.touched">Please enter
            confirm password</span>
          <span class="text-danger" *ngIf="f.confirmpassword.errors?.matching && f.confirmpassword.touched">Confirm
            Password does not match</span>
        </div>

        <h4 *ngIf="hobbies.length < 2; else t" class="text-warning">Your Hobby</h4>
        <ng-template #t>
          <h4 class="text-warning">Your Hobbies</h4>
        </ng-template>

        <div class="form-group" formArrayName="hobbies">
          <button type="button" class="btn btn-success" (click)="onAddingHobby()">Add Hobby</button>
          <div id="dynamicControls" class="form-group" *ngFor="let l of hobbies.controls; let i = index">
            <span class="col-xs-5">
              <input type="text" [placeholder]="'Hobby ' + (i + 1)" [formControlName]="i" class="form-control"></span>
            <span><button id="removeControl" type="button" class="btn btn-danger" (click)="onRemovingHobby(i)">X
              </button></span>
          </div>
        </div>
        <button type="submit" [disabled]="!this.form.valid" class="btn btn-primary">Submit</button>
      </form>
    </div>
  </div>
</div>


Step 3 : app-component.ts

import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import Validation from './utils/validation';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {
  excludedUserName: string[] = ['Test', 'test'];
  form!: FormGroup;

  constructor(private formBuilder: FormBuilder) { }
 
  ngOnInit(): void {
    this.form = this.formBuilder.group({
      'userData': new FormGroup({
        'email': new FormControl(null, [Validators.required, Validators.email]),
        'username': new FormControl(null, [Validators.required,
        this.excludedUserNames.bind(this)])
      }),
      'password': new FormControl(null, [Validators.required, Validators.minLength(6)]),
      'confirmpassword': new FormControl(null, Validators.required),
      'hobbies': new FormArray([])
    }, {
      validators: [Validation.match('password', 'confirmpassword')]
    });
  }

  onSubmit() {
    console.log(this.form);
  }

  onAddingHobby() {
    const control = new FormControl(null, Validators.required);
    this.hobbies.push(control);
  }
  onRemovingHobby(i: number) {
    this.hobbies.removeAt(i);
  }

  excludedUserNames(fromControl: FormControl): { [s: string]: boolean } | null {
    if (this.excludedUserName.indexOf(fromControl.value) !== -1) {
      return { 'excludedUserName': true };
    }
    return null;
  }

  get hobbies() {
    return this.form.get('hobbies') as FormArray;
  }
 
  get f(): { [key: string]: AbstractControl } {
    return this.form.controls;
  }
}

Friday, October 15, 2021

Adding dynamic controls using reactive forms in angular

Adding dynamic controls using reactive forms




In the above example we are capturing user name , email and his/her hobbies. User can add more than one hobby. So we add hobby control dynamically.

Step 1 : app-component.html

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
      <form (ngSubmit)="onSubmit()" [formGroup]="form" autocomplete="off">
        <div id="user-data" formGroupName="userData">
          <div class="form-group">
            <label for="username" class="text-warning">User Name</label>
            <input type="username" placeholder="User Name" name="username" formControlName="username"
              class="form-control" />
            <span class="text-danger"
              *ngIf="!(form.get('userData.username')?.valid) && form.get('userData.username')?.touched">Please enter
              user name</span>
          </div>
          <div class="form-group">
            <label for="email" class="text-warning">Email</label>
            <input type="text" placeholder="Email" name="email" class="form-control" formControlName="email" />
            <span class="text-danger"
              *ngIf="!(form.get('userData.email')?.valid) && form.get('userData.email')?.touched">Please enter valid
              email</span>
          </div>
        </div>
        <h4 *ngIf="hobbies.length < 2; else t" class="text-warning">Your Hobby</h4>
        <ng-template #t>
          <h4 class="text-warning">Your Hobbies</h4>
        </ng-template>

        <div class="form-group" formArrayName="hobbies">
          <button type="button" class="btn btn-success" (click)="onAddingHobby()">Add Hobby</button>
          <div id="dynamicControls" class="form-group" *ngFor="let hobby of hobbies.controls; let i = index">
            <span class="col-xs-5">
              <input type="text" [placeholder]="'Hobby ' + (i + 1)" [formControlName]="i" class="form-control"></span>
            <span><button id="removeControl" type="button" class="btn btn-danger" (click)="onRemovingHobby(i)">X
              </button></span>
          </div>
        </div>
        <button type="submit" [disabled]="!this.form.valid" class="btn btn-primary">Submit</button>
      </form>
    </div>
  </div>
</div>

Step 2 : app-component.ts

import { Component, OnInit } from '@angular/core';
import { FormArray, FormControl, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  excludedUserName: string[] = ['Test', 'test'];
  form!: FormGroup;
  ngOnInit(): void {
    this.form = new FormGroup({
      'userData': new FormGroup({
        'email': new FormControl(null, [Validators.required, Validators.email]),
        'username': new FormControl(null, [Validators.required,
                                this.excludedUserNames.bind(this)]),
      }),

      'hobbies': new FormArray([])
    });
  }
  onSubmit() {
    console.log(this.form);
  }

  onAddingHobby() {
    const control = new FormControl(null, Validators.required);
    this.hobbies.push(control);
  }
  onRemovingHobby(i: number) {
    this.hobbies.removeAt(i);
  }

  excludedUserNames(fromControl: FormControl): { [s: string]: boolean } | null {
    if (this.excludedUserName.indexOf(fromControl.value) !== -1) {
      return { 'excludedUserName': true };
    }
    return null;
  }

  get hobbies() {
    return this.form.get('hobbies') as FormArray;
  }
}

Monday, October 11, 2021

Subject in Angular

 What is a Subject?

Subject is a special type of Observable in RxJs Library in which we can send our data to other components or services. A Subject is like an Observable but can multicast to many observers which means subject is at the same time an Observable and an Observer.

To understand the subject we take the below example. In this example, we display user name and its status on home component and on click of user name we display user info in user component.


Step 1 : Create user.model.ts

export class User{
    userName : string = '';
    userStatus : string = '';
    constructor(userName : string , userStatus : string){
        this.userName = userName;
        this.userStatus = userStatus;
    }
}

Step 2 : Create user.service.ts

selectedUserEmitter : Subject that send User type into another component

userList : default user list

import { EventEmitter, Injectable } from "@angular/core";
import { Subject } from "rxjs";
import { User } from "../model/user.model";
@Injectable({
    providedIn: 'root'
})
export class UserService {
    selectedUserEmitter = new Subject<User>();
    userList: User[] = [{ userName: 'Mark', userStatus: 'Active' },
    { userName: 'Cris', userStatus: 'Inactive' }];

    getUserList(): User[] {
        return this.userList.slice();
    }
}

Step 3 : generate home and user component

ng g c home

ng g c user

Step 4 : home.component.html 

<div class="row" *ngFor="let user of this.userList">
    <div class="span6">
        <a (click)="onClick(user)"> <label for="UserName">User Name</label> {{user.userName}} </a>
    </div>
    <div class="span6">
        <a (click)="onClick(user)"> <label for="Status">Status</label> {{user.userStatus}} </a>
    </div>
    <hr />

</div>

home.component.ts

export class HomeComponent implements OnInit, OnDestroy {
  userList : User[] = [];
  constructor(private userService: UserService) { }
  ngOnDestroy(): void {
    this.userService.activatedEmitter.unsubscribe();
  }

  ngOnInit(): void {
  this.userList = this.userService.getUserList();
  }

  onClick(user : User){
    this.userService.selectedUserEmitter.next(user);
  }
}


Step 4 : user.component.html

<div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
    <p>{{this.selectedUserName}}</p>
    <p>{{this.selectedUserStatus}}</p>
</div>

user.component.ts

export class UserComponent implements OnInit,OnDestroy {
  selectedUserName : string = '';
  selectedUserStatus : string = '';
  constructor(private userService: UserService) { }
  ngOnDestroy(): void {
    this.userService.selectedUserEmitter.unsubscribe();
  }

  ngOnInit(): void {
    this.userService.selectedUserEmitter.subscribe(item => {
      this.selectedUserName = item.userName;
      this.selectedUserStatus = item.userStatus;
    });
  }
}

Step 5 : app.component.html

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
      <div class="panel panel-default">
        <div class="panel panel-heading">
          Details
        </div>
        <div class="panel panel-body">
          <app-home></app-home>
        </div>
      </div>
    </div>
  </div>
  <div class="row">
    <app-user></app-user>
  </div>
</div>


Custom Observable in Angular

 How to Create a Custom Observable in Angular

Angular makes use of observables as an interface to handle a variety of common asynchronous operations.

Steps to create custom observable in Angular

1. First thing is to create instance of observable with the help on Observable.create() method
2. An observable can send three types of notifications-
    
    nextWith the next value, observer sends a value that can be a number, a string or an object.
    
    error - Notify error in observable

    completeNotify the execution of observable completed

3. Subscribe an observable instance using subcribe() method
4. Unsubscribe observable using unsubscribe() in onDestroy


export class HomeComponent implements OnInit, OnDestroy {
  private onSubcription!: Subscription;
 
  constructor() { }
 
ngOnDestroy(): void {
    this.onSubcription.unsubscribe();
  }

  ngOnInit(): void {
     const customObservable = Observable.create((observer: Observer<Number>) => {
       setInterval(
         () => {
           let data = Math.floor(Math.random() * 10);
           observer.next(data);
           if (data == 6)
             observer.error("invalid number");
           else if (data == 8)
             observer.complete();
         }, 1000);
     });

     this.onSubcription = customObservable.subscribe((count: Number) => {
       console.log(count);
     },(error: string) =>
     {
      console.log(error);
     },() =>{
       console.log("completed");
     })
  }
}