Introduction
This article is going to describe how to restrict some values typing in a text box input field, We have used Angular 6 to develop this application using Visual Studio Code as the IDE, Let's see how to do it
Background
- If you love to start with .NET Core on a Linux server, check what are the basic things you have to do, Install .NETCore in a Linux server
- Say Hello from .NET Core application in a Linux server,.NET Core with a Linux server: Hello World!
- If you are interested in open source platforms and want to try out .NET Core application development in Linux, try with these steps,.NETCore: Create a web application with a Linux server
- If you want to know how to create an ASP.NET Core service application check this article, ASP.NETCore: Create a Web API application
- If you want to show a loading panel on the screen using ASP.NET Core, go through this article, ASP.NET Core : How to show a loading panel in a page
- If you like to use template generators for .NET Core this is the ideal article for you, .NET Core: Create web application with Yeoman template generator
- When you are developing ASP.NET Core web applications, security is a crucial thing, follow this article to know more about it, Secure your .NETCore web applications using IdentityServer 4
- Check how to show a confirmation dialog with jquery from this post, ASP.NET Core : How to show a confirmation dialog with jquery
- If you want to try out advanced features in jquery dialog on top of .NET Core, this will be a great article for you, ASP.NET Core : Advanced JQuery dialog actions
- If you are interested in user authentication & ASP.NET Identity follow this link, ASP.NET Identity: Customize User Authentication
- You can send a simple smtp email by checking this article, C#: Create a simple SMTP email with HTML body
- Check this article to know how to use a windows service to fire an email How to fire an email using a windows service
- If you ever want to log error messages, warning or any information in your application, you have to select a logging framework, Go through this article and learn what are the available logging frameworks, Log messages using NLog framework
- Check this article and learn how to use hashing and salting to protect your passwords, keys C#: How to generate a unique key or password using salting + hashing
- If you are a LINQ query fan and want to know few basic tricks, this is the article for you LINQ - list update tricks
- If you are interested to follow on ODATA queries, check this article ODATA Reads with Parameters
- Go through ODATA Reads to know about read queries with ODATA
- If you are interested to know about Azure storage, blobs check this article,Send smtp email with Azure blob storage attachments
- We are going to create a Function app and publish that in Azure, if you are curious to know more about Azure functions check this one, Azure Function App: Create a trigger on Cosmos DB
- If you are interested in Microsoft Graph and want to know more about Outlook API, check this article, NET Core: Building Function app with Microsoft Graph API and Azure Functions
- If you like to know about Microsoft Graph and how we can integrate our business solution with it, go through this article, .NET Core: Process a Excel file with Microsoft Graph API & Azure Function
- Check this article and get to know how to work with Azure Cosmos DB - Document API, Explore Azure Cosmos DB - document API
- Learn how to map your on premise database in to a cloud NOSQL based database, Azure Cosmos DB: Designing your data structure
- You can see a how to load a partial view using ASP.NET MVC ASP.NET Core MVC: How to load a partial view
Create Angular project
Let's create an angular project from Visual Studio Code terminal window, Open Visual Studio Code and navigate to the menu, click on Terminal and then New Terminal. You can type ng new command to create a new angular project as follows,
ng new <projectname>
A new project is created and you can check file explorer to check created files, We are going to change app.component.html and insert a form with some text inputs
Let's build the angular application with build command,
ng build
Run the application and try to access it from http://localhost:4200/
ng serve
You can see the application in the browser like this,
Let's change app.component.html page and add a student creation form like this,
We want to add a dropdown control to select Gender value, let's add it
When you add ng-select component, it shows following parser error, it says ng-select is not a known element,
Let's install ng-select package to this solution and check how it works
We have to import ng-select module in app.module file to use it in the solution
import { NgSelectModule } from '@ng-select/ng-select';
You can see student create form as below, its working fine since we added necessary libraries like ng-select library
Let's inspect the code and check how it works, You can see how bootstrap classes and input controls have been used. Postal No and Gender values rendered as dropdown controls. We have to fetch some values from the server and bind into it. Let's try to start with that
We have partially completed implementing HTML view, let's try to fill initial data in to form such as Gender and Postal code dropdown values,
We have to get data from the server when form loads, so let's implement ngOnInit event in app.component.ts, before that we have to get necessary libraries, let's implement OnInit in the component as below
export class AppComponent implements OnInit {
It shows cannot find name 'OnInit', we haven't added necessary libraries to the .ts file,
Let's add OnInit library from angular/core and try to resolve the issue
import { Component, OnInit } from '@angular/core';
In the code, it extends from OnInit interface but necessary methods are not added yet, let's add ngOnInit method in app.component.ts file
ngOnInit(){
}
Create a Service project
Let's start to create a service project using Visual Studio 2017, Go to available templates to create a ASP.NET Core Web application
When you click on OK button, you will be able to see available templates for ASP.NET Core 2.2, Let's select API project from available templates and go with the default screen
Your API project is created. After that will try to create a shared project to hold our common business logic. Let's add a new project and create a shared project in .NET framework.
You can see the solution with 2 projects, Web API project & Shared project as follows,
Let's create a class to hold common objects. MasterData class will hold data for Gender and PostalCode, we want these lists to populate dropdowns.
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; }
}
}
We want to hold gender values in a enum, you will see these values in Gender dropdown
namespace input_restrictions_dal.Enum
{
public enum Gender
{
Male = 1,
Female = 2
}
}
Open startup class to check what happens when the application starts. We have to enable necessary configurations to communicate with the client application.
We have to enable CORS to allow communication with any origin as below, Let's add necessary code lines into ConfigureServices and Configure method.
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();
}
Let's move to the API project and create the service interface as IStudentInterface as below.
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;
}
}
}
Let's create StudentController class and implement data retrieval service method as below,
We are calling service methods created in the previous step, Service method is a GET request and we named it as masterdata. It produces two results when it succeeds returns OK status with Masterdata object and else NotFound. It's better to describe all the possibilities in a service method as above.
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);
}
}
}
Add Validation in the Client App
You can see the student creation form with angular model bindings in app.component.html, We have applied some directives to restrict the input in these controls. Let's discuss them in detail at the end of this post.
Let's open app.component.ts file and check OnInit method, it calls service method and pass data to the HTML page with angular model bindings
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;
}
);
}
When Postal No changes, Postal Place should populate with the appropriate city as per the requirement, we have to implement dropdown change event as below.
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';
Check data.service.ts file in the shared folder, it responsible to call service API methods as in GetMasterData method. You will see the value of api_url in environments file
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.import { PostalCodeMasterData } from "./masterdata.postalcode.model";
export class MasterData {
gender : Array<object>;
postalCode : Array<PostalCodeMasterData>;
}
We have to create a typescript class to hold the postal code data
export class PostalCodeMasterData {
zipCodeId : number;
code : string;
city : string;
}
Finally, we want to add a class to hold member model as below,
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.It checks for a specific input as per the regular expression shown below.
It listens to key down and paste event to capture the inputs in that specific control.
As per the regular expression used, we can input only the letters simple or in capital letters.
//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//validate gpa
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[decimalnumberOnly]'
})
export class DecimalNumberOnlyDirective {
//with decimals
private regex: RegExp = new RegExp(/^[0-9]+(\.[0-9]*){0,1}$/g);
private specialKeys: Array<string> = ['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();
}
}
}
If you remember, we used api_url value from an environment variable, You can see it as given below.
We can use this file for development purpose and create a environment.prod.ts file directing the production environment.
We can use this file for development purpose and create a environment.prod.ts file directing the production environment.
production: false,
api_url : 'http://localhost:50844/api'
};
You can see the folder structure in the service project as follows, It has API project with controllers, service classes, startup and appsettings file.
You can see front end solution structure with directives we explained, shared data models, service method classes and separate configuration files for different environments (development and production). The screen is rendered from app.component
Download
TechNet Gallery
You can download the sample code from here, Apply Input Restriction in Angular 6
GitHub
You can clone the sample code from this repo, ng-input-restrictions
Conclusion
In this article, it describes how to apply input restrictions to form controls using Angular 6. The sample code has used .NET Core Web API project to develop the service layer. We used different directives to achieve this.