TechNet Guru Awards February 2019 - Miscellaneous - SILVER
I won the SILVER medal for one of my article on TechNet Guru competition
Source Code
GutHub : angular-zingchart
import {PhoneValidator} from './directives/input-validators/phone-validator.directive'; import {EmailValidator} from './directives/input-validators/email-validator.directive'; import {SSNValidator} from './directives/input-validators/ssn-validator.directive';
@NgModule({ declarations: [ AppComponent,
//validate email import { NG_VALIDATORS, FormControl, ValidatorFn, Validator } from '@angular/forms'; import { Directive } from '@angular/core';
@Directive({ selector: '[emailvalidator][ngModel]', providers: [ { provide: NG_VALIDATORS, useExisting: EmailValidator, multi: true } ] })
export class EmailValidator implements Validator { validator: ValidatorFn;
constructor() { this.validator = this.emailValidator(); }
validate(c: FormControl) { return this.validator(c); }
emailValidator(): ValidatorFn { return (c: FormControl) => { if(c.value == "") { return null; } let isValid = /^[_a-z0-9]+(\.[_a-z0-9]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/ .test(c.value); //email if (isValid) { return null; } else { return { emailvalidator: { valid: false } }; } } } }
We can validate Phone no field using this regular expression, It allows to enter phone no in +11111111111 format.
//validate phone no import { NG_VALIDATORS, FormControl, ValidatorFn, Validator } from '@angular/forms'; import { Directive } from '@angular/core';
@Directive({ selector: '[phonevalidator][ngModel]', providers: [ { provide: NG_VALIDATORS, useExisting: PhoneValidator, multi: true } ] })
export class PhoneValidator implements Validator { validator: ValidatorFn; constructor() { this.validator = this.phoneValidator(); } validate(c: FormControl) { return this.validator(c); } phoneValidator(): ValidatorFn { return (c: FormControl) => { if(c.value == "") { return null; } let isValid = /^\+[0-9]{11}$/.test(c.value); if (isValid) { return null; } else { return { phonevalidator: { valid: false } }; } } } }
npm install --save norwegian-national-id-validator
You can find the following directive has used installed npm package to validate norwegian ssn no
//validate ssn import { NG_VALIDATORS, FormControl, ValidatorFn, Validator } from '@angular/forms'; import { Directive } from '@angular/core'; import { validateNorwegianIdNumber } from 'norwegian-national-id-validator';
@Directive({ selector: '[ssnvalidator][ngModel]', providers: [ { provide: NG_VALIDATORS, useExisting: SSNValidator, multi: true } ] })
export class SSNValidator implements Validator { validator: ValidatorFn; constructor() { this.validator = this.ssnValidator(); } validate(c: FormControl) { return this.validator(c); } ssnValidator(): ValidatorFn { return (c: FormControl) => { if(c.value == "") { return null; } let isValid = /^[0-9]{6}( )[0-9]{5}$/g.test(c.value); if (isValid) { var format = validateNorwegianIdNumber(c.value.replace(/ /g,'')); if(format){ return null; } else{ return { ssnvalidator: { valid: false } }; } } else { return { ssnvalidator: { valid: false } }; } } } }
.invalid-feedback-select {
width: 100%;
font-size: 80%;
color: #dc3545;
}
"styles": [ "./node_modules/bootstrap/dist/css/bootstrap.min.css", "src/styles.css", "src/assets/css/common.scss" ],
ng new <projectname>

ng build
ng serve
import { NgSelectModule } from '@ng-select/ng-select';
export class AppComponent implements OnInit {
import { Component, OnInit } from '@angular/core';
ngOnInit(){
}
namespace input_restrictions_dal.Dto { public class MasterData { public IEnumerable Gender { get; set; } public IEnumerable PostalCode { get; set; } }
public class DropDownField { public int Id { get; set; } public string Value { get; set; } }
public class PostalCodefield { public int Id { get; set; } public string Code { get; set; } public string City { get; set; } } }
namespace input_restrictions_dal.Enum { public enum Gender { Male = 1, Female = 2 } }
public void ConfigureServices(IServiceCollection services) { services.AddCors(o => { o.AddPolicy("AllowAnyOrigin", builderCor => { builderCor.AllowAnyOrigin().AllowCredentials().AllowAnyHeader().AllowAnyMethod(); }); o.DefaultPolicyName = "AllowAnyOrigin"; }); }
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseHttpsRedirection(); app.UseCors("AllowAnyOrigin"); app.UseMvc(); }
using input_restrictions_dal.Dto;
namespace input_restrictions_api.Service
{
public interface IStudentService
{
MasterData GetMasterData();
}
}
using System; using System.Collections.Generic; using input_restrictions_dal.Dto; using input_restrictions_dal.Enum; using System.Linq;
namespace input_restrictions_api.Service { public class StudentService : IStudentService { public MasterData GetMasterData() { MasterData masterData = new MasterData { Gender = (from Gender g in Enum.GetValues(typeof(Gender)) select new { ID = Convert.ToInt32(g), Name = g.ToString() }).Select(s => new DropDownField() { Id = s.ID, Value = s.Name }).ToList(), PostalCode = new List { new PostalCodefield {Id =1, Code="00130", City = "Colombo"}, new PostalCodefield { Id = 1, Code = "20000", City = "Kandy" }, new PostalCodefield { Id = 1, Code = "80000", City = "Galle" } } }; return masterData; } } }
using Microsoft.AspNetCore.Mvc; using input_restrictions_api.Service; using input_restrictions_dal.Dto; using System.Net;
namespace input_restrictions_api.Controllers { [Route("api/[controller]")] [ApiController] public class StudentController : ControllerBase {
private readonly IStudentService _studentService;
public StudentController() { _studentService = new StudentService(); }
[HttpGet("masterdata")] [ProducesResponseType(typeof(MasterData), (int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.NotFound)] public ActionResult MasterData() { MasterData masterData = _studentService.GetMasterData(); return Ok(masterData); } } }
import { Component, OnInit } from '@angular/core'; import { MasterData } from './shared/masterdata.model'; import { DataService } from './shared/data.service'; import { Member } from './shared/member.model';
@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] })
export class AppComponent implements OnInit { masterData: MasterData; member: Member;
constructor(private dataService : DataService) {
}
ngOnInit(){ this.masterData = new MasterData(); this.member = new Member(); this.GetMasterData(); }
GetMasterData () { this.dataService.GetMasterData().subscribe( data => { this.masterData = data; }, err => { throw err;
} ); }
onPostalNoChange(event) { if (event == null) { this.member.postalPlace = ''; } else { this.masterData.postalCode.forEach(entry => { if (entry.code == event.code) { this.member.postalPlace = entry.city; } }); } }
You can see the app.module file, all the imported modules and custom directives we created are added.
import { NgSelectModule } from '@ng-select/ng-select'; import { HttpClientModule } from '@angular/common/http';
import { LettersOnlyDirective} from './directives/letters.directive'; import {PhoneNoDirective} from './directives/phoneno.directive'; import {SSNDirective} from './directives/ssn.directive'; import {LettersNumbersOnly} from './directives/letters-numbers.directive'; import {DecimalNumberOnlyDirective} from './directives/decimal-number.directive';
import { HttpClient } from '@angular/common/http' import { Observable } from 'rxjs' import { MasterData } from "./masterdata.model"; import { environment } from "src/environments/environment"; import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class DataService { constructor(private http : HttpClient) {}
GetMasterData () : Observable<MasterData>{ return this.http.get(environment.api_url
+ '/student/masterdata'); } }
Let's see the model classes in the client application. we have to map service method data in the frontend classes, so we created a MasterData class as shown below.
export class PostalCodeMasterData { zipCodeId : number; code : string; city : string; }
export class Member { firstName: string; lastName: string; phone: string; email: string; ssn: string; gender: string; postalNo: number; postalPlace: string; addressLine1: string; addressLine2: string; gpa: string; certificateIssued: boolean; }
We can restrict inputs in firstname and lastname fields using this directive, specials keys are allowed other than that.
//validate firstname and lastname import { Directive, ElementRef, HostListener} from '@angular/core';
@Directive({ selector: '[lettersOnly]' })
export class LettersOnlyDirective{ private regex: RegExp = new RegExp(/^[a-zA-Z]+$/g); private specialKeys: Array = ['Backspace', 'Tab', 'End', 'Home'];
constructor(private el: ElementRef) { }
@HostListener('paste', ['$event']) onkeydown(e: any) { var value = e.clipboardData.getData('Text'); if (value && !String(value).match(this.regex)) { event.preventDefault(); } }
@HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) { if (this.specialKeys.indexOf(event.key) !== -1) { return; }
let current: string = this.el.nativeElement.value; let next: string = current.concat(event.key); if (next && !String(next).match(this.regex)) { event.preventDefault(); } } }
We can restrict inputs for a phone no filed using this directive, it allows only to enter + value and then numbers
//validate phone no import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({ selector: '[phoneOnly]' })
export class PhoneNoDirective { private regex: RegExp = new RegExp(/^(\+)[0-9]{0,11}$/g); private specialKeys: Array = ['Backspace', 'Tab', 'End', 'Home'];
constructor(private el: ElementRef) { }
@HostListener('paste', ['$event']) onkeydown(e: any) { var pastedvalue = e.clipboardData.getData('Text'); var value = this.el.nativeElement.value + pastedvalue; if (value && !String(value).match(this.regex)) { event.preventDefault(); } }
@HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) { if (this.specialKeys.indexOf(event.key) !== -1) { return; } let current: string = this.el.nativeElement.value; let next: string = current.concat(event.key); if (next && !String(next).match(this.regex)) { event.preventDefault(); } } }
Check this directive restricts ssn no in noregian format, please have a look for sample ssn nos, How to generate a ssn number in norway
//validate ssn import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({ selector: '[ssnNumber]' })
export class SSNDirective { private regex: RegExp = new RegExp(/^[0-9]{1,6}( ){0,1}([0-9]){0,5}$/g); private specialKeys: Array = ['Backspace', 'Tab', 'End', 'Home'];
constructor(private el: ElementRef) { }
@HostListener('paste', ['$event']) onkeydown(e: any) { var pastedvalue = e.clipboardData.getData('Text'); var value = this.el.nativeElement.value + pastedvalue; if (value && !String(value).match(this.regex)) { event.preventDefault(); } }
@HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) { if (this.specialKeys.indexOf(event.key) !== -1) { return; } let current: string = this.el.nativeElement.value; let next: string = current.concat(event.key); if (next && !String(next).match(this.regex)) { event.preventDefault(); } } }
We can validate address fields with the given directive, it allows to enter letters and number only, no special characters
//validate address line 1 and 2 import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({ selector: '[lettersNumbersOnly]' })
export class LettersNumbersOnly { private regex: RegExp = new RegExp(/^[a-zA-Z0-9 ]+$/g); private specialKeys: Array = ['Backspace', 'Tab', 'End', 'Home'];
constructor(private el: ElementRef) { }
@HostListener('paste', ['$event']) onkeydown(e: any) { var value = e.clipboardData.getData('Text'); if (value && !String(value).match(this.regex)) { event.preventDefault(); } } @HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) { if (this.specialKeys.indexOf(event.key) !== -1) { return; } let current: string = this.el.nativeElement.value; let next: string = current.concat(event.key); if (next && !String(next).match(this.regex)) { event.preventDefault(); } } }
We can validate for decimal numbers like gpa value with following regular expression