Skip to content
This repository has been archived by the owner on Mar 27, 2023. It is now read-only.

How to mark custom form control as dirty/touched? #3191

Closed
przemekciacka opened this issue Mar 7, 2019 · 6 comments
Closed

How to mark custom form control as dirty/touched? #3191

przemekciacka opened this issue Mar 7, 2019 · 6 comments
Labels
resolution: no fix needed Issues that do not require a change to Clarity

Comments

@przemekciacka
Copy link

Issue

When using the custom form control that implements Angular's ControlValueAccessor interface it isn't marked as touched/dirty when markAsDirty() method of ClrForm is called.

Code examples

component.ts

export class CorrespondenceNewModalComponent implements OnInit {
  @ViewChild(ClrForm) clrForm: ClrForm;

  form: FormGroup;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    this.buildForm();
  }

  onFormSubmit() {
    if (this.form.invalid) {
      this.clrForm.markAsDirty();
      return;
    }
  }

  private buildForm() {
    this.form = this.formBuilder.group({
      sender: [null, [Validators.required]],
      sentAt: ['', [Validators.required]]
    });
  }
}

where type, sender and receiver fields are used by custom form controls.

component.html

<form clrForm [formGroup]="form" (submit)="onFormSubmit()">
  <div class="clr-form-control clr-row">
    <label for="sender" class="clr-control-label clr-col-4">Sender</label>
    <div class="clr-control-container clr-col-8">
      <app-custom-form-control formControlName="sender"></app-custom-form-control>
    </div>
  </div>

  <clr-date-container>
    <label class="clr-col-4">Data wysłania</label>
    <input
      type="date"
      class="clr-col-8"
      clrDate
      formControlName="sentAt"
    />
  </clr-date-container>

  <input type="submit" value="Save" />
</form>

custom-form-control.ts

@Component({
  selector: 'app-custom-form-control',
  templateUrl: './correspondence-contact-select.component.html',
  styleUrls: ['./correspondence-contact-select.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CorrespondenceContactSelectComponent),
      multi: true
    }
  ]
})
export class CustomFormControlComponent implements OnInit, ControlValueAccessor {
  disabled: boolean;
  options: any[] = [
    { value: 1, label: 'Option 1' },
    { value: 2, label: 'Option 2' }
  ];
  
  onChange: any = () => {};
  onTouched: any = () => {};

  ngOnInit() {}

  onSelectChange(value) {
    this.onChange(value);
  }

  writeValue(value: Contact): void {}

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState?(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }
}

custom-form-control.html

<ng-select bindLabel="label" bindValue="value" [items]="contacts" (change)="onSelectChange($event)"></ng-select>

In source codes of the Clarity, I found MarkControlService that seems to be used to mark controls as dirty/touched but can't figure it out how to use with custom form control or if it possible even?

Any ideas about how it can be achieved?

@gnomeontherun
Copy link
Contributor

This is a limitation in Angular currently that is being tracked by angular/angular#10887. I suggest looking at some of the workarounds proposed there for your form control to get an instance of your FormControl, and then be able to call the appropriate markAs methods. Also see https://stackoverflow.com/questions/44730711/how-do-i-know-when-custom-form-control-is-marked-as-pristine-in-angular.

Closing as an issue with Angular.

@gnomeontherun gnomeontherun added the resolution: no fix needed Issues that do not require a change to Clarity label Mar 7, 2019
@przemekciacka
Copy link
Author

@gnomeontherun examples you posted works perfectly but with use FormGroup instance not ClrForm provided by the Clarity, by example:

From the previous example if I add to custom-form-control.ts file the following code (as in examples from StackOverflow you posted)

@Input() control: FormControl;

...

ngOnInit() {
    this.control.markAsTouched = function() {
      console.log('Control marked as touched');
    };
}

where control is injected using @Input() and is accessible, it works only when I call the following code from the form component (added to component.ts from the above example)

onFormSubmit() {
    if (this.form.invalid) {
      // this.clrForm.markAsDirty();
      this.markFormGroupTouched(this.form);
      return;
    }
}

private markFormGroupTouched(form: FormGroup) {
    Object.values(form.controls).forEach(control => {
      control.markAsTouched();

      if ((control as any).controls) {
        this.markFormGroupTouched(control as FormGroup);
      }
    });
}

As you can see in that scenario I don't use this.clrForm.markAsDirty() but directly controls from FormGroup instance. By this approach, I can handle markAsTouched in my custom components but the downside is that Clarity's form inputs are not marked as touch nor validation icon is shown. On the other hand, when I call this.clrForm.markAsDirty() it works the opposite way: clarity's inputs are marked as touched but my custom input doesn't receive any update at all, even using examples provided by you. It looks like the clarity's form mechanism doesn't touch at all custom form components. Correct me If I'm wrong.

@gnomeontherun
Copy link
Contributor

The purpose of clrForm.markAsDirty() is to mark all controls as dirty in the form. For this to work correctly, you'd have to also wrap it in a Clarity form container (which we don't have a generic wrapper yet, see #2864). So unfortunately, this requires you to do the same thing by traversing the form tree and marking it as dirty (which is exactly what clrForm.markAsDirty() does). So basically, if you have a form control that isn't supported by Clarity, our API can't pick it up.

I haven't tested this with custom form components, but if you wanted to make a stackblitz demo that would help so I can actually see what you're doing.

Either way, this is turning into a how-to kind of topic which we typically handle on StackOverflow.

@azad47808
Copy link

How can I mark a form controle as unTouched.

@mathisscott
Copy link
Contributor

@azad47808 : Have you tried resetting the formControl?

@github-actions
Copy link

Hi there 👋, this is an automated message. To help Clarity keep track of discussions, we automatically lock closed issues after 14 days. Please look for another open issue or open a new issue with updated details and reference this one as necessary.

@github-actions github-actions bot locked and limited conversation to collaborators Aug 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
resolution: no fix needed Issues that do not require a change to Clarity
Projects
None yet
Development

No branches or pull requests

4 participants