Cannot read property of custom Validator and required - Angular - javascript

I'm try to make custom Validators that give user message when he/she leave a space on text but i received this error.
1-Cannot read property 'removeSpaceFromUserName' of undefined
2-Cannot read property 'required' of null
at Object.eval [as updateDirectives]
Here's the html of the component
<form [formGroup]='form'>
<div class="form-group">
<label for="username">Username</label>
<input
formControlName='username'
id="username"
type="text"
class="form-control">
<div *ngIf="username.touched && username.touched" class="alert alert-danger">
<div *ngIf="username.errors.required"> You need to enter user name</div>
<div *ngIf="username.errors.minlength"> Min Length is
{{ username.errors.minLength.requiredLength}}
</div>
<div *ngIf="UserNameValiditors.removeSpaceFromUserName">
removeSpaceFromUserName </div>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
formControlName='password'
id="password"
type="text"
class="form-control">
</div>
<button class="btn btn-primary" type="submit">Sign Up</button>
</form>
Here's the custom validator class
import { AbstractControl, ValidationErrors } from "#angular/forms";
export class UserNameValiditors {
static removeSpaceFromUserName(control: AbstractControl): ValidationErrors | null {
if ((control.value as string).indexOf(' ') >= 0) {
return {
removeSpaceFromUserName: true
};
}
else {
return null;
}
}
}
import { Component } from '#angular/core';
import { FormControl , FormGroup , Validators } from "#angular/forms";
import { UserNameValiditors } from './UserNameValditors';
#Component({
selector: 'signup-form',
templateUrl: './signup-form.component.html',
styleUrls: ['./signup-form.component.css']
})
export class SignupFormComponent {
form= new FormGroup(
{
username : new FormControl('',
[
Validators.required,
Validators.minLength(3) ,
UserNameValiditors.removeSpaceFromUserName
]) ,
password : new FormControl('',Validators.required)
});
get username()
{
return this.form.get('username');
}
}

You can try with this solution.
I have create a demo on Stackblitz
app.component.ts
myForms: FormGroup;
constructor(fb: FormBuilder) {
this.myForms = fb.group({
username: [null, Validators.compose([
Validators.required, Validators.minLength(3), usernameValidator])],
password: [null, [
Validators.required]]
});
}
app.component.html
<form [formGroup]="myForms">
<label>User Name :
<input type="text" formControlName="username">
</label><br>
<div class="errors" *ngIf="myForms.get('username').invalid && (myForms.get('username').touched || myForms.get('username').dirty)">
<div *ngIf="myForms.get('username').hasError('required')">
username is required
</div>
<div *ngIf="myForms.get('username').errors.minlength">
username must be at least 3 characters
</div>
<div class="error-text" *ngIf="myForms.get('username').hasError('removeSpaceFromUserName')">
removeSpaceFromUserName
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
formControlName='password'
id="password"
type="text"
class="form-control">
</div>
<button class="btn btn-primary" type="submit">Sign Up</button>
</form>

Use hasError() to check if certain error is present on the form.
html code
<div *ngIf="username.hasError('required')"> You need to enter user name</div>
<div *ngIf="username.hasError('minlength')"> Min Length is {{ username.hasError('minLength')}}
</div>f
<div *ngIf="username.hasError('removeSpaceFromUserName')">
removeSpaceFromUserName </div>
</div>
Your working code is here

Related

How can I validate my form and save data in my database? angular php mysql

I'm working on an angular project and I want to develop a form, validate it, and save data in my database with php and mysql. I tried to do this but it doesn't work. I got these errors.
Property 'dataService' does not exist on type 'AppComponent'.
'data' is declared but its value is never read.
Parameter 'data' implicitly has an 'any' type.
Property 'router' does not exist on type 'AppComponent'.
'error' is declared but its value is never read.
Parameter 'error' implicitly has an 'any' type.
register.component.html
<h2 class="text-center">Registration</h2>
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-6 col-md-offset-3">
<div class="jumbotron">
<form [formGroup]="angForm" autocomplete="off" >
<div class="form-group">
<label for="name">Name</label>
<input type="text" name="name" formControlName="name" autocomplete="off" class="form-control input-sm" required minlength="1" maxlength="250" placeholder="Name"
[class.is-invalid]="name.invalid && (name.dirty || name.touched)">
<div *ngIf="name.invalid && (name.dirty || name.touched)" class="invalid-feedback">
<div *ngIf="name.errors?.['required']">
This field is required.
</div>
</div></div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" name="email" formControlName="email" autocomplete="off" required minlength="1" maxlength="250" class="form-control input-sm" placeholder="Email"
[class.is-invalid]="email.invalid && (email.dirty || email.touched)">
<div *ngIf="email.invalid && (email.dirty || email.touched)" class="invalid-feedback">
<div *ngIf="email.errors?.['required']">
This field is required.
</div>
<div *ngIf="!email.errors?.['required'] && email.errors?.['emailValidator']">
Invalid email format.
</div>
</div></div>
<div class="form-group">
<label for="Password">Password</label>
<input type="password" name="Password" formControlName="password" required minlength="15" autocomplete="off" class="form-control input-sm" placeholder="Password"
[class.is-invalid]="password.invalid && (password.dirty || password.touched)">
<button type="button" class="btn btn-outline-secondary" (click)="user.showPassword = !user.showPassword">
<i class="bi" [ngClass]="{'bi-eye-fill': !user.showPassword, 'bi-eye-slash-fill': user.showPassword}"></i>
</button>
<div *ngIf="password.invalid && (password.dirty || password.touched)" class="invalid-feedback">
<div *ngIf="password.errors?.['required']">
This field is required.
</div>
<div *ngIf="password.errors?.['minlength']">
This field must have at least 8 characters.
</div>
</div></div>
<button type="submit" class="btn btn-success" (click)="validate(angForm1)">Register</button>
</form>
</div>
</div>
<div class="col-md-3">
</div>
</div>
register.component.ts
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, FormBuilder, Validators, NgForm, AbstractControl} from
'#angular/forms';
import { first } from 'rxjs/operators';
import { Router } from '#angular/router';
import { ApiService } from '../api.service';
import { emailValidator } from './email-validator.directive';
interface IUser {
name: string;
email: string;
password: string;
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
angForm!: FormGroup;
user: IUser;
constructor() {
this.user = {} as IUser;
}
ngOnInit(): void {
this.angForm = new FormGroup({
name: new FormControl(this.user.name, [
Validators.required
]),
email: new FormControl(this.user.email, [
Validators.required,
EmailValidator,
]),
password: new FormControl(this.user.password, [
Validators.required,
Validators.minLength(8),
]),
});
}
get name() {
return this.angForm.get('name')!;
}
get email() {
return this.angForm.get('email')!;
}
get password() {
return this.angForm.get('password')!;
}
public validate(angForm1:any): void {
if (this.angForm.invalid) {
for (const control of Object.keys(this.angForm.controls)) {
this.angForm.controls[control].markAsTouched();
}
return;
}
else{ this.dataService. userregistration(angForm1.value.name,angForm1.value.email,
angForm1.value.password).pipe(first()).subscribe(
data => {
this.router.navigate(['login']);
},
error => {
});
}
this.user = this.angForm.value;
console.info('Name:', this.user.name);
console.info('Email:', this.user.email);
console.info('Password:', this.user.password);
}
}
register.php
<?php
include_once "database.php";
$postdata = file_get_contents("php://input");
if (isset($postdata) && !empty($postdata)) {
$request = json_decode($postdata);
$name = trim($request->name);
$pwd = mysqli_real_escape_string($mysqli, trim($request->pwd));
$email = mysqli_real_escape_string($mysqli, trim($request->email));
$sql = "INSERT INTO users(name,password,email) VALUES ('$name','$pwd','$email')";
if ($mysqli->query($sql) === true) {
$authdata = [
"name" => $name,
"pwd" => "",
"email" => $email,
"Id" => mysqli_insert_id($mysqli),
];
echo json_encode($authdata);
}
}
?>
api.service.ts
import {
Injectable,
Output,
EventEmitter
}
from '#angular/core';
import {
map
}
from 'rxjs/operators';
import {
HttpClient
}
from '#angular/common/http';
import {
Users
}
from './users';
#Injectable({
providedIn: 'root'
})
export class ApiService {
redirectUrl: string;
baseUrl: string = "http://localhost/angular_admin/php";
#Output() getLoggedInName: EventEmitter < any > = new EventEmitter();
constructor(private httpClient: HttpClient) {}
public userlogin(username: any, password: any) {
alert(username)
return this.httpClient.post < any > (this.baseUrl + '/login.php', {
username,
password
})
.pipe(map(Users => {
this.setToken(Users[0].name);
this.getLoggedInName.emit(true);
return Users;
}));
}
public userregistration(name: any, email: any, pwd: any) {
return this.httpClient.post < any > (this.baseUrl + '/register.php', {
name,
email,
pwd
})
.pipe(map(Users => {
return Users;
}));
}
//token
setToken(token: string) {
localStorage.setItem('token', token);
}
getToken() {
return localStorage.getItem('token');
}
deleteToken() {
localStorage.removeItem('token');
}
isLoggedIn() {
const usertoken = this.getToken();
if (usertoken != null) {
return true
}
return false;
}
}
In your constructor in your ts:
constructor(private router: Router,private apiservice: ApiService) {
this.user = {} as IUser;
}
public validate(angForm1:any): void {
if (this.angForm.invalid) {
for (const control of Object.keys(this.angForm.controls)) {
this.angForm.controls[control].markAsTouched();
}
return;
}
else{ this.apiservice. userregistration(angForm1.value.name,angForm1.value.email,
angForm1.value.password).pipe(first()).subscribe(
(data: any) => {
this.router.navigate(['login']);
},
error => {
});
}
this.user = this.angForm.value;
console.info('Name:', this.user.name);
console.info('Email:', this.user.email);
console.info('Password:', this.user.password);
}
In your html:
<h2 class="text-center">Registration</h2>
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-6 col-md-offset-3">
<div class="jumbotron">
<form [formGroup]="angForm" autocomplete="off" >
<div class="form-group">
<label for="name">Name</label>
<input type="text" name="name" formControlName="name" autocomplete="off" class="form-control input-sm" required minlength="1" maxlength="250" placeholder="Name"
[class.is-invalid]="angForm.controls['name'].invalid && (angForm.controls['name'].dirty || angForm.controls['name'].touched)">
<div *ngIf="angForm.controls['name'].invalid && (angForm.controls['name'].dirty || angForm.controls['name'].touched)" class="invalid-feedback">
<div *ngIf="angForm.controls['name'].errors?.required">
This field is required.
</div>
</div></div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" name="email" formControlName="email" autocomplete="off" required minlength="1" maxlength="250" class="form-control input-sm" placeholder="Email"
[class.is-invalid]="angForm.controls['email'].invalid && (angForm.controls['email'].dirty || angForm.controls['email'].touched)">
<div *ngIf="angForm.controls['email'].invalid && (angForm.controls['email'].dirty || angForm.controls['email'].touched)" class="invalid-feedback">
<div *ngIf="angForm.controls['email'].errors.required">
This field is required.
</div>
<div *ngIf="!email.errors?.['required'] && email.errors?.['emailValidator']">
Invalid email format.
</div>
</div></div>
<div class="form-group">
<label for="Password">Password</label>
<input type="password" name="Password" formControlName="password" required minlength="15" autocomplete="off" class="form-control input-sm" placeholder="Password"
[class.is-invalid]="angForm.controls['password'].invalid && (angForm.controls['password'].dirty || angForm.controls['password'].touched)">
<button type="button" class="btn btn-outline-secondary" (click)="user.showPassword = !user.showPassword">
<i class="bi" [ngClass]="{'bi-eye-fill': !user.showPassword, 'bi-eye-slash-fill': user.showPassword}"></i>
</button>
<div *ngIf="angForm.controls['password'].invalid && (angForm.controls['password'].dirty || angForm.controls['password'].touched)" class="invalid-feedback">
<div *ngIf="angForm.controls['password'].errors.required">
This field is required.
</div>
<div *ngIf="angForm.controls['password'].errors.minlength">
This field must have at least 8 characters.
</div>
</div></div>
<button type="submit" class="btn btn-success" (click)="validate(angForm1)">Register</button>
</form>
</div>
</div>
<div class="col-md-3">
</div>
</div>

How can I validate an angular form

I have this inscription form. I tried to validate it but in vain. inputs are saved in my database despite they are empty I want to have these validations:
All inputs are required
email address should be valid
name should be composer by only letters
Password should have minimum 8 characters, at least 1 uppercase
letter, 1 lowercase letter and 1 number
I want to have a message under evey invalid input.(in <div id="na"></div> for example).How can I do this please?
HTML file
<h2 class="text-center">Inscription</h2>
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-6 col-md-offset-3">
<div class="jumbotron">
<form [formGroup]="angForm" (ngSubmit)="postdata(angForm)" autocomplete="off">
<div class="form-group mb-3">
<label for="name">Nom</label>
<input type="text" name="name" formControlName="name" autocomplete="off" id="name"
class="form-control input-sm" placeholder="Nom">
</div>
<div id="na"></div>
<div class="form-group mb-3">
<label for="email">Email</label>
<input type="email" name="email" formControlName="email" autocomplete="off" id="email"
class="form-control input-sm" placeholder="Email">
</div>
<div id="mail"></div>
<div class="form-group mb-3">
<label for="Password">Mot de passe</label>
<input type="password" name="Password" formControlName="password" autocomplete="off"
id="password" class="form-control input-sm" placeholder="Mot de passe">
</div>
<div id="pwd"></div>
<button type="sumit" class="btn btn-success">Enregistrer</button>
</form>
</div>
</div>
<div class="col-md-3">
</div>
</div>
Type script file
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, FormBuilder, Validators, NgForm } from '#angular/forms';
import { first } from 'rxjs/operators';
import { Router } from '#angular/router';
import { ApiService } from '../api.service';
#Component({
selector: 'app-inscription',
templateUrl: './inscription.component.html',
styleUrls: ['./inscription.component.css']
})
export class InscriptionComponent implements OnInit {
angForm: FormGroup;
constructor(private fb: FormBuilder,private dataService: ApiService,private router:Router) {
this.angForm = this.fb.group({
email: [],
password: [],
name: [],
mobile: []
});
}
ngOnInit() {
}
postdata(angForm1:any){this.dataService.userregistration(angForm1.value.name,angForm1.value.email,angForm1.value.password)
.pipe(first())
.subscribe(
data => {
this.router.navigate(['login']);
},
error => {
});
}
get email() { return this.angForm.get('email'); }
get password() { return this.angForm.get('password'); }
get name() { return this.angForm.get('name'); }
}
thanks in advance
this.angForm = this.fb.group({
email: ['', Validators.required, Validators.email],
password: ['', Validators.required, Validators.minLength(8), Validators.pattern("(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}")],
name: ['', Validators.required, Validators.pattern('^[a-zA-Z ]*$')],
mobile: [null, Validators.required, Validators.minLength(10), Validators.maxLength(10)]
});
This is the syntax for Validations.
In HTML, before closing of form-group div write
<span class="text-danger"
*ngIf="(angForm.name.touched || submitted) &&
angForm.name.errors?.required">
Name is required
</span>
<span class="text-danger"
*ngIf="((angForm.password.touched || submitted) &&
angForm.password.errors?.required )|| (angForm.invalid && submitted)">
Must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters </span>
same applies for email, mobile error msg in HTML.
Please refer for reactive form validation.
https://www.freecodecamp.org/news/how-to-validate-angular-reactive-forms/
response to Rothitha
If you don't want to use the "auxiliar variable" submitted you can use in submit.
submit(form:FormGroup)
{
if (form.invalid)
form.markallAsTouched()
else
{
..doSomething..
}
}
If we can better mannagement about errors (remove this ugly *ngIf="angForm.get('password').touched && angForm.get('password').touched" we can use a tecnica similar bootstrap mannage the error
We use a .css like
.invalid-feedback
{
display:none
}
.ng-invalid.ng-touched ~ .invalid-feedback
{
display: block;
}
And an html like
<!--enclosed all under a div-->
<div>
<!--a label-->
<label for="email">Email</label>
<!--a input-->
<input id="email" formControlName="email">
<!--a div class="invalid-feedback-->
<div class="invalid-feedback">
<!--if there're several validators use *ngIf-->
<div *ngIf="angForm.controls.email.errors?.required">Email is required</div>
<div *ngIf="angForm.controls.email.errors?.email">it's not a valid email</div>
</div>
</div>
See stackblitz

How do I add specific validation to reactive forms on angular

I'm trying to render a div based on specific errors, my form works but is buggy and is trowing a type error, "undefined is not an object" , and i don't understand why; can someone help me understand what I'm missing? I've tried simplifying my code by using just the .errors propery, that takes the errors away but its not specific enough to so that it knows what error to render depending on the state of the form, any insight would be super helpful :)
HTML
<form [formGroup]="form">
<div class="spacer">
<label for="oldPassword">Old Password</label><br /><input
type="text"
class="form-control"
id="oldPassword"
formControlName="oldPassword"
/>
<div class="alert alert-danger" *ngIf="form.get('oldPassword').errors.passwordValidator">Duplicate Password</div>
<div class="alert alert-danger" *ngIf="form.get('oldPassword').touched && form.get('oldPassword').errors.required">Old Password is Required</div>
<div *ngIf="forms.get('oldPassword').pending">Loading...</div>
</div>
<div class="spacer">
<label for="newPassword">New Password</label><br /><input
type="text"
class="form-control"
id="newPassword"
formControlName="newPassword"
/>
<div *ngIf="form.get('newPassword').touched && newPassword.invalid" class="alert alert-danger">New Password is Required</div>
</div>
<div class="spacer">
<label for="confirmPassword">Confirm Password</label><br /><input
type="text"
class="form-control"
id="confirmPassword"
formControlName="confirmPassword"
/>
<div *ngIf="confirmPassword.touched && confirmPassword.invalid" class="alert alert-danger">Confirm Password is Required</div>
</div>
<button class="btn btn-primary" (click)="onClick()">Submit!</button>
</form>
{{ oldPassword | json}}
TS:
import { Component } from '#angular/core';
import { FormBuilder, Validators, FormGroup, FormControl,} from '#angular/forms'
import { CustomValidators } from '../passwordValidator';
#Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css']
})
export class FormComponent {
form = new FormGroup({
oldPassword: new FormControl('',Validators.required, CustomValidators.passwordValidator),
newPassword: new FormControl('',Validators.required),
confirmPassword: new FormControl('',Validators.required)
})
onClick() {
console.log(this.form.get('oldPassword').errors)
}
}
//CustomValidators.passwordValidator
CUSTOM VALIDATOR.TS
import { AbstractControl, ValidationErrors, } from '#angular/forms';
export class CustomValidators {
static passwordValidator(control: AbstractControl): Promise<ValidationErrors | null> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (control.value === "123") {
resolve({ passwordValidator: true })
}
resolve(null)
}, 2000);
});
}
}
Here is the error
You have some issues...
<div *ngIf="forms.get('oldPassword').pending">Loading...</div>, remove the s from forms
<div *ngIf="confirmPassword.touched && confirmPassword.invalid" is invalid
*ngIf="form.get('newPassword').touched && newPassword.invalid" is invalid
Your custom async validator should be placed as the third argument
Those undefined issues stem from errors being null
Suggestion: Use FormBuilder instead of calling new FormControl(), but I'll keep my sample with your current code. Also usually we use ngSubmit instead of click event in forms.
So first place the async validator in correct place:
oldPassword: new FormControl(
"",
[Validators.required],
[CustomValidators.passwordValidator]
),
The rest of the errors is related to that errors being null in template if there are no errors... where you are calling such as...
*ngIf="form.get('oldPassword').errors.passwordValidator"
You could solve this by adding the safe navigation operator:
*ngIf="form.get('oldPassword').errors?.passwordValidator"
That will work, but I use the following way, which is in my opinion nicer and more intuitive:
*ngIf="form.hasError('passwordValidator', 'oldPassword')"
So here's a stripped down, shortened version of your code:
<form [formGroup]="form" (ngSubmit)="onClick()">
<label for="oldPassword">Old Password</label><br />
<input formControlName="oldPassword" />
<div *ngIf="form.hasError('passwordValidator', 'oldPassword')">
Duplicate Password
</div>
<div *ngIf="form.get('oldPassword').touched && form.hasError('required', 'oldPassword')">
Old Password is Required
</div>
<div *ngIf="form.get('oldPassword').pending">Loading...</div>
<button type="submit" [disabled]="!form.valid">Submit!</button>
</form>
STACKBLITZ

ERROR TypeError: Cannot read property 'title' of undefined

I've been battling with these block of codes for some days, and even when i try initializing it as an object i get errors.
this is my restaurantForm.ts file
import { Component, OnInit } from '#angular/core';
import {RestaurantService} from '../../restaurant.service';
import {ProductService} from '../../product.service';
import {ActivatedRoute, Router} from '#angular/router';
import 'rxjs/add/operator/take';
import {Product} from '../../model/product';
#Component({
selector: 'app-product-form',
templateUrl: './restaurant-form.component.html',
styleUrls: ['./restaurant-form.component.css']
})
export class RestaurantFormComponent implements OnInit {
restaurants$;
id;
product: Product;
constructor(private restaurantService: RestaurantService,
private productService: ProductService,
private route: ActivatedRoute,
private router: Router) {
this.restaurants$ = this.restaurantService.getAll();
this.id = this.route.snapshot.paramMap.get('id');
if (this.id) {
this.productService.get(this.id).take(1).subscribe(p => this.product = p);
}
this.product = new Product();
}
save(product) {
if (this.id) {
this.productService.update(this.id, product);
} else {
this.productService.create(product);
}
this.router.navigate(['/admin/restaurants']);
}
delete() {
if (!confirm('Are you sure you want to delete this product?')) { return ; }
this.productService.delete(this.id);
this.router.navigate(['/admin/restaurants']);
}
ngOnInit() {
}
}
this is my product model
export interface Product {
$key: string;
title: string;
price: number;
restaurant: string;
imageUrl: string;
}
My restaurantForm.html
<div class="container">
<div class="row">
<div class="col-md-6">
<form #f="ngForm" (ngSubmit)="save(f)">
<div class="form-group">
<label for="title">Title</label>
<input #title="ngModel" [(ngModel)]="product.title" name="title" id="title" type="text" class="form-control" required>
<div class="alert-danger alert" *ngIf="title.touched && title.invalid">
Title is required.
</div>
</div>
<div class="form-group">
<label for="price">Delivery Price</label>
<div class="input-group">
<span class="input-group-addon">₦</span>
<input #price="ngModel" [(ngModel)]="product.price" name="price" id="price"
type="number" class="form-control" required [min]="0">
</div>
<div class="alert alert-danger" *ngIf="price.touched && price.invalid">
<div *ngIf="price.errors.required">
Delivery Price is required
</div>
<div *ngIf="price.errors.min">
Delivery Price should be 0 or higher.
</div>
</div>
</div>
<div class="form-group">
<label for="restaurant">Restaurant</label>
<select #restaurant="ngModel" [(ngModel)]="product.restaurant" name="restaurant" id="restaurant" class="form-control" required>
<option value=""></option>
<option *ngFor="let r of restaurants$ | async" [value]="r.$key">
{{ r.name }}
</option>
</select>
<div class="alert alert-danger" *ngIf="restaurant.touched && restaurant.invalid">
Please select a restaurant.
</div>
</div>
<div class="form-group">
<label for="imageUrl">Image Url</label>
<input #imageUrl="ngModel" [(ngModel)]="product.imageUrl" name="imageUrl"
id="imageUrl" type="text" class="form-control" required url>
<div class="alert alert-danger" *ngIf="imageUrl.touched && imageUrl.invalid">
<div *ngIf="imageUrl.errors.required">Image Url is required.</div>
<div *ngIf="imageUrl.errors.url">Please enter a valid Url.</div>
</div>
</div>
<button class="btn btn-primary">Save</button>
<button type="button" (click)="delete()" class="btn btn-danger">Delete</button>
</form>
</div>
<div class="col-md-6">
<app-product-card [product]="product" [showActions]="false"></app-product-card>
</div>
</div>
</div>
I get the same errors with price, $key, restaurant and imageUrl.
thanks in advance. Although Ive looked up some solutions saying i should use elvis Operator e.g 'product?.title' this method isnt still working.
Because product is undefined, you need to declare and initialize it with empty object inside the constructor or ngOninit.
EDIT:
You need to have the Product declared in the component as,
const product : Produce = { $key: "", title: "",price:0,restuarant :"" ,imageurl:"" };
When the template get initialized, the product is undefined and it continues until the response return from API. Add a check for the template where you bind the object properties.Do the same for price etc.
<input *ngIf="product.title" #title="ngModel" [(ngModel)]="product.title" name="title" id="title" type="text" class="form-control" required>

Angular 4 Reactive Forms FormControl errors is null

If I tab through the text inputs without entering anything, the error msg divs display indicating that the required validator has fired correctly. However, if I type anything into one of the fields, the console immediately throws this error:
Cannot read property 'required' of null
Here is my component:
import { PasswordValidators } from './../validators/password.validators';
import { Component, OnInit } from '#angular/core';
import { FormBuilder, Validators, FormGroup, FormControl } from '#angular/forms';
#Component({
selector: 'app-changepassword-form',
templateUrl: './changepassword-form.component.html',
styleUrls: ['./changepassword-form.component.css']
})
export class ChangepasswordFormComponent {
form;
constructor(fb: FormBuilder) {
this.form = fb.group({
newPassword: ['', Validators.required],
confirmPassword: ['', Validators.required]
})
}
get newPassword() {
return this.form.get('newPassword');
}
get confirmPassword() {
return this.form.get('confirmPassword');
}
}
and HTML:
<form [formGroup]="form">
<div class="form-group">
<label for="newPassword">New Password</label>
<input formControlName="newPassword" id="newPassword" type="text" class="form-control">
<div class="alert alert-danger" *ngIf="newPassword.touched && newPassword.errors.required">
Required
</div>
</div>
<div class="form-group">
<label for="confirmPassword">Confirm Password</label>
<input formControlName="confirmPassword" id="confirmPassword" type="text" class="form-control">
<div class="alert alert-danger" *ngIf="confirmPassword.touched && confirmPassword.errors.required">
Required
</div>
</div>
<p><button class="btn btn-primary">Submit</button></p>
</form>
That error is coming from this:
*ngIf="newPassword.touched && newPassword.errors.required"
When you put in a value, there is no longer an errors collection so checking newPassword.errors.required generates that Cannot read property 'required' of null error.
Try something like this instead:
*ngIf="newPassword.touched && newPassword.errors?.required"
As an example, mine looks like this:
<div class="col-md-8">
<input class="form-control"
id="productNameId"
type="text"
placeholder="Name (required)"
required
minlength="3"
[(ngModel)] = product.productName
name="productName"
#productNameVar="ngModel" />
<span class="help-block" *ngIf="(productNameVar.touched ||
productNameVar.dirty || product.id !== 0) &&
productNameVar.errors">
<span *ngIf="productNameVar.errors.required">
Product name is required.
</span>
<span *ngIf="productNameVar.errors.minlength">
Product name must be at least three characters.
</span>
</span>
</div>
You can also use the following syntax and it will work without the need to have a value first:
form.get('newPassword').hasError('required')
This will check for 'required' in the errors.
This will work as well and it's more concise :
form.hasError('required','newPassword')
If you are compiling with AOT option, according to this article, you should privilege hasError() syntax:
Don’t use control.errors?.someError, use control.hasError(‘someError’)

Categories