Why is the form value object empty?

angular typescript angular-reactive-forms

1869 观看

2回复

49 作者的声誉

Help please understand. I'm trying to write a custom validator for a reactive form.

component:

private form: FormGroup;

  ngOnInit() {
    const this_ = this;

    this.form = new FormGroup({
      'email':      new FormControl(null, [Validators.required, Validators.email]),
      'password':   new FormControl(null, [Validators.required, Validators.minLength(6)]),
      'password2':  new FormControl(null, [Validators.required, Validators.minLength(6), this_.comparePasswords]),
      'name':       new FormControl(null, [Validators.required]),
      'agree':      new FormControl(false, [Validators.requiredTrue])
    });
  }

  comparePasswords(c: FormControl) {
    console.log(c);

    const hashStr = Md5.hashStr(c.value.password);
    const hashStr2 = Md5.hashStr(c.value.password2);

    console.log(hashStr, hashStr2);

    return (hashStr === hashStr2) ? null : {
      comparePasswords: {
        valid: false
      }
    };
  }

All the imports that you need to connect. After loading the page, the browser console immediately displays the form object, in which the value object is null.

I can not make check in the function comparePasswords().

Console display follow:

ERROR TypeError: Cannot read property 'password' of null

LIVE EXAMPLE HERE

作者: provoter33 的来源 发布者: 2017 年 12 月 27 日

回应 2


3

410 作者的声誉

Change null to ""

this.form = new FormGroup({
  'email':      new FormControl("", [Validators.required, Validators.email]),
  'password':   new FormControl("", [Validators.required, Validators.minLength(6)]),
  'password2':  new FormControl("", [Validators.required, Validators.minLength(6), this_.comparePasswords]),
  'name':       new FormControl("", [Validators.required]),
  'agree':      new FormControl(false, [Validators.requiredTrue])
});
作者: Wallace 发布者: 2017 年 12 月 27 日

1

45064 作者的声誉

Besides giving the initial value as null, you are setting your custom validator on the formcontrol, so what you actually get in your custom validator is just the formcontrol password2, not the entire formgroup.

I would therefore place the custom validator at formgroup level, or better yet, create a nested formgroup for the passwords and apply the validator for that. Why? Since if you apply the validator on the whole form, it will be fired whenever any changes happen to form. But in this sample, I apply it on the whole form as well as minified your code. Also the advantage to applying a custom validator on a formgroup level (nested or not) will take care of both checking the inputs. As your validator sits in your question it will only check if the password2 matches password whenever changes happens to the password2 field. So what happens if you modify the password field after modifying password2, an error is not showed, and form is considered valid.

So build form as such:

constructor(private fb: FormBuilder) { }

ngOnInit() {
  this.form = this.fb.group({
    password:   ['', [Validators.required, Validators.minLength(6)]],
    password2:  ['', [Validators.required, Validators.minLength(6)]],
  },{validator: this.comparePasswords});
}

Then your custom validator would look like this:

comparePasswords(c: FormGroup) {
  const hashStr = Md5.hashStr(c.controls.password.value);
  const hashStr2 = Md5.hashStr(c.controls.password2.value);
  return (hashStr === hashStr2) ? null : { notSame: true };
}

You could compare just c.controls.password.value and c.controls.password2.value but since you are using Md5, I just used those values here. Also notice that we are just sending an object with some custom error of your choosing, here notSame if the passwords do not match.

And to display the error message you can do:

<div *ngIf="form.hasError('notSame')">Passwords do not match!</div>

Your modified StackBlitz

作者: AJT82 发布者: 2017 年 12 月 28 日
32x32