Skip to content

Instantly share code, notes, and snippets.

@lydemann
Last active January 31, 2023 07:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lydemann/7c53fd707f342b6979a26344859cb2bc to your computer and use it in GitHub Desktop.
Save lydemann/7c53fd707f342b6979a26344859cb2bc to your computer and use it in GitHub Desktop.
date-picker.component.ts
class DateErrorStateMatcher implements ErrorStateMatcher {
private hasError: boolean = undefined;
constructor(hasError$: Observable<boolean>, destroy$: Observable<void>) {
hasError$.pipe(takeUntil(destroy$)).subscribe(hasError => {
this.hasError = hasError;
});
}
public isErrorState(
control: FormControl,
form: NgForm | FormGroupDirective,
): boolean {
const isSubmitted = form && form.submitted;
const isFromDirtyAndSubmitted = !!(
control &&
control.invalid &&
(!form || isSubmitted) &&
(control.dirty || control.touched)
);
return this.hasError !== undefined
? this.hasError
: isFromDirtyAndSubmitted;
}
}
@Component({
selector: 'app-date-picker',
templateUrl: './date-picker.component.html',
styleUrls: ['./date-picker.component.scss'],
})
export class DatePickerComponent
implements ControlValueAccessor, OnDestroy, AfterViewInit {
@Input()
public set showError(v: boolean) {
this._showErrorSubject.next(v);
}
private _date: Date;
@Input()
public set date(date: Date) {
const hasChanged = this.setInnerValue(date);
if(hasChanged) {
this.onChange(date);
this.onTouched();
this.dateChange.next(date);
}
}
public get date(): Date {
return this._date;
}
// sets inner value and returns if it has changed
private setInnerValue(date: Date): boolean {
if(date !== this.date) {
this._date = date;
}
}
@Input() public minDate: Date;
@Input() public maxDate: Date;
@Input() public errorMessage: string = 'Invalid input';
@Input() public placeholder: string = 'Choose a date';
public dateChange: EventEmitter<Date> = new EventEmitter();
public isDisabled = false;
// used to display mat error
public formControl = new FormControl('');
private destroy$ = new Subject<void>();
private _showErrorSubject = new BehaviorSubject<boolean>(undefined);
private _showError$: Observable<
boolean
> = this._showErrorSubject.asObservable();
// tslint:disable-next-line: member-ordering
public dateErrorStateMatcher = new DateErrorStateMatcher(
this._showError$,
this.destroy$.asObservable(),
);
private onTouched = Function;
constructor(public ngControl: NgControl) {
ngControl.valueAccessor = this;
}
public ngAfterViewInit(): void {
// syncing with validators on host element
this.formControl = this.ngControl.control as FormControl;
}
public ngOnDestroy(): void {
this.destroy$.next();
}
public onDateChange(dateInput: MatDatepickerInputEvent<Date>) {
const date = dateInput.value;
}
public writeValue(date: Date): void {
this.setInnerValue(date);
}
public registerOnChange(fn: any): void {
this.onChange = fn;
}
public registerOnTouched(fn: any): void {
this.onTouched = fn;
}
public setDisabledState?(isDisabled: boolean): void {
this.isDisabled = isDisabled;
}
// tslint:disable-next-line: no-empty
private onChange = (date: Date) => {};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment