form validation in angular 2 - html

I am writing a form validation in angular2.
my error is Cannot read property 'valid' of undefined
My HTML file contains a form i.e.
<form id="commentform" class="comment-form" novalidate
[ngFormModel] = "contact" (ngSubmit)="submit(contact.value)">
<div class="form-input">
<input type="text" id="author" name="author" placeholder="Name *" value=""
[ngFormControl] = "contact.controls['author']" pattern="[a-zA-Z ]*"/>
<div [hidden]="author.valid">Name is required
</div>
</div>
I am getting error at div [hidden]="author.valid".
The error is Cannot read property 'valid' of undefined"
My component file contains
import {FormBuilder ,ControlGroup,Validators } from '#angular/common';
#Component({
selector: 'my-contact',
templateUrl : 'app/contact.html'
}
export class ContactComponent {
contact : ControlGroup;
constructor(private _OnChange:OnChange,private _formBuilder : FormBuilder){
this.ngAfterViewInit();
}
ngOnInit() : any{
this.contact = this._formBuilder.group({
'author' : ['',Validators.required] }); }
submit(){
console.log(JSON.stringify(this.contact.value));
}

Use
[hidden]="contact.controls['author'].valid"

Because author is not a variable. Use
<div [hidden]="contact?.controls?.author?.valid">Name is required</div>
Actually, even better. you should use the new forms module #angular/forms
https://scotch.io/tutorials/using-angular-2s-model-driven-forms-with-formgroup-and-formcontrol

Related

Show valid email address on the angular prompt

I have created a temporary password email which any user can get once they click on the forgot password feature. After getting the temp pass they will see a prompt asking them to enter that temp pass. I want to show the same valid email address they have used or associated with the account they have on the angular prompt or pop-up text box. Currently I have created a prompt where I am not able to show the email, since I have not used it before.
My concern is how can I trigger the email address so that it will be visible on that pop-up prompt?
email address as an example: abcd#yahoo.com
I know how to use the <a> tag using href="" for the backend to share hyperlinks, but I'm not familiar how to show or how to trigger any email link on an angular prompt.
Below codes are what I have for the .html and the .ts files.
temporary.component.ts
tempPasswordTextLbl: "We have sent a temp pass to the abcd#yahoo.com email you provided. Please enter it below.",
temporary.component.html
<p style="margin: 30px; text-align: justify; font-size:15px;">{{header.oneTimePasswordMessageLbl?header.oneTimePasswordMessageLbl:headerText.oneTimePasswordMessageLbl}}</p>
Below is the image of the prompt and the email should show up as shown in the screenshot:
As I understood it, first you need to check if the email is valid and only then show the popup informing that the code was sent to the email previously informed.
For this you need to use FormBuilder, FormGroup and Validators
html
<div class="jumbotron">
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
<h3>Angular Form Validation</h3>
<form [formGroup]="myregisterForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label>Email: {{ myEmail }}</label>
<input
type="text"
[(ngModel)]="myEmail"
formControlName="email"
class="form-control"
[ngClass]="{ 'is-invalid': submitted && f.email.errors }"
/>
<div *ngIf="submitted && f.email.errors" class="invalid-feedback">
<div *ngIf="f.email.errors.required">Email is required</div>
<div *ngIf="f.email.errors.email">
Email must be a valid email address
</div>
</div>
</div>
<div class="form-group">
<button class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
#Component({
selector: 'app',
templateUrl: 'app.component.html',
})
export class AppComponent implements OnInit {
myregisterForm: FormGroup;
submitted = false;
myEmail = ''; // need to use text interpolation in html
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.myregisterForm = this.formBuilder.group({
email: [
'',
[
Validators.required,
Validators.email,
Validators.pattern('^[a-z0-9._%+-]+#[a-z0-9.-]+\\.[a-z]{2,4}$'),
],
],
});
}
// convenience getter for easy access to form fields
get f() {
return this.myregisterForm.controls;
}
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.myregisterForm.invalid) {
return;
}
alert(
'We have sent the temp pass to: ' + this.myEmail + ' email you provided'
);
}
}
See working example on Stackblitz

Error: formGroup expects a FormGroup instance. Please pass one in. Reactive forms Angular

I am using reactive forms in Angular version 10. But getting the following error.
ERROR Error: formGroup expects a FormGroup instance. Please pass one in.
Example:
<div [formGroup]="myGroup">
<input formControlName="firstName">
</div>
In your class:
this.myGroup = new FormGroup({
firstName: new FormControl()
});
at Function.missingFormException (forms.js:1700:1)
at FormGroupDirective._checkFormPresent (forms.js:5632:1)
at FormGroupDirective.ngOnChanges (forms.js:5454:1)
at FormGroupDirective.rememberChangeHistoryAndInvokeOnChangesHook (core.js:2373:1)
at callHook (core.js:3285:1)
at callHooks (core.js:3251:1)
at executeInitAndCheckHooks (core.js:3203:1)
at selectIndexInternal (core.js:6324:1)
at ɵɵadvance (core.js:6306:1)
at PatientInformationComponent_Template (template.html:39:34)
My sample HTML code is as follows.
<div [formGroup]="MyForm">
<input formControlName="firstName">
<input formControlName="lastName">
</div>
My TS code:
export class MyComponent implements OnInit{
MyForm: FormGroup;
constructor( private formbuilder: FormBuilder) {}
ngOnInit() {
this.MyForm= this.formbuilder.group({
firstName: new FormControl("", Validators.maxLength(100)),
lastName: new FormControl("",Validators.maxLength(100)),
});
}
}
Although the form works properly, but the error always shows in the console. I think it might be because of some other lifecycle hook. Could you give me some solution for this.
Since you haven't initialized your form called myForm in .ts code, you should try adding *ngIf and change div HTML tag to form element.
<form *ngIf="form"
[formGroup]="MyForm">
<input formControlName="firstName">
<input formControlName="lastName">
</form>
i had the same issue., for me it was
i declared the form in component.ts
form: FormGroup = this._fb.group({})
and in component.html i used
<form [formGroup]="studentForm" (ngSubmit)="onSubmit()">
i used different names in each place
i had to use same form name in both component.html and component.ts

Angular 8 : Set title of group box from ts code

I have a component that contains groupbox:
<fieldset>
<legend>Title</legend>
</fieldset>
Is it possible to set the title of the groupbox from the ts code ?
In your component file:
#Component({
//...
})
export class MyComponent {
title = 'My Title';
}
In your template:
<fieldset>
<legend>{{ title }}</legend>
</fieldset>
Find more on Angular Template Syntax

caused by: Cannot read property 'product_name' of undefined

When I try to load a html form component in my angular2 app, it will not read a property on one part of the form.
EXCEPTION: Uncaught (in promise): Error: Error in
http://localhost:3000/app/material/material-new.component.html:15:7
caused by: Cannot read property 'product_name' of undefined
I have another component that is identical bar the fields and does not encounter this problem when loaded. Components match and I am going mad about this.
Why does it not read that property of 'product_name' .
Heres the code.
Create Material
<div class="card container form-container">
<div class="row">
<div class="col-md-12">
<form (ngSubmit)="createMaterial(material)" #materialForm="ngForm" >
<div class="form-group">
<label class="label-text" for="product_name">Product
Name</label>
<input type="text"
class="form-control"
id="product_name"
placeholder="Product name"
required
name="product_name"
#product_name='ngModel'
[(ngModel)]="material.product_name">
<div [hidden]="product_name.valid || product_name.pristine">
Input product name
</div>
</div>
import { Component } from '#angular/core';
import { Material } from './material';
import { MaterialService } from './material.service';
import { Observable } from 'rxjs/Rx';
#Component({
moduleId: module.id,
selector: 'material-new',
templateUrl: 'material-new.component.html',
styleUrls: ['material-new.component.css'],
providers: [ MaterialService ]
})
export class MaterialNewComponent {
material : Material;
submitted : boolean = false;
constructor(
private materialService : MaterialService
) {}
createMaterial( material : Material) {
this.submitted = true;
this.materialService.createMaterial(material)
.subscribe(
data => { return true },
error => { console.log("error saving material")
return Observable.throw(error);
}
)
}
}
You error points to [(ngModel)]="material.product_name"
Your material object is undefined, because you have not initialized it. So all you need to do, is to initialize your Object.
So change:
material : Material;
to
material : Material = <Material>{};
and it will no longer be undefined.
You should use async pipe to unwrap the Observable because it does the job of subscribing and unsubscribing automatically.
What you'll need to do:
TS Code:
material: Observable<Material>;
// In createMaterial
this.material = this.materialService.createMaterial(material);
Template:
[(ngModel)]="(material | async)?.product_name"
The ? will check if material | async is undefined.

check if emails match on blur

I'm trying to check if email field and confirm email field match each other. That is, the user types in their email and then they have to confirm it again. I want the match/validation to happen on blur (when the user presses enter or the textfield loses focus).
Here's my ts file:
import {Component, OnInit} from '#angular/core';
import {User} from './user.interface';
import {FormBuilder, FormGroup, ValidatorFn} from '#angular/forms';
#Component({
selector: 'my-email',
templateUrl: '/app/components/profile/email.component.html',
styleUrls:['styles.css'],
})
export class EmailComponent implements OnInit {
public user : User;
Form : FormGroup;
ngOnInit() {
// initialize model here
this.user = {
Email: '',
confirmEmail: ''
}
if(this.Form.valid) {
this.displayErrors = false;
}
}
constructor(fb: FormBuilder, private cookieService: CookieService, private router: Router) {
this.Form = fb.group({
email: [''],
confirmEmail: ['']
},
{
validator: this.matchingEmailsValidator('email', 'confirmEmail')
});
}
save(model: User, isValid: boolean) {
// call API to save customer
//save email
}
matchingEmailsValidator(emailKey: string, confirmEmailKey: string): ValidatorFn {
return (group: FormGroup): {[key: string]: any} => {
let email = group.controls[emailKey];
let confirmEmail = group.controls[confirmEmailKey];
if (email.value !== confirmEmail.value) {
return {
mismatch: true
};
}
};
}
}
Here's my view:
<form [formGroup]="Form" novalidate (ngSubmit)="Form.valid && save(Form.value, Form.valid)">
<div class="container-fluid">
<div id = "container" class="contain" style="text-align: center">
<div>
<fieldset class="form-group">
<label id = "rounded" class="item item-input .col-md-6 .col-md-offset-3">
<input class="email-address-entry form-control" name="email" type="email" placeholder="name#domain.com" formControlName="email" pattern="^(\\w|[0-9.!#$%&’*+/=?^_\`{|}~-])+#(\\w|[0-9-])+(?:‌​[.](\\w|[0-9-])+)*$"/>
</label>
<p class="Reenter-your-email">Reenter your email to confirm</p>
<label id = "rounded" class="item item-input">
<input class="email-address-entry form-control" (blur)="displayErrors=true" name="confirmEmail" type="email" placeholder="name#domain.com" formControlName="confirmEmail" validateEqual="email"/>
</label>
</fieldset>
</div>
<div>
<label class="entry-invalid">
<p *ngIf="displayErrors && !Form.get('email').valid">The email you entered does not match.</p>
</label>
</div>
<div (click)="Form.get('email').length > 0 ? save(Form.value, Form.valid) : NaN" class="{{ Form.get('email').length > 0 ? 'container-fluid anchorBottomHighlight' : 'container-fluid anchorBottom'}}">
<label class="footerLabel">Confirm</label>
</div>
</div>
</div>
</form>
Currently, with the way it's set up, the validation occurs but it does not get cleared when the correct match is input. I'm wondering how I can setup my view correctly? So the validation message is shown/hidden when the correct match is set and not.
Also it seems like Form.get('email').length > 0 is never greater than 0 / never hit, so my label doesn't toggle to be clickable.
I'm using Angular 2 and reactive forms.
It looks that you're mixing the two form syntaxes: template-driven forms and model-driven forms.
Since you're declaring a form model in your class with FormBuilder, I'm assuming you want a model-driven form.
This means your fields don't need attributes like [(ngModel)] or #EmailAddress.
Instead of that:
<input type="email" [(ngModel)]="user.EmailAddress" required #EmailAddress="ngModel">
Write this:
<!-- Now I'm using `formControlName` to bind the field to the model -->
<!-- Its value must match one of the names you used in the FormBuilder -->
<input type="email" formControlName="email">
ALL of your validators must be declared in the FormBuilder. Not just matchingEmailsValidator, but also required:
this.Form = fb.group({
email: ['', Validators.required],
confirmEmail: ['', Validators.required]
},
{
validator: this.matchingEmailsValidator('email', 'confirmEmail')
});
Now you can access a field with the following syntax:
// In the class
this.Form.get('email').value
this.Form.get('email').errors
<!-- In the template -->
{{ Form.get('email').value }}
{{ Form.get('email').errors }}
You can use these syntaxes to display errors. For example:
<input type="email" formControlName="email">
<p *ngIf="Form.get('email').dirty && Form.get('email').errors.required">
This field is required.
</p>
In the example above, I am displaying an error message if the email field has been touched (i.e. the user tried to enter something) AND the required error is present.
You can also verify that your validation rules are enforced by inspecting the form's markup with your browser's dev tools. Angular should have added classes like .ng-invalid or .ng-valid to the <input> tags that have validation rules.
Finally, regarding your question to check email match on blur. You can't postpone Angular's validation, it will happen in real-time (as the user types). But you could wait for the blur event to display errors.
Combining this last advice with my previous example, here's how you could should an error if the email field is empty AND it has lost focus (blur event):
<input type="email" formControlName="email" (blur)="displayErrors=true">
<p *ngIf="displayErrors && Form.get('email').dirty && Form.get('email').errors.required">
This field is required.
</p>
UPDATE(01-FEB-2017) after Euridice posted this Plunkr:
You still have wayyyyy to much validation code in your template. Like I said, ALL VALIDATORS should be declared IN THE FORM MODEL (with the FormBuilder). More specifically:
The pattern="..." attribute in the email field should be replaced with Validators.pattern() in the form model.
What is the validateEqual="email" attribute in the confirmEmail field? You're not using that anywhere.
The main problem is your test to display the error message: *ngIf="displayErrors && !Form.get('email').valid && Form.get('email').error.mismatch".
First of all, the property is errors with an "s", not error.
Also, your custom validator is setting the error on the form itself, NOT on the email field. This means you should retrieve your mismatch custom error from Form.errors.mismatch, NOT Form.get('email').errors.mismatch.
Here's the updated, working Plunkr: https://plnkr.co/edit/dTjcqlm6rZQxA7E0yZLa?p=preview