How add validation Email with pattern validation using ngClass - javascript

I want to display data in red colour when email is invalid.
I have n no. of data, out of them some email ids are not validated.
I have used only dynamic class.
//ts file
email_regx = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
if (this.data.email_id) {
this.email_regx = true;
} else {
this.email_regx = false;
}
//html file
<span [ngClass]="{'redClass': email_regx}">{{ data?.email_id }}</span>
//css
.redClass{ color: red}

At first, please think about using an input field instead.
I would recommend to use FormBuilder from Angular Forms.
It will help you with a lean template and make validation a lot easier.
Could look like:
// TS
contactForm: FormGroup;
constructor() {
this.contactForm = this.formBuilder.group({
email: [
'',
Validators.compose([
Validators.pattern('^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*#[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$'),
Validators.required,
])
]
});
The FormGroup called "contactForm" here holds one input field called "email".
The validation is for your email.
// Template
<form id="contactForm" [formGroup]="contactForm">
<ion-item lines="none" class="list-item">
<div>
<ion-label position="stacked"
[class.error]="contactForm.controls.email.value != undefined && !contactForm.controls.email.valid">
E-Mail *
</ion-label>
<ion-input id="email" type="email" formControlName="email"></ion-input>
</div>
</ion-item>
</form>
The important part here is the formControlName and the [formGroup] to connect to your ts´s validation.
The part [class.error] adds the class "error" to the label. You also could use that for your input field.

You are not using regex the right way. Have a look to this doc.
You can make a simple function to test your email and return a boolean.
Component ts file :
public isValidEmail(email: string): boolean {
return /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email);
}
html file :
<span [ngClass]="{'redClass': isValidEmail(data?.email_id)}">{{ data?.email_id }}</span>

Related

Why is my Angular FormGroup Valid when a control that is marked as required is empty?

I am trying to setup a basic form validation for a select.
In my constructor I have the following FormGroup
this.formSubmission = new FormGroup(
{
triggers: new FormControl(['', [ Validators.required]])
}
)
I have a button on the screen to test the validity of the FormGroup and it always comes back as valid even when there is nothing selected for "triggers".
When clicked the following code executes:
console.log('FormGroup Status: ' + this.formSubmission.status)
This will return VALID.
The HTML portion of this can be found here:
<div [formGroup]="formSubmission">
<mat-form-field appearance="fill">
<mat-label>Triggers</mat-label>
<mat-select
formControlName="triggers" multiple
>
<mat-option *ngFor="let trigger of triggersList" [value]="trigger.TRIGGER_NAME">{{trigger.TRIGGER_NAME}}</mat-option>
</mat-select>
</mat-form-field>
</div>
You defined triggers wrong.
triggers: new FormControl(['', [ Validators.required]])
will result in triggers: array.
First argument is the value, second is the validators, asyncValidators or options
what you probably meant to do is this:
triggers: new FormControl('', [ Validators.required])

Creating a reusable method attach to input field for multiple components in Angular

I am beginner in angular and started working on angular 12 project. I am working on reactive forms where I am adding on Blur method to add class to my input field on some error conditions to give some styling to input fields.
I am able to do that but now I have 12-15 components with forms. I want to utilize the same functionality on all the components. Is there a way I can do this without repeating the code in ts file for onblur method. Below is my code.
<form [formGroup]="changePasswordForm" (ngSubmit)="submitForm()">
<div class="form-group" [ngClass]="f.oldPassword.invalid && ((f.oldPassword.dirty || f.oldPassword.touched))?'has-error':''">
<label>Old Password<span class="error-red">*</span></label>
<input type="password" class="form-control input-type2" formControlName="oldPassword" (blur)="onBlur($event)">
<div class="error error-msg">
<div *ngIf="f.oldPassword.errors?.required">
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Old password is required.
</div>
</div>
</div>
</form>
Component.ts
onBlur(e: any) {
if (e.target.className && e.target.className.indexOf('ng-invalid') > 0) {
e.target.className = e.target.className.replace('has-success', '');
} else {
e.target.className = e.target.className + ' has-success';
}
}
I am writing the same piece of code in all the form components to get my work done. I know one way to deal above is create service and write it down over there. But I did some research and found that we can create directives for such things. But I am not sure how to do it. Any help will be appreciated. Thanks.
You can use a directive on the input
#Directive({ selector: "[errorStyling]" })
export class ErrorStylingDirective {
constructor(
private elem:ElementRef
) { }
#HostListener("blur")
onBlur() {
// do something here
}
}
You could also use #HostBinding('class.xxx') approach to set the updated classes

Create forms according to the user action. But not at once

I have to build a form like so.
This shows upfront. i.e. without user interaction.
When a user pressed the + button it creates the same kind of UI again like so.
You can see that the user can add any number of same UI parts again and again. Can you tell me how to do this?
I went through number of articles. But it has the whole form created once. i.e. not like my use case. Any direction for this?
Example: https://jasonwatmore.com/post/2019/06/25/angular-8-dynamic-reactive-forms-example
and https://alligator.io/angular/reactive-forms-formarray-dynamic-fields/
Based on the form you need to reproduce :
Create a function returning a formGroup to populate your array
createSchoolPath(): FormGroup {
return this.fb.group({
schoolName: '',
level: '',
topics: [],
inProgress: true
})
}
You then need to create your parent form which include your form array (and populate it once for the first form you want to show upfront) :
constructor( private fb: formBuilder) {}
form: FormGroup = this.fb.group({
schoolPaths: this.fb.array([this.createSchoolPaths])
});
Finally as you want to let users add more sections, you need a way to populate your array :
/* component */
addSchoolPath(): void {
const paths = this.form.get('schoolPaths') as FormArray;
// use the first function to push a new formGroup
paths.push(this.createSchoolPath());
}
<!-- html -->
<button (click)="addSchoolPath()">+</button>
To display it :
<form [formGroup]="form">
<div formArrayName="schoolPaths" *ngFor="let path of form.get('schoolPaths').controls; let i = index">
<div [formGroupName]="i">
<!-- place your inputs here -->
</div>
</div>
</form>
<button (click)="addSchoolPath()">+</button>
To complementary Gérôme's answer, you can also use directly a formArray
createGroup()
{
return new FormGroup({
school:new FormControl(),
level:new FormControl(),
topic:new FormControl(),
progress:new FormControl()
})
}
At first you has a formArray
formArray:FormArray=new FormArray([this.createGroup()])
The add button is simple
add()
{
this.formArray.push(this.createGroup())
}
And the .html
<form [formGroup]="formArray">
<div *ngFor="let group of formArray.controls" [formGroup]="group">
<input formControlName="school">
<input formControlName="level">
<input formControlName="topic">
<input formControlName="progress">
</div>
</form>
See that, in general we use a formArray inside a formGroup, But in case you only want a FormArray, you can loop over the formArray.controls directly

what is the equevalant for getelementbyid in angular 2 [duplicate]

I have a code:
document.getElementById('loginInput').value = '123';
But while compiling the code I receive following error:
Property value does not exist on type HTMLElement.
I have declared a var: value: string;.
How can I avoid this error?
Thank you.
if you want to set value than you can do the same in some function on click or on some event fire.
also you can get value using ViewChild using local variable like this
<input type='text' id='loginInput' #abc/>
and get value like this
this.abc.nativeElement.value
here is working example
Update
okay got it , you have to use ngAfterViewInit method of angualr2 for the same like this
ngAfterViewInit(){
document.getElementById('loginInput').value = '123344565';
}
ngAfterViewInit will not throw any error because it will render after template loading
(<HTMLInputElement>document.getElementById('loginInput')).value = '123';
Angular cannot take HTML elements directly thereby you need to specify the element type by binding the above generic to it.
UPDATE::
This can also be done using ViewChild with #localvariable as shown here, as mentioned in here
<textarea #someVar id="tasknote"
name="tasknote"
[(ngModel)]="taskNote"
placeholder="{{ notePlaceholder }}"
style="background-color: pink"
(blur)="updateNote() ; noteEditMode = false " (click)="noteEditMode = false"> {{ todo.note }}
</textarea>
import {ElementRef,Renderer2} from '#angular/core';
#ViewChild('someVar') el:ElementRef;
constructor(private rd: Renderer2) {}
ngAfterViewInit() {
console.log(this.rd);
this.el.nativeElement.focus(); //<<<=====same as oldest way
}
A different approach, i.e: You could just do it 'the Angular way' and use ngModel and skip document.getElementById('loginInput').value = '123'; altogether. Instead:
<input type="text" [(ngModel)]="username"/>
<input type="text" [(ngModel)]="password"/>
and in your component you give these values:
username: 'whatever'
password: 'whatever'
this will preset the username and password upon navigating to page.
Complate Angular Way ( Set/Get value by Id ):
// In Html tag
<button (click) ="setValue()">Set Value</button>
<input type="text" #userNameId />
// In component .ts File
export class testUserClass {
#ViewChild('userNameId') userNameId: ElementRef;
ngAfterViewInit(){
console.log(this.userNameId.nativeElement.value );
}
setValue(){
this.userNameId.nativeElement.value = "Sample user Name";
}
}

Validating *ngFor used forms using angular 2 [formControl]

I have an angular Form and it used *ngFor for repeat an input box. Also, I have to validate dynamically all input boxes that are generated by *ngFor.
There is a JSON array called list that contains Questions. and I have to generate input boxes for answers and they should be validated. Validation information also in the list.
This is an example of the list
[{id:1,
mandatory:false,
questionDescription:"Blue flags are in position and contain words “Stop, Tank Car Connected” or “Stop, Men at Work”",
questionType:1,
validation:{maximum:100,minimum:0}},
{id:2,
mandatory:true,
questionDescription:"Wheels are chocked and handbrake(s) set” or “Stop, Men at Work",
questionType:2,
validation:{maxLength:10,minLength:3}}]
I tried to validate generated input boxes as described in here.
https://scotch.io/tutorials/angular-2-form-validation (see validation forms there).
So I have to give validation information for each input boxes like below.
(this example from given tutorial)
constructor(fb: FormBuilder){
this.complexForm = fb.group({
'firstName' : [null, Validators.required],
'lastName': [null, Validators.compose([Validators.required, Validators.minLength(5), Validators.maxLength(10)])]
})
this is the HTML for it.
<div class="form-group">
<label>First Name:</label>
<input class="form-control" type="text"[formControl]="complexForm.controls['firstName']">
</div>
<div class="form-group" >
<label>Last Name</label>
<input class="form-control" type="text" [formControl]="complexForm.controls['lastName']">
</div>
So in my case, all input boxes generate by *ngFor and I have to assign tags like firstName, lastName dynamically to those boxes.
So I used question.id as that tag and implemented control group as followed.
inspectionForm: FormGroup;
constructor(fb: FormBuilder) {
this.questionTemplate = templateService.getQuestionTemplate();
let objString: string = "{";
for (let item of this.questionTemplate.sectionList[0].questionList) {
if (item.questionType == 2) {
objString += '"' + item.id + '":null,';
}
}
objString = objString.slice(0, -1);
objString += '}';
let objJson = JSON.parse(objString);
for (let item of this.questionTemplate.sectionList[0].questionList) {
if (item.questionType == 2) {
objJson[item.id] = [null,Validators.compose([Validators.minLength(item.validation.minLength), Validators.maxLength(item.validation.maxLength)])];
}
}
this.inspectionForm = fb.group(objJson);
}
and here is my HTML code.
<form [formGroup]="inspectionForm" (ngSubmit)="submitForm(inspectionForm.value)">
<div *ngFor="let question of section.questionList" [ngSwitch]="question.questionType">
<ion-row *ngSwitchCase="QuestionType.String">
<ion-col width-80>{{question.questionDescription}}</ion-col>
<ion-col width-20>
<ion-input id="{{question.id}}" type="text" class="inspection-bottom-border" [formControl]="inspectionForm.controls['{{question.id}}']"></ion-input>
</ion-col>
</ion-row>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" [disabled]="!inspectionForm.valid">Submit</button>
</div>
</form>
The Problem is....
If I define [formControl] as [formControl]="inspectionForm.controls['{{question.id}}']"
I get an error like follows,
unhandled Promise rejection: Template parse errors:
Parser Error: Got interpolation ({{}}) where expression was expected at column 25 in [inspectionForm.controls['{{question.id}}']] in InspectionPage#36:91 ("idth-20>
<ion-input id="{{question.id}}" type="text" class="inspection-bottom-border" [ERROR ->][formControl]="inspectionForm.controls['{{question.id}}']"></ion-input>
then I searched for an answer in StackOverflow, I found someone has said don't use [] and {{}} in one time (Dynamic routerLink value from ngFor item giving error "Got interpolation ({{}}) where expression was expected")
But if I removed [] and defined as follows
formControl="inspectionForm.controls['{{question.id}}']"
I get an error as follows
EXCEPTION: Error in ./InspectionPage class InspectionPage - inline template:36:91 caused by: Cannot create property 'validator' on string 'inspectionForm.controls['2']'
(this '2' the is question.id of first type 2 question)
if I define as follows same error occurs
formControl="inspectionForm.controls['2']"
But the problem is if I define as follows with [formControl]
[formControl]="inspectionForm.controls['2']"
The app is Working Perfectly....
But I have to give question.id dynamically. How I can do that?
Are there someone have a solution for this error. Please give a suggestion.
Thank you very much.
just use [formControl]="inspectionForm.controls[question.id]"
Thanks #Sasxa for the answer

Categories

Resources