tiaguinho / material-community-components

:panda_face: Angular Material Components created from the community
https://tiaguinho.github.io/material-community-components
MIT License
324 stars 50 forks source link

Binding the colorPicker to an input in a Reactive Form #79

Open Samoulou opened 5 years ago

Samoulou commented 5 years ago

When connecting the colorpicker to an input in a Reactive From using MccColorPickerOrigin and MccConnectedColorPicker it put the input controls as pristine: false.

The binding between the color picker and the input is certainly detected as a modification after the init.

The binding shouldn't make the input controls as pristine

samogot commented 5 years ago

I've bypassed it by creating my own control that implements ControlValueAccessor and wraps MccColorPickerComponent

IMPORTANT NOTICE: I only need to track confirmed changes as dirty, that's why I use selected event with distinctUntilChanged. this.formData.valueChanges.pipe(first()) and skip(1) is needed to to know first value after initialization (for distinct to work) but don't trigger change for it

color-picker.component.html:

<mat-form-field class="full-width">
  <input #origin="mccColorPickerOrigin" (blur)="_OnTouched()" [formControl]="formData" [placeholder]="placeholder"
    matInput mccColorPickerOrigin/>
  <mcc-color-picker #picker [mccConnectedColorPickerOrigin]="origin" class="color-prefix" matPrefix mccConnectedColorPicker>
  </mcc-color-picker>
</mat-form-field>

color-picker.component.ts:

import { Component, forwardRef, Input, ViewChild } from '@angular/core';
import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from "@angular/forms";
import { distinctUntilChanged, first, map, skip } from "rxjs/operators";
import { concat } from "rxjs";

@Component({
  selector: 'app-color-picker',
  templateUrl: './color-picker.component.html',
  styleUrls: ['./color-picker.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ColorPickerComponent),
      multi: true
    }
  ]
})
export class ColorPickerComponent implements ControlValueAccessor {

  @Input()
  placeholder: string;

  @ViewChild('picker') picker;

  formData = this.fb.control("");

  private _OnTouched: () => void;

  constructor(private fb: FormBuilder) {
  }

  registerOnChange(fn: (_: string) => void): void {
    concat(this.formData.valueChanges.pipe(first()), this.picker.selected).pipe(
      distinctUntilChanged(),
      skip(1)
    ).subscribe(fn);
  }

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

  setDisabledState(isDisabled: boolean): void {
    if (isDisabled) {
      this.formData.disable();
    } else {
      this.formData.enable();
    }
  }

  writeValue(str: string): void {
    this.formData.setValue(str);
  }

}