Calendar control validity state #1676

Closed
odedolive opened this Issue Dec 23, 2016 · 2 comments

Projects

None yet

3 participants

@odedolive
odedolive commented Dec 23, 2016 edited

Currently, when entering an invalid value into the control, the bound "value" is null, because it's not a valid date. (does not parse successfully)
The problem is that the invalid value is still visible to the user, which might be confusing.
This makes it impossible to hook in custom validation logic.
When we look at the value I don't know if the value is empty (to trigger the "required" validation) or if the value is invalid (when the control is not required in the form, but we want to prevent submission if the user entered invalid value)

One way of solving it might be to use the same logic that the autocomplete control has - expose a Date value if a valid date is selected or entered, or a string value otherwise.

[x] bug report => Search github for a similar issue or PR before submitting
[ ] feature request => Please check if request is not on the roadmap already https://github.com/primefaces/primeng/wiki/Roadmap
[ ] support request => Please do not submit support request here, instead see http://forum.primefaces.org/viewforum.php?f=35

Plunkr Case (Bug Reports)
Please fork the plunkr below and create a case demonstrating your bug report. Issues without a plunkr have much less possibility to be reviewed.

http://plnkr.co/edit/NtWWnN

Current behavior

Expected behavior

Minimal reproduction of the problem with instructions

What is the motivation / use case for changing the behavior?

Please tell us about your environment:

  • Angular version: 2.0.X
  • PrimeNG version: 2.0.X
  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
  • Language: [all | TypeScript X.X | ES6/7 | ES5]

  • Node (for AoT issues): node --version =

@ribizli
ribizli commented Dec 27, 2016

Check out our wrapper, which does support NG validation:

import { Component, forwardRef, ViewChild, ExistingProvider, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor, NG_VALIDATORS, AbstractControl, Validator } from '@angular/forms';
import { Calendar } from 'primeng/primeng';

const CUSTOM_CALENDAR_CONTROL_VALUE_ACCESSOR: ExistingProvider = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CalendarComponent),
  multi: true
};

const CALENDAR_VALIDATOR: ExistingProvider = {
  provide: NG_VALIDATORS,
  useExisting: forwardRef(() => CalendarComponent),
  multi: true
};

@Component({
  selector: 'pst-calendar',
  template: `<p-calendar #calendar [(ngModel)]="date"
      [disabled]="disabled"
      (onBlur)="onBlur($event)"></p-calendar>
  `,
  providers: [CUSTOM_CALENDAR_CONTROL_VALUE_ACCESSOR, CALENDAR_VALIDATOR]
})
export class CalendarComponent implements ControlValueAccessor, Validator, OnInit {

  constructor() { }

  _date: Date;
  get date() {
    return this._date;
  }
  set date(date: Date) {
    this._date = date;
    this.onChange(date);
  }

  @ViewChild(Calendar) private _calendar: Calendar;
  private _inputFieldValue: string;

  disabled: boolean;

  private onChange = (_) => { };
  private onTouched = () => { };

  ngOnInit() {
    if (this._calendar) {
      let origOnInput = this._calendar.onInput;
      this._calendar.onInput = (event) => {
        this._inputFieldValue = event.target.value;
        origOnInput.call(this._calendar, event);
      };
    }
  }

  validate(c: AbstractControl) {
    if (this._calendar && this._inputFieldValue && this.date === null) {
      return { invalidDate: true };
    }
  }
  onBlur(event) {
    this.onTouched();
  }

  /* ControlValueAccessor methods */
  writeValue(date: Date): void {
    this._date = date;
    if (!date) {
      this._calendar.inputFieldValue = null;
      this._inputFieldValue = null;
    }
  }

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

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

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

I created a pull request with the implementation of the NG_VALIDATORS within the calendar control itself.
Let's hope it gets approved.

@cagataycivici cagataycivici self-assigned this Jan 18, 2017
@cagataycivici cagataycivici added this to the 2.0 milestone Jan 18, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment