Getting error in Chrome Console: EXCEPTION: Error: Uncaught (in promise): TypeError: Cannot read property 'applicationName' of null.
Model:
export class BasicInfoModel {
applicationName: string;
localDirectoryPath: string;
}
Controller emitting data to parent component, parent component there it is saved to services.
Controller:
import { Component, Output, OnInit, EventEmitter} from '#angular/core';
import { FormGroup, FormControl, REACTIVE_FORM_DIRECTIVES, Validators,
FormBuilder, FormArray}from "#angular/forms";
import { Observable } from "rxjs/Rx";
import { BasicInfoModel } from '../basicinfomodel';
import { BasicInfoService} from '../app.dev.basicinfo.service';
#Component({
selector: 'basic-info',
templateUrl: './basicInfo.html',
styleUrls: ['../../ComponentStyles.css'],
directives: [REACTIVE_FORM_DIRECTIVES]
})
export class BASIC_INFOComponent implements OnInit {
observableBasic: BasicInfoModel;
basicInfoForm: FormGroup;
#Output() basicInfoUpdate = new EventEmitter<JSON>();
#Output() basicInfoFormValid = new EventEmitter<Boolean>();
constructor(private formBuilder: FormBuilder, private BasicInfoService:
BasicInfoService) { }
onSubmit() {
debugger;
this.observableBasic;
this.basicInfoUpdate.emit(this.basicInfoForm.value);
}
ngOnInit() {
this.basicInfoForm = new FormGroup({
'applicationName': new FormControl('', Validators.required),
'localDirectoryPath': new FormControl('', Validators.required)
});
this.basicInfoForm.valueChanges.subscribe(data => console.log('form
changes', data));
this.BasicInfoService.currentBasicInfo
.subscribe(
(basic: BasicInfoModel) => {
this.observableBasic = basic;
});
(<FormGroup>this.basicInfoForm).setValue(this.observableBasic, { onlySelf: true });
}
}
What i want to achieve:
When i build my code, i want my formGroup should be populated with null values.
when i filled the data and saved it to behaviourSubject in my services, latter when i revisit the page my formGroup should be in sync with data services.
Modified the Controler by adding : (this.observableBasic != undefined)
ngOnInit() {
this.basicInfoForm = new FormGroup({
'applicationName': new FormControl('', Validators.required),
'localDirectoryPath': new FormControl('', Validators.required)
});
this.BasicInfoService.currentBasicInfo
.subscribe((basic: BasicInfoModel) => { this.observableBasic = basic; });
if (this.observableBasic != undefined) {
(<FormGroup>this.basicInfoForm).setValue(this.observableBasic, { onlySelf: true });
}
this.basicInfoForm.valueChanges.subscribe(data => console.log('form changes', data));
}
Related
I'm having some trouble getting a custom validator working. I have other custom and non-custom validators working, but this one that I am passing a parameter to does not work as expected. Within the validator, it is recognizing that the validation code is working, but when looking at the form within field-validation-error, it is returning that the form is valid. Any help would be appreciated, thanks!
Within password.component.ts
this.passwordFormGroup = new FormGroup({
hintQuestionFormControl1: new FormControl(this.currentQuestions[0], Validators.required),
hintAnsFormControl1: new FormControl(this.currentAnswers[0], [Validators.required, EditAccountValidators.checkQuestionsDontContainAnswer('hintQuestionFormControl1')]),
});
Within edditAccountValidators.ts
export class EditAccountValidators {
public static checkQuestionsDontContainAnswer(correspondingQuestion: string): ValidatorFn {
return (control: FormControl) => {
if (control.parent) {
const question = control.parent.get(correspondingQuestion).value;
const answer = control.value;
if (question && answer) {
question.split(" ").forEach(function (wordInQuestion) {
answer.split(" ").forEach(function (wordInAnswer) {
if (wordInQuestion.toLowerCase().includes(wordInAnswer.toLowerCase())) {
console.log('same');
return {answerDoesntContainQuestion : true};
}
});
});
}
}
return null;
}
}
Within field-validation-error.component.ts
import {Component, Input, OnInit} from '#angular/core';
#Component({
selector: 'field-validation-error',
templateUrl: './field-validation-error.component.html',
styleUrls: ['./field-validation-error.component.css']
})
export class FieldValidationErrorComponent implements OnInit {
#Input() validatorName: string;
#Input() form: any;
errorMessage: string;
displayError: boolean;
ngOnInit(): void {
this.errorMessage = this.getValidatorErrorMessage();
this.form.valueChanges.subscribe(() => {
this.displayError = this.form.hasError(this.validatorName);
console.log(this.form);
});
}
private getValidatorErrorMessage() {
return this.validatorName;
}
}
calling Within password.component.html
<field-validation-error
[form]="passwordFormGroup.get('hintAnsFormControl1')"
[validatorName]="'answerDoesntContainQuestion'">
</field-validation-error>
My async validation function call on every keyup event. How to call async function on blue event.
Registration Component Code::
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { UserService } from '../../services/user.service';
import { ApiError } from '../../models/apierror';
import { UniqueUsername } from '../class/unique-username';
#Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css'],
})
export class RegisterComponent implements OnInit {
error!: ApiError;
submitted = false;
registrationForm!: FormGroup;
constructor(
private fb: FormBuilder,
private router: Router,
private userService: UserService,
private uniqueUsername: UniqueUsername
) {}
ngOnInit(): void {
this.registrationForm = this.fb.group({
name: ['', Validators.required],
username: [
'',
[Validators.required],
[this.uniqueUsername.validate.bind(this.uniqueUsername)],
],
password: ['', Validators.required],
});
}
get name() {
return this.registrationForm.get('name');
}
get username() {
return this.registrationForm.get('username');
}
get password() {
return this.registrationForm.get('password');
}
onSubmit() {
const formData = new FormData();
formData.append('name', this.registrationForm.get('name')!.value);
formData.append('username', this.registrationForm.get('username')!.value);
formData.append('password', this.registrationForm.get('password')!.value);
}
gotoHome() {
this.router.navigate(['/']);
}
}
Async Validator class code::
import { Injectable } from '#angular/core';
import {
AbstractControl,
AsyncValidator,
ValidationErrors,
} from '#angular/forms';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { UserService } from '../../services/user.service';
#Injectable({ providedIn: 'root' })
export class UniqueUsername implements AsyncValidator {
constructor(private userService: UserService) {}
validate(control: AbstractControl): Observable<ValidationErrors | null> {
const { value } = control;
return this.userService.checkUsername(value).pipe(
map((isExist: boolean) => (isExist ? { uniqueUserName: true } : null)),
catchError(() => of(null))
);
}
}
Combine AbstractControlOptions with FormBuilder:
this.registrationForm = new FormGroup(
this.fb.group({
name: ['', Validators.required],
username: [
'',
[Validators.required],
[this.uniqueUsername.validate.bind(this.uniqueUsername)],
],
password: ['', Validators.required],
}).controls, {
updateOn: 'blur'
}
);
Using the constructor of FormGroup and FormControl
form=new FormGroup({
...
username:new FormControl('',{
validators:Validators.required,
asyncValidators:this.uniqueUsername.validate.bind(this.uniqueUsername),
updateOn:'blur'
}
)
})
Using FormBuilder
form=this.fb.group({
...
username:this.fb.control('',{
validators:Validators.required,
asyncValidators:this.uniqueUsername.validate.bind(this.uniqueUsername),
updateOn:'blur',
})
})
//or
form=this.fb.group({
...
username:['',{
validators:Validators.required,
asyncValidators:this.uniqueUsername.validate.bind(this.uniqueUsername),
updateOn:'blur',
}]
})
You can use updateOn:'blur' from AbstractControlOptions interface. Other option available are change & submit
I am building an Angular 4 app that requires the BriteVerify email validation on form fields in several components. I am trying to implement this validation as a custom async validator that I can use with reactive forms. Currently, I can get the API response, but the control status is stuck in pending state. I get no errors so I am a bit confused. Please tell me what I am doing wrong. Here is my code.
Component
import { Component,
OnInit } from '#angular/core';
import { FormBuilder,
FormGroup,
FormControl,
Validators } from '#angular/forms';
import { Router } from '#angular/router';
import { EmailValidationService } from '../services/email-validation.service';
import { CustomValidators } from '../utilities/custom-validators/custom-validators';
#Component({
templateUrl: './email-form.component.html',
styleUrls: ['./email-form.component.sass']
})
export class EmailFormComponent implements OnInit {
public emailForm: FormGroup;
public formSubmitted: Boolean;
public emailSent: Boolean;
constructor(
private router: Router,
private builder: FormBuilder,
private service: EmailValidationService
) { }
ngOnInit() {
this.formSubmitted = false;
this.emailForm = this.builder.group({
email: [ '', [ Validators.required ], [ CustomValidators.briteVerifyValidator(this.service) ] ]
});
}
get email() {
return this.emailForm.get('email');
}
// rest of logic
}
Validator class
import { AbstractControl } from '#angular/forms';
import { EmailValidationService } from '../../services/email-validation.service';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
export class CustomValidators {
static briteVerifyValidator(service: EmailValidationService) {
return (control: AbstractControl) => {
if (!control.valueChanges) {
return Observable.of(null);
} else {
return control.valueChanges
.debounceTime(1000)
.distinctUntilChanged()
.switchMap(value => service.validateEmail(value))
.map(data => {
return data.status === 'invalid' ? { invalid: true } : null;
});
}
}
}
}
Service
import { Injectable } from '#angular/core';
import { HttpClient,
HttpParams } from '#angular/common/http';
interface EmailValidationResponse {
address: string,
account: string,
domain: string,
status: string,
connected: string,
disposable: boolean,
role_address: boolean,
error_code?: string,
error?: string,
duration: number
}
#Injectable()
export class EmailValidationService {
public emailValidationUrl = 'https://briteverifyendpoint.com';
constructor(
private http: HttpClient
) { }
validateEmail(value) {
let params = new HttpParams();
params = params.append('address', value);
return this.http.get<EmailValidationResponse>(this.emailValidationUrl, {
params: params
});
}
}
Template (just form)
<form class="email-form" [formGroup]="emailForm" (ngSubmit)="sendEmail()">
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<fieldset class="form-group required" [ngClass]="{ 'has-error': email.invalid && formSubmitted }">
<div>{{ email.status }}</div>
<label class="control-label" for="email">Email</label>
<input class="form-control input-lg" name="email" id="email" formControlName="email">
<ng-container *ngIf="email.invalid && formSubmitted">
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Please enter valid email address.
</ng-container>
</fieldset>
<button type="submit" class="btn btn-primary btn-lg btn-block">Send</button>
</div>
</div>
</form>
There's a gotcha!
That is, your observable never completes...
This is happening because the observable never completes, so Angular does not know when to change the form status. So remember your observable must to complete.
You can accomplish this in many ways, for example, you can call the first() method, or if you are creating your own observable, you can call the complete method on the observer.
So you can use first()
UPDATE TO RXJS 6:
briteVerifyValidator(service: Service) {
return (control: AbstractControl) => {
if (!control.valueChanges) {
return of(null);
} else {
return control.valueChanges.pipe(
debounceTime(1000),
distinctUntilChanged(),
switchMap(value => service.getData(value)),
map(data => {
return data.status === 'invalid' ? { invalid: true } : null;
})
).pipe(first())
}
}
}
A slightly modified validator, i.e always returns error: STACKBLITZ
OLD:
.map(data => {
return data.status === 'invalid' ? { invalid: true } : null;
})
.first();
A slightly modified validator, i.e always returns error: STACKBLITZ
So what I did was to throw a 404 when the username was not taken and use the subscribe error path to resolve for null, and when I did get a response I resolved with an error. Another way would be to return a data property either filled width the username or empty
through the response object and use that insead of the 404
Ex.
In this example I bind (this) to be able to use my service inside the validator function
An extract of my component class ngOnInit()
//signup.component.ts
constructor(
private authService: AuthServic //this will be included with bind(this)
) {
ngOnInit() {
this.user = new FormGroup(
{
email: new FormControl("", Validators.required),
username: new FormControl(
"",
Validators.required,
CustomUserValidators.usernameUniqueValidator.bind(this) //the whole class
),
password: new FormControl("", Validators.required),
},
{ updateOn: "blur" });
}
An extract from my validator class
//user.validator.ts
...
static async usernameUniqueValidator(
control: FormControl
): Promise<ValidationErrors | null> {
let controlBind = this as any;
let authService = controlBind.authService as AuthService;
//I just added types to be able to get my functions as I type
return new Promise(resolve => {
if (control.value == "") {
resolve(null);
} else {
authService.checkUsername(control.value).subscribe(
() => {
resolve({
usernameExists: {
valid: false
}
});
},
() => {
resolve(null);
}
);
}
});
...
I've been doing it slightly differently and faced the same issue.
Here is my code and the fix in case if someone would need it:
forbiddenNames(control: FormControl): Promise<any> | Observable<any> {
const promise = new Promise<any>((resolve, reject) => {
setTimeout(() => {
if (control.value.toUpperCase() === 'TEST') {
resolve({'nameIsForbidden': true});
} else {
return null;//HERE YOU SHOULD RETURN resolve(null) instead of just null
}
}, 1);
});
return promise;
}
I tries using the .first(). technique described by #AT82 but I didn't find it solved the problem.
What I eventually discovered was that the form status was changing but it because I'm using onPush, the status change wasn't triggering change detection so nothing was updating in the page.
The solution I ended up going with was:
export class EmailFormComponent implements OnInit {
...
constructor(
...
private changeDetector: ChangeDetectorRef,
) {
...
// Subscribe to status changes on the form
// and use the statusChange to trigger changeDetection
this.myForm.statusChanges.pipe(
distinctUntilChanged()
).subscribe(() => this.changeDetector.markForCheck())
}
}
import { Component,
OnInit } from '#angular/core';
import { FormBuilder,
FormGroup,
FormControl,
Validators } from '#angular/forms';
import { Router } from '#angular/router';
import { EmailValidationService } from '../services/email-validation.service';
import { CustomValidators } from '../utilities/custom-validators/custom-validators';
#Component({
templateUrl: './email-form.component.html',
styleUrls: ['./email-form.component.sass']
})
export class EmailFormComponent implements OnInit {
public emailForm: FormGroup;
public formSubmitted: Boolean;
public emailSent: Boolean;
constructor(
private router: Router,
private builder: FormBuilder,
private service: EmailValidationService
) { }
ngOnInit() {
this.formSubmitted = false;
this.emailForm = this.builder.group({
email: [ '', [ Validators.required ], [ CustomValidators.briteVerifyValidator(this.service) ] ]
});
}
get email() {
return this.emailForm.get('email');
}
// rest of logic
}
I've got a sign up form and I want to check that if the username is already taken or not. To achieve this I'm using promises now.
My sign up component looks like this:
import { Component, OnInit } from '#angular/core';
import { FormControl, FormBuilder, FormGroup, Validators } from '#angular/forms';
import { UserService } from '../shared/user.service'
#Component({
selector: 'app-auth',
providers: [],
templateUrl: './auth.component.html',
styleUrls: ['./auth.component.css']
})
export class AuthComponent implements OnInit {
// Tabs for log in or sign up
tab = 'signup';
// Sign up form
signUpForm: FormGroup;
// Log in form
logInForm: FormGroup;
constructor(private formBuilder: FormBuilder, private ussr: UserService) {
this.signUpForm = this.formBuilder.group({
'username': [null, [
Validators.required, Validators.minLength(4), Validators.maxLength(12), this.ussr.getUserNameFromServer
]],
'email': '',
'password': '' });
this.logInForm = this.formBuilder.group({ 'username': '', 'password': '' });
}
ngOnInit() {
}
activeTab(tab: string) {
this.tab = tab;
}
signUpSubmit(value: any) {
console.log(value);
}
}
And the UserService:
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { FormControl } from '#angular/forms';
import 'rxjs/add/operator/map';
#Injectable()
export class UserService {
constructor (private http: Http) {}
private extractData (res: Response) {
let body = res.json();
return body || { };
}
getUserNameFromServer = (c: FormControl) => {
return new Promise (
(resolve, reject) => {
this.http.get('https://jsonplaceholder.typicode.com/users/1')
.map(this.extractData)
.subscribe(
(res: any) => {
if (c.value == res.username) {
console.log('taken')
resolve({'usernameTaken': true})
} else {
console.log('is not taken')
resolve(null)
}
},
err => { console.log(err) }
)
}
);
}
}
I already read some blog posts about this topic, and I also checked two SO questions (1, 2), but I can't get it to work.
The service successfully got the server's answer, but when I call it inside the component's validator, the form is going to be invalid every time.
In the examples above, they just call it in the validator section, and I guess the ng2 do the rest of the work in the background, or am I wrong? How is the validator got the promise's value?
The problem was that I insert the async custom validator into the sync validator section. Which means the 2nd param is for the sync validators, the 3rd one for the async ones.
This works now:
'username': [null,
[ Validators.required, Validators.minLength(4), Validators.maxLength(12) ],
[ this.ussr.getUserNameFromServer ]
],
Let's say we have a service that does an http call to an API to create an user. Based on the result (200 or error) the app should redirect or display the errors (there are some Validations going on client-side, but that is not the topic since validations should always also happen server-side).
The Angular 2 docs state that it is bad practice to let the service return an observable and subscribe to it in the component. The service should be self-contained and the component shouldn't need to know anything about this. It should be enough to call userService.createUser(user_data);
But then again routing should happen in the component. So I'm wondering how to handle this situation? Should my Service return a new Observable? Or just a value? But then how do I deal with the async task?
What is the right way to do this?
Let's take this service to create a user and this component as an example:
// user.service.ts:
import { Http, Headers } from '#angular/http';
import { Inject, Injectable } from '#angular/core';
import { API_CONFIG, Config } from '../config/api.config';
import { User } from '../models/user.model';
#Injectable()
export class UserService {
validation_errors: Array<any> = [];
constructor(
#Inject(API_CONFIG) private api_config: Config,
private http: Http,
#Inject(User) public user: User
) {}
createUser(user: User) {
var body = JSON.stringify({ user });
var myHeader = new Headers();
myHeader.append('Content-Type', 'application/json');
this.http.post(this.api_config.apiEndpoint + '/users/', body, { headers: myHeader })
.map(res => res.json())
.subscribe(
res => {
// User was created successfully
this.user = this.fromJson(res.data);
},
err => {
// Something went wrong, let's collect all errors in a class attribute
let errors = err.json().errors;
for(var i = 0; i < errors.length; i++) {
this.validation_errors.push(errors[i])
}
}
);
}
/**
* #param input_json JSON returned from API, formatted according to jsonapi.org, containing one single user.
* #return UserModel instantiated with the values from input_json
*/
fromJson(input_json: any) {
var user:User = new User();
user = input_json.attributes;
user.id = input_json.id;
return user;
}
}
// user.component.ts:
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup, REACTIVE_FORM_DIRECTIVES, Validators } from '#angular/forms';
import { Router, RouteParams, ROUTER_DIRECTIVES } from '#angular/router-deprecated';
import { UserService } from '../../shared/index';
#Component({
selector: 'fac-user-editor',
templateUrl: 'app/+users/editor/user-editor.component.html',
styleUrls: ['app/+users/editor/user-editor.component.css'],
directives: [REACTIVE_FORM_DIRECTIVES, ROUTER_DIRECTIVES],
providers: [UserService]
})
export class UserEditorComponent implements OnInit {
// Setup Form
private email_regex = '[a-z0-9\\.\\-\\_]+#[a-z0-9\\.\\-\\_]+\\.[a-z0-9\\.\\-\\_]+';
userForm: FormGroup;
action: string;
idCtrl = new FormControl('');
nameCtrl = new FormControl('', [Validators.required]);
emailCtrl = new FormControl('', [Validators.required, Validators.pattern(this.email_regex)]);
usernameCtrl = new FormControl('', [Validators.required, Validators.minLength(5)]);
passwordCtrl = new FormControl('', [Validators.minLength(8)]);
passwordConfirmationCtrl = new FormControl('');
public user_id: string;
constructor(private userService: UserService, private router: Router, private params: RouteParams) {}
/**
* Handle submit of form
*/
onSubmit(form: any) {
// Here should happen some error handling / routing, depending on the result of the call to the API
this.userService.createUser(this.userService.user);
}
ngOnInit(): any {
this.userForm = new FormGroup({
id: this.idCtrl,
name: this.nameCtrl,
email: this.emailCtrl,
username: this.usernameCtrl,
password: this.passwordCtrl,
password_confirmation: this.passwordConfirmationCtrl
});
}
}
I could display the error messages in the template like this:
<div class="form-group"
[hidden]="adminService.validation_errors.length === 0"
class="alert alert-warning" role="alert">
<strong>Some errors occured</strong>
<ul>
<li *ngFor="let validation_error of adminService.validation_errors">
<span class="text-capitalize">{{validation_error.source.field}}:</span> {{validation_error.detail}}
</li>
</ul>
</div>
This is how I solved the problem. My service now uses .map() to transform the data (JSON) returned from the backend and returns an Observable which will initialise my User Model. The Component can subscribe to the observable. The data is stored in a variable of the component, as well as the validation errors.
I also use FormBuilder form the new Form API. This should work with RC 3.
I hope this helps someone.
// user.service.ts:
import { Http, Headers } from '#angular/http';
import { Inject, Injectable } from '#angular/core';
import { API_CONFIG, Config } from '../config/api.config';
import { User } from '../models/user.model';
#Injectable()
export class UserService {
constructor(
#Inject(API_CONFIG) private api_config: Config,
private http: Http,
#Inject(User) public user: User
) {}
createUser(user: User) {
var body = JSON.stringify({ user });
var myHeader = new Headers();
myHeader.append('Content-Type', 'application/json');
// Use map to transform reply from server (JSON to User Object) and return an Observable
// The component can subscribe to.
return this.http.post(this.api_config.apiEndpoint + '/users/', body, { headers: myHeader })
.map(res => res.json())
.map(res => {
return this.fromJson(res.data);
});
}
/**
* #param input_json JSON returned from API, formatted according to jsonapi.org, containing one single user.
* #return UserModel instantiated with the values from input_json
*/
fromJson(input_json: any) {
var user:User = new User();
user = input_json.attributes;
user.id = input_json.id;
return user;
}
}
// user.component.ts:
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup, FormBuilder, REACTIVE_FORM_DIRECTIVES, Validators } from '#angular/forms';
import { Router, RouteParams, ROUTER_DIRECTIVES } from '#angular/router-deprecated';
// Include the User Model
import { User, UserService } from '../../shared/index';
#Component({
selector: 'fac-user-editor',
templateUrl: 'app/+users/editor/user-editor.component.html',
styleUrls: ['app/+users/editor/user-editor.component.css'],
directives: [REACTIVE_FORM_DIRECTIVES, ROUTER_DIRECTIVES],
providers: [User, UserService]
})
export class UserEditorComponent implements OnInit {
// Setup Form
private email_regex = '[a-z0-9\\.\\-\\_]+#[a-z0-9\\.\\-\\_]+\\.[a-z0-9\\.\\-\\_]+';
userForm: FormGroup;
validation_errors: Array<string> = [];
user_id: string;
constructor(private userService: UserService, private user: User, private router: Router, private params: RouteParams, private formBuilder: FormBuilder) {}
/**
* Handle submit of form
*/
onSubmit(form: any) {
// Subscribe to observable and handle errors
this.userService.createUser(this.userService.user).subscribe(
user => {
// Store created user in Component variable. We could now display it or navigate somewhere
this.user = user;
},
err => {
let errors = err.json().errors;
for(var i = 0; i < errors.length; i++) {
// Handle errors in the component and don't store it in the Service
this.validation_errors.push(errors[i])
}
}
);
}
ngOnInit(): any {
// Use the new FormBuilder
this.userForm = this.formBuilder.group({
id: [''],
name: ['', Validators.required],
email: ['', [Validators.required, Validators.pattern(this.email_regex)]],
username: ['', [Validators.required, Validators.minLength(5)]],
password: ['', [Validators.required, Validators.minLength(8)]],
password_confirmation: ['']
});
}
}
user-editor.component.html
<div class="form-group"
[hidden]="validation_errors.length === 0"
class="alert alert-warning" role="alert">
<strong>Some errors occured</strong>
<ul>
<li *ngFor="let validation_error ofvalidation_errors">
<span class="text-capitalize">{{validation_error.source.field}}:</span> {{validation_error.detail}}
</li>
</ul>
</div>