I want to confirm the passwords, but when I wrote the logic of validator and send it to the mat-error
the message haven't shown, but the validator work normally, how fix this moment in reactive forms in my case??
export class SignUpComponent implements OnInit {
profileForm: FormGroup;
constructor(
private userService: UserService,
private formBuilder: FormBuilder
) {
this.profileForm = this.formBuilder.group({
name: ['', [Validators.required, Validators.pattern(/^[a-zA-Z0-9_ -]+$/)]],
email: ['', [Validators.required, Validators.pattern(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)]],
password: ['', [Validators.required, Validators.pattern(/^(?=.*[A-Z])(?=.*\d)(.{8,100})$/)]],
passwordConfirm: ['', [Validators.required]]
},
{ validator: this.checkPasswords }
);
}
checkPasswords(group: FormGroup) {
let pass = group.get('password').value;
let confirmPass = group.get('passwordConfirm').value;
return pass === confirmPass ? null : { mismatch: true }
}
ngOnInit() {
}
get name(){
return this.profileForm.get('name');
}
get email(){
return this.profileForm.get('email');
}
get password(){
return this.profileForm.get('password')
}
get passwordConfirm(){
return this.profileForm.get('passwordConfirm')
}
onSubmit() {
console.warn(this.profileForm.value);
this.userService.createUser(this.profileForm.value);
}
}
in html code
<form class="form-to-submit" [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<div class="form-input-position">
<mat-form-field class="example-full-width" >
<input matInput placeholder="Name" formControlName="name" required>
<mat-icon matSuffix>supervised_user_circle</mat-icon>
<mat-error *ngIf="name.hasError('required')">
Field should be <strong>required</strong>
</mat-error>
<mat-error *ngIf="name.hasError('pattern')">
Field should use <strong>Latin alphabet</strong>
</mat-error>
</mat-form-field>
</div>
<div class="form-input-position">
<mat-form-field class="example-full-width" >
<input matInput placeholder="Email" formControlName="email" required>
<mat-icon matSuffix>email</mat-icon>
<mat-error *ngIf="email.hasError('required')">
Field should be <strong>required</strong>
</mat-error>
<mat-error *ngIf="email.hasError('pattern')">
Use right <strong>email format</strong>
</mat-error>
</mat-form-field>
</div>
<div class="form-input-position">
<mat-form-field class="example-full-width" >
<input matInput type="password" placeholder="Password" formControlName="password" required>
<mat-icon matSuffix>lock</mat-icon>
<mat-error *ngIf="password.hasError('required')">
Field should be <strong>required</strong>
</mat-error>
<mat-error *ngIf="password.hasError('pattern')">
Should be <strong>minimum 8 elements, one uppercase letter, one number</strong>
</mat-error>
</mat-form-field>
</div>
<div class="form-input-position">
<mat-form-field class="example-full-width" >
<input matInput type="password" placeholder="Confirm password" formControlName="passwordConfirm" required>
<mat-icon matSuffix>lock</mat-icon>
<mat-error *ngIf="passwordConfirm.hasError('required')">
Field should be <strong>required</strong>
</mat-error>
{{profileForm.hasError('mismatch')}}
<mat-error *ngIf="profileForm.hasError('mismatch')">
Password <strong>mistmached</strong>
</mat-error>
</mat-form-field>
</div>
<div class="form-input-button">
<button mat-raised-button color="accent" [disabled]="!profileForm.valid" type="submit">Submit</button>
<button mat-raised-button color="warn">Cancel</button>
</div>
</form>
this case I have tried (Confirm password validation in Angular 6 solution) but the problem in error:
Uncaught Error: Unexpected value 'SignUpComponent' declared by the module 'AppModule'. Please add a @Pipe/@Directive/@Component annotation.
and if I am right it is template-driven forms
not a reactive way
Node
my app.modul.ts
file
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { SignUpComponent } from './sign-up/sign-up.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatIconModule,
MatMenuModule,
MatInputModule,
MatButtonModule
} from '@angular/material';
import { LoginComponent } from './login/login.component';
import { HomeComponent } from './home/home.component';
@NgModule({
declarations: [
AppComponent,
SignUpComponent,
LoginComponent,
HomeComponent
],
imports: [
BrowserModule,
FormsModule,
AppRoutingModule,
BrowserAnimationsModule,
MatMenuModule,
MatIconModule,
MatInputModule,
MatButtonModule,
ReactiveFormsModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Node 2
I have read the https://itnext.io/materror-cross-field-validators-in-angular-material-7-97053b2ed0cf
and this https://material.angular.io/components/input/overview#changing-when-error-messages-are-shown
this links told about the ErrorStateMatcher implementation to touch the input. Well I changed my code
in sign-up.component.ts
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
return control.dirty && form.invalid;
}
}
If we started typing something in the input, and the form itself is invalid, state that the control has errors.
create the object errorMatcher = new MyErrorStateMatcher();
in sign in class SignUpComponent
my form in ts file looks like
this.profileForm = this.formBuilder.group({
name: ['', [Validators.required, Validators.pattern(/^[a-zA-Z0-9_ -]+$/)]],
email: ['', [Validators.required, Validators.pattern(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)]],
password: ['', [Validators.required, Validators.pattern(/^(?=.*[A-Z])(?=.*\d)(.{8,100})$/)]],
passwordConfirm: ['']
},
{ validator: this.passwordValidator }
);
}
passwordValidator(form: FormGroup) {
const condition = form.get('password').value !== form.get('verifyPassword').value;
return condition ? { passwordsDoNotMatch: true} : null;
}
and finally html file
<input matInput type="password" placeholder="Confirm password" formControlName="passwordConfirm" required
[errorStateMatcher]="matcher">
<mat-icon matSuffix>lock</mat-icon>
<mat-error *ngIf="passwordConfirm.hasError('required')">
Field should be <strong>required</strong>
</mat-error>
{{profileForm.hasError('mismatch')}}
<mat-error
*ngIf="profileForm.hasError('passwordsDoNotMatch')">
Field should be <strong>AAAAA</strong>
</mat-error>
<p
*ngIf="profileForm.hasError('passwordsDoNotMatch')">aaaaaaaaaaaaaaaa</p>
However, I have a big problem which stop downloading form
compiler.js:2175 Uncaught Error: Unexpected value 'SignUpComponent' declared by the module 'AppModule'. Please add a @Pipe/@Directive/@Component annotation.
I've tried to fix it (add to @NgModule next lines)
providers: [
{ provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher }
],
but it didn't help me
*Update
To create a customFormControl over a control, we use parent, see an example
As we want to make check when password change too
See that the form is like
And the .html
The stackblitz here
The other way is using a custom errorStateMatcher
Update 2 I said that other way is "use a errorStateMatcher." A erroStateMatcher is a simple function that return true or false. If return true, our control will be marked as if he was invalid(*)
Imagine we has a form like
See that error is belong to formGroup, we can create a customErrorMatcher that return true if control is invalid or if form.hasError('mismatch`)
Well, the .html
As always I can, the stackblitz
(*) check in the stackblitz form.get('passwordConfirm').invalid