0

I'm creating a "file upload" component in Angular and I'd like to mark it as invalid during the upload. Indeed, when the user selects a file, it gets uploaded to the server but during that period of time, I don't want the user to be able to submit the form, so I'd like to set the validity state of the control to "invalid" when the upload starts and to "valid" when the upload is done.

I read that I can implement the interface Validator but it seems to me that the validate method gets called by Angular and not by me, so I can't mark the control as invalid as I want.

ssougnez
  • 5,315
  • 11
  • 46
  • 79
  • why not just mark fields/buttons as disabled? – John Kane Jul 31 '19 at 20:47
  • I want the control to be generic, so if the control is able to set its validity to "invalid" by itself, the form validity would be updated as well and then, my submit button that is disabled when the form is invalid would become disables automatically. I don't want to require extra lines of code as soon as my form contains a file upload control. – ssougnez Jul 31 '19 at 20:53
  • does this help? This sets a field invalid, thus making the form invalid https://stackoverflow.com/questions/43553544/how-can-i-manually-set-an-angular-form-field-as-invalid – sinanspd Jul 31 '19 at 20:59
  • Not really. I want to be able to update the validity state from within the class that inherits `ControlValueAccessor`. The issue is that this interface does not give me access to the control the it represents, so I can't call `control.setErrors()` – ssougnez Jul 31 '19 at 21:03

2 Answers2

0

I finally found what I was looking for. Posting the solution here as I guess it could be interesting for others.

First, I inject Injector in the custom form control:

constructor(private inj: Injector) {}

Then, in ngOnInit, I retrieve a reference to NgControl which refers to the form control:

public ngOnInit() {
    this._control = this.inj.get(NgControl);
}

Then, whenever I want, I can update the validity of the control:

this._control.control.setErrors({ 'uploading': true });

Note that it is a temporary validation, indeed, as soon as you call onChange, the validation is rechecked by Angular, so the error "uploading" is not maintained.

ssougnez
  • 5,315
  • 11
  • 46
  • 79
0

an outside the box solution here might be to implement an async validator that actually performs the upload, like:

uploadCompleteValidator() {
  return (ctrl: AbstractControl) => {
    let value = ctrl.value;
    return (value) ? this.uploadFile(value).pipe(mapTo(null)) : of(null);
  };
}

an async validator runs everytime the control value changes, and is invalid while the async validation is in flight, which is what it seems like you want here. I've never used a validator in this way, and it seems kind of odd, but it could work.

Another option is to have a group with 2 controls instead of a single control. 1 control for the file, and 1 control for the result, then define a "both or neither" validator, and you set the result control automatically upon upload completion.

bryan60
  • 28,215
  • 4
  • 48
  • 65