4
votes

I think i have a very common question about form handling in angular, but don't find any answer for my question after searching and reading for hours.

The problem:
I built a reactive form and if the user is in the angular context (typing values etc.), it's all fine. But when i use a chrome plugin like Web Developer Form Filler and fill the form with it, the model doesn't update.

To reproduce the problem, i've created a tiny app here: https://stackblitz.com/edit/angular-ltrmpd.

Form controller:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  form = new FormGroup({
    name: new FormControl('Valid name', [
      Validators.required,
      Validators.minLength(5)
    ])
  });

  get name() { return this.form.get('name'); }

  onSubmit() {
    // reload all form data and revalidate, but how?

    if (this.form.valid) {
      alert('VALID');
    }
  }
}

Form view:

<form [formGroup]="form" (ngSubmit)="onSubmit()">

  <div class="form-group row">
    <label for="name" class="col-sm-2 col-form-label">Name</label>
    <div class="col-sm-10">
      <input formControlName="name" type="text"class="form-control" id="name" [class.is-invalid]="name.invalid && name.touched" />
      <pre class="invalid-feedback">{{ name.errors | json }}</pre>
    </div>
  </div>

  <pre>{{ form.value | json }}</pre>
  <pre>form.valid: {{ form.valid }}</pre>

  <button type="button" class="btn btn-danger" onclick="document.getElementById('name').value = 'X'">SET VALUE FROM OUTSIDE</button> model doesn't update <br /><br />

  <button type="button" class="btn btn-success" (click)="name.patchValue('YYY')">SET VALUE ANGULAR WAY</button> updates the model right <br /><br />

  <button type="submit" class="btn btn-primary" [disabled]="!form.valid">Submit</button>
</form>
  • The default form value is valid
  • Click button "SET VALUE FROM OUTSIDE" -> the model doesn't update
  • Click "Submit" -> You should not be able to click the button or we update the model and validation state manually after clicking the button

The simplest solution i tried is to update the model and revalidate after the user submits the form. But how can i update the model with the current form values?

I only found this question: How to update Angular 2 Reactive form field when changes occurred outside of Angular world. But i think it's not the same problem, because i don't have any control over this form filler tools.

1
How about trigger an input event afterward? Does it resolve your problem? Anyway, you must notify Angular that values have been changed if they were changed from outside world. stackblitz.com/edit/angular-jybsvy?file=src/app/… - wannadream
It would solve the problem, if i had access to the functions of this tools. The user triggers the "fill form" action with a chrome plugin and it sets the form values according to the example i've posted. It would be safe if i could say "reload data from the form and write it to the model", like i mentioned above. - jonpanze

1 Answers

2
votes

I was looking for the same event and finally looked into the reactive form implementation under @angular/core package then there is an input event bind to the form element which is responsible for running validator attached to that form element and updating FormControlName.

so to solve your problem you can dispatch an input event on the same form control.

Example -

var event = new Event("input");
element.dispatchEvent(event);

if you need more insight on the reactive form implementation then you can look for it below.

Note- Below referring line number of default_value_accessor.ts file.

In line 68 – we’ve input event bind to the host element which ultimately calling _handleInput

host:      {
'(input)': '$any(this)._handleInput($event.target.value)',
'(blur)': 'onTouched()',
'(compositionstart)': '$any(this)._compositionStart()',
'(compositionend)': '$any(this)._compositionEnd($event.target.value)'
},

Line 134 – we’ve _handleInput definition which is running onChange callback which is responsible for running _executeValidators function from validator.ts .

/**@internal*/
_handleInput(value: any): void {
   if (!this._compositionMode || (this._compositionMode && !this._composing)) {
      this.onChange(value);
    }
}