Validation isn't working & Input Field is filled with my Own code

I have been following angular classes literally, but I am stuck with reactive forms
Validation isn’t working & input field is filled with some portions of my own code, I don’t know why

Appreciate any help

error1

Could you paste a code snippet showing the HTML and Typescript? Use the code format around you code snippets to make them legible:

let someVariable: string = "";

I appreciate your quick response dear

Here is the change-password.component.ts

import { Component} from '@angular/core';
import { FormBuilder, Validators, FormGroup, FormControl } from '@angular/forms';
import { PasswordValidators } from './password.validators';

@Component({
  selector: 'change-password',
  templateUrl: './change-password.component.html',
  styleUrls: ['./change-password.component.css']
})
export class ChangePasswordComponent {
  form: FormGroup;
  constructor(fb: FormBuilder){
    this.form = fb.group({
      oldPassword: new FormControl(['', Validators.required], PasswordValidators.validOldPassword),
      newPassword: new FormControl(['', Validators.required]),
      confirmPassword: new FormControl(['', Validators.required])
    }, {
        validator: PasswordValidators.passwordsShouldMatch
    } );
  }


  get oldPassword(){ return this.form.get('oldPassword'); }
  get newPassword(){ return this.form.get('newPassword'); }
  get confirmPassword(){ return this.form.get('confirmPassword'); }

}

& here is password.validators.ts

import { AbstractControl, ValidationErrors } from '@angular/forms';

export class PasswordValidators {
  static validOldPassword(control: AbstractControl){
    return new Promise((resolve) => {
      if(control.value !== '1234' ) resolve ({ invalidOldPassword: true });
      else resolve(null);
    });
  }

  static passwordsShouldMatch(control: AbstractControl) {
    let newPassword = control.get('newPassword');
    let confirmPassword = control.get('confirmPassword');

    if (newPassword.value !== confirmPassword.value)
      return { passwordsShouldMatch: true };
        
    return null;
  }
}

Still trying to verify the state of that screenshot you showed - is that the state of the page when you load it? Or is it only after you have entered some data into the fields? If you have an exact sequence of steps that you took to get into that state it would be nice to have those written out. For example:

  1. Refresh the page (or start with a fresh page)
  2. Type “blah” into some field
  3. … more steps…

And finally write down the expected result (eg. “get an error message saying …”) and what you are actually seeing (which could be multiple things that are unexpected).

  1. As I refresh the page the code gets filled automatically
  2. here is the text gets filled in the input field, I made the type of the first input field as text to make text visible…
,function (control) {        return isEmptyInputValue(control.value) ? { 'required': true } : null;    }

There is no error message whatsoever

output

So for starters, this syntax here is actually deprecated:

  form: FormGroup;
  constructor(fb: FormBuilder){
    this.form = fb.group({
      ...
    }, /* This bit here (start) ==> */ {
        validator: PasswordValidators.passwordsShouldMatch
    } /*  <=== This bit here (end) */);
  }

Adding a second parameter to the FormBuilder.group method was certainly not discussed in Mosh’s videos (only in his solution). In the Angular docs, that second parameter should contain an AbstractControlOptions unless you are invoking the deprecated API. According to the API of the AbstractControlOptions interface, you just need to rename that from validator to validators to be a valid AbstractControlOptions interface.

It is also unclear to me if you can safely combine FormBuilder with trying to manually construct the FormControl objects (which also look a bit wonky and might simply be improperly constructed):

  constructor(fb: FormBuilder){ /* <=== Using FormBuilder */
    this.form = fb.group({
      /* Then attempting to manually construct the FormControl: */
      oldPassword: new FormControl(['', Validators.required], PasswordValidators.validOldPassword),

A standard FormControl constructor should look more like this (according to its definition):

new FormControl('', Validators.required, PasswordValidators.validOldPassword)

You should be able to fix that by just leveraging FormBuilder:

  constructor(fb: FormBuilder){
    this.form = fb.group({
      oldPassword: ['', Validators.required, PasswordValidators.validOldPassword],
      newPassword: ['', Validators.required],
      confirmPassword: ['', Validators.required]
    }

Aside: I noticed a small bug at line 14 in your HTML (perhaps you can spot it now):

<div  *ngIf="oldPassword.errors.invalidOldPassword">Old Password is required.</div>

Interestingly, password match validator is the example Angular has in their docs for creating a “group-level validator” so it should be relatively easy to replicate.


Personally, I just put the validator on the confirmPassword and used the parent property on the AbstractControl to get access to the newPassword value (since it meant I had the confirmPassword directly available) which means my method to check if they match looks like this:

        if (control.parent?.get('newPassword')?.value === control.value) {
            return null;
        }
        return { confirmPasswordMismatch: true }

NOTE: that leverages a bunch of type-safety mumbo-jumbo since the version of TS / Angular I am working with obliges strict null safety.

Thanks a lot dear
some I am able to clear the input field.

this.form = fb.group({
      oldPassword: ['',                 // I removed this two single quotes & the field is now clear & added again
        Validators.required, 
        PasswordValidators.validOldPassword
      ],
      newPassword: ['', Validators.required],
      confirmPassword: ['', Validators.required]
    }, {
      validator: PasswordValidators.passwordsShouldMatch
    });

Only thing now bootstrap is not active

I believe you need the two single quotes since it is the first parameter for constructing a FormConcept.

Only thing now bootstrap is not active

Not sure what you mean “bootstrap is not active” - could you clarify?

Did you remember to add this to the top of styles.css?

@import "~bootstrap/dist/css/bootstrap.css";
/*
 * And possibly this if you want icons, though it seems
 * you would not need it for this particular exercise.
*/
@import "~bootstrap-icons/font/bootstrap-icons.css";

Just now I added these two lines

@import "~bootstrap/dist/css/bootstrap.css";
@import "~bootstrap/dist/css/bootstrap.min.css"

I would like to add that since the course is designed in Angular 4 & I was using Angular 12, I was often getting many errors, so I had to uninstall Angular 12, then I installed Angular 4, now everything is fine. maybe later after finishing the course I have a lot to do to migrate to the latest version of Angular…

thanks so much Mr. Jason Runkle for your help