Friday, November 3, 2023

Custom Validations in Angular -Part 10

 Developer writing code to perform validations to application specific is
  called "custom validations"
 Custom validations logic should be written with in static methods
 
Syntax:
     export class <validationsclassname>
     {
         static <methodname>(para:FormControl|FormGroup)
         {
              logic to perform validation
                 ...
              return({methodname:true}); //validation failed
                or
              return null;  //validation success
         }
          ...
     }


para with FormControl is required for validation based on single prop
para with FormGroup is  required for validation based on multiple props

Create a class validations.








import { FormControl, FormGroup } from "@angular/forms";

export class Validations {
    static isavailable(fc:FormControl)
    {//para fc will reference to username prop
        if(fc.value=="ramu" || fc.value=="raju")
        return({isavailable:true});
        else
        return null;
    }
    static comparepwds(fg:FormGroup)
    {
        if(fg.value.confirmpassword==fg.value.password)
        return null;
        else
        return({comparepwds:true});

    }
}

Angular Forms Sample Example -Template Driven Form

Create a Component

ng g c tdf --flat











.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-tdf',
  templateUrl: './tdf.component.html',
  styleUrls: ['./tdf.component.css']
})
export class TdfComponent  implements OnInit{
  ngOnInit(): void {
    throw new Error('Method not implemented.');
  }
  firstname:string | undefined;
  lastname:string | undefined;
  info:string | undefined;

 register(usermodel1: { valid: any; })
 {
   if(usermodel1.valid)
   this.info=this.firstname+":"+this.lastname;
 }
}


.html Changes

<form #usermodel="ngForm">
    <div style="font-size:x-large;margin:20px">
    firstname:<input [(ngModel)]="firstname" name="firstname" required>
    <span *ngIf="usermodel.controls['firstname'].invalid">
        enter firstname
    </span>
    <br>
    lastname:<input [(ngModel)]="lastname" name="lastname" required>
    <span *ngIf="usermodel.controls['lastname'].invalid && usermodel.controls['lastname'].touched">
        enter lastname
    </span>
    <br>
    <input type="button" value="register" (click)="register(usermodel)">
    <br>
    {{info}}
    </div>
  </form>


Output

















MDF vs TDF:
-----------
1.MDF will apply validations to model props with in component class
  TDF  "     "       "       to control with in template

2.MDF will provide programming flexibility
  [like dynamic controls creation and validations can be verified in router guard]

 TDF will not provide programming flexibility

3.MDF makes validations unit testing easy
  TDF doesn't provide validations unit testing easy

4.MDF is not developer friendly
  TDF is developer friendly


Thursday, November 2, 2023

Angular Forms Part 8 (Forms Array)

 Form Array class:


This is used to create an array of form controls (or) form groups (or) nested form array

The main importance of form array is dynamic controls creation.

This class comes with 2 unique methods of an array
 1.push(item)--it will add an item into form array
 2.removeItem(index)--it will remove an element from formarray

requirement:
     cart model
        |
   Cust name--Form Control
   address --Form Control
     prods --Form Array[collection of Form Groups, Each Form Group will maintain one prod info]

Design a form with the following fields

    Cust name: textbox
     address:
         text area[multiline textbox]
         add product button

  productid      prod name     price
  textbox         textbox          textbox       remove

    ...      ...       ...
 
         save button




Create a component

ng g c mdf3 --flat

 
.ts Changes

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

@Component({
  selector: 'app-mdf3',
  templateUrl: './mdf3.component.html',
  styleUrls: ['./mdf3.component.css'],
})
export class Mdf3Component {
  cartmodel: FormGroup;
  custinfo: string | undefined;
  prodsinfo: string | undefined;

  createFormGroup(): FormGroup {
    return new FormGroup({
      pid: new FormControl('', [Validators.required]),
      pname: new FormControl('', [Validators.required]),
      price: new FormControl('', [Validators.required]),
    });
  }
  constructor() {
    //build a model
    this.cartmodel = new FormGroup({
      custname: new FormControl('', [Validators.required]),
      address: new FormControl('', [Validators.required]),
      prods: new FormArray([this.createFormGroup()]),
    });
  }
  addproduct() {
    (<FormArray>this.cartmodel.get('prods')).push(this.createFormGroup());
    //get("prods") will return AbstractControl class,this should be typecasted to FormArray class to access push method
  }
  delete(i: number) {
    //para i will recieve index number
    (<FormArray>this.cartmodel.get('prods')).removeAt(i);
  }
  save() {
    this.custinfo =
      this.cartmodel.value.custname + ':' + this.cartmodel.value.address;
    this.prodsinfo = '';
    for (let p of this.cartmodel.value.prods) {
      this.prodsinfo =
        this.prodsinfo + p.pid + ':' + p.pname + ':' + p.price + '<br>';
    }
  }
}


.html Changes

<form [formGroup]="cartmodel">
    <div style="font-size:x-large;margin:15px">
   custname:<input formControlName="custname"> <br>
   address : <br>
   <textarea rows="5" cols="30" formControlName="address"></textarea>
   <br>
   <input type="button" value="addproduct" (click)="addproduct()">
   <br>
   <table border="1">
       <tr>
           <th>pid</th>
           <th>pname</th>
           <th>price</th>
           <th>option</th>
       </tr>
       <ng-container formArrayName="prods">
        <tr *ngFor="let p of cartmodel.get('prods')?.value;let i=index" [formGroupName]="i">
            <td>
                <input formControlName="pid">
            </td>
            <td>
               <input formControlName="pname">
           </td>
           <td>
               <input formControlName="price">
           </td>
           <td>
            <input type="button" value="remove" (click)="delete(i)">
        </td>
        </tr>
      </ng-container>
   </table>
   <br>
   <input type="button" value="save" (click)="save()">
   <br>
   {{custinfo}}
   <br>
   <span [innerHtml]="prodsinfo"></span>
   </div>
   </form>
   

note:
-----
Initially prods form array will have only one form group, so ngfor will create
 one table row with textboxes
addproduct button click will add one new formgroup into prods formarray,accordingly
 ngfor will create a new table row with textboxes

*remove button click will remove formgroup from prods formarray based on
 index,accordingly table row will be removed


Output





Angular Forms Part 7 DropDownList

.html Changes .

<form #studentForm="ngForm" (ngSubmit)="RegisterStudent(studentForm)">

        <div class="form-group">
          <label for="branch">Branch</label>
          <select id="branch" name="branch" ngModel class="form-control">
            <option value="1">CSE</option>
            <option value="2">ETC</option>
            <option value="3">Mechanical</option>
            <option value="4">Electrical</option>
          </select>
        </div>
        <div class="panel-footer">
          <button class="btn btn-primary" type="submit">Submit</button>
        </div>
    </form>


.ts Changes

@Component({
  selector: 'app-formsvalidation',
  templateUrl: './formsvalidation.component.html',
  styleUrls: ['./formsvalidation.component.css']
})
export class FormsvalidationComponent {
 
  RegisterStudent(studentForm: NgForm): void {  
    console.log(studentForm.value);
  }
}


OutPut














Dropdownlist item selected 
If we include the selected attribute on the dropdownlist, then we may expect that option or item to be selected by default. But in angular template driven forms, that will not work. Lets include the “selected” attribute on the ETC branch option to verify this



 <select id="branch" name="branch" class="form-control">
            <option value="1">CSE</option>
            <option value="2" selected>ETC</option>
            <option value="3">Mechanical</option>
            <option value="4">Electrical</option>
          </select>



ETC department is not selected by default when the page load.

However, if you remove the “ngModel” directive from the select list as shown below, then you will see that the ETC branch is selected when the form is load.













Output















we use the “ngModel” directive in angular for two-way data binding. So when we put the ngModel directive back into the control then the “selected” attribute will not work on the drop down list or select list. If we remove the ngModel directive from the control then selected attribute work but two way data binding will not work.

To Make it work


.html 

<form #studentForm="ngForm" (ngSubmit)="RegisterStudent(studentForm)">
        <div class="form-group">
          <label for="branch">Branch</label>
          <select id="branch" name="branch" [(ngModel)]="BranchId" class="form-control">
            <option value="1">CSE</option>
            <option value="2">ETC</option>
            <option value="3">Mechanical</option>
            <option value="4">Electrical</option>
          </select>
        </div>
        <div class="panel-footer">
          <button class="btn btn-primary" type="submit">Submit</button>
        </div>
    </form>


.ts

export class FormsvalidationComponent {
  BranchId = "2";
  RegisterStudent(studentForm: NgForm): void {  
    console.log(studentForm.value);
  }


Output



 











Dynamically Binding Drop Down

.html Changes


<form #studentForm="ngForm" (ngSubmit)="RegisterStudent(studentForm)">
        <div class="form-group">
          <label for="branch">Branch</label>
          <select id="branch" name="branch" class="form-control" ngModel>
            <option *ngFor="let branch of Branches" [value]="branch.id">
              {{branch.name}}
            </option>
          </select>
        </div>
        <div class="panel-footer">
          <button class="btn btn-primary" type="submit">Submit</button>
        </div>
    </form>


.ts Changes

@Component({
  selector: 'app-formsvalidation',
  templateUrl: './formsvalidation.component.html',
  styleUrls: ['./formsvalidation.component.css']
})
export class FormsvalidationComponent {
 
  Branches: any[] = [
    { id: 1, name: 'CSE' },
    { id: 2, name: 'ETC' },
    { id: 3, name: 'Mechanical' },
    { id: 4, name: 'Electrical' }
  ];

  RegisterStudent(studentForm: NgForm): void {  
    console.log(studentForm.value);
  }
}


Output




Angular Forms Part 6 CheckBox



 .html Changes

<form #studentForm="ngForm" (ngSubmit)="RegisterStudent(studentForm)">
        <div class="form-group">
          <div class="form-control">
            <label class="checkbox-inline">
              <input type="checkbox" name="isAccept" ngModel>Accept Terms & Conditions
            </label>
          </div>
        </div>
        <div class="panel-footer">
          <button class="btn btn-primary" type="submit">Submit</button>
        </div>
    </form>


In the above code, we set the name attribute of the input element checkbox to isAccept. We have not set the value property here. This is because its value can be true of false. If the checkbox is checked or selected then the value is true else the value is false.


.ts Changes

export class FormsvalidationComponent {
  RegisterStudent(studentForm: NgForm): void {  
    console.log(studentForm.value);
  }
}


Output











Default Check Box Checked

<input type=”checkbox” name=”isAccept” ngModel checked>Accept Terms & Conditions

With the above changes in place, now browse the application and you will see the the checkbox is not checked by default when the page load.

However, if we remove the “ngModel” directive from the checkbox as shown below, then you will see that the checkbox is checked when the form is load.


 <input type=”checkbox” name=”isAccept” checked>Accept Terms & Conditions


How to make it work

.ts Changes

export class FormsvalidationComponent {
  isAccept = true;
  RegisterStudent(studentForm: NgForm): void {  
    console.log(studentForm.value);
  }
}

.html

<div class="form-group">
          <div class="form-control">
            <label class="checkbox-inline">
              <input type="checkbox" name="isAccept" [(ngModel)]="isAccept">Accept Terms & Conditions
            </label>
          </div>
</div>


Output














Kubernetes

Prerequisites We assume anyone who wants to understand Kubernetes should have an understating of how the Docker works, how the Docker images...