Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 Directive implementing ControlValueAccessor doesn't update 'touched' property on change

I'm trying to create my own Angular 2 Directive for Jquery UI Datepicker. I've seen some different approaches on the internet and in SO as well, but no one achieves the goal that I want to. So this is the code that I have so far:

import {Directive, ElementRef, Input, forwardRef} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";

declare  var $:any;

@Directive({
  selector: '[date-picker]',
  providers: [{
    provide: NG_VALUE_ACCESSOR,useExisting:
      forwardRef(() => DatePickerDirective),
    multi: true
  }]
})
export class DatePickerDirective implements ControlValueAccessor {
  private value: string;

  @Input('changeMonth') changeMonth:boolean = true;
  @Input('changeYear') changeYear:boolean = true;

  constructor(private el: ElementRef) {

  }

  ngAfterViewInit(){
    $(this.el.nativeElement).datepicker({
      changeMonth: this.changeMonth,
      yearRange: "1:100",
      changeYear: this.changeYear
    }).on('change', e => this.onChange(e.target.value));
  }

  onChange: Function = () => {};

  onTouched: Function = () => {};

  writeValue(val: string) : void {
    this.value = val;
  }

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

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

What is happening is that even when I select a date (picker) or type it directly on input field, it isn't updating "touched" property.

Do you have any ideas for fixing it?

like image 231
Pasp Ruby Avatar asked Nov 19 '16 15:11

Pasp Ruby


1 Answers

For those who eventually have the same problem, I figured out a way to manage it, as you can below:

import {Directive, ElementRef, Input, forwardRef} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";

declare  var $:any;

export const CUSTOM_INPUT_DATE_PICKER_CONTROL_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => DatePickerDirective),
  multi: true
};

@Directive({
  selector: '[date-picker]',
  host: {'(blur)': 'onTouched($event)'},
  providers: [CUSTOM_INPUT_DATE_PICKER_CONTROL_VALUE_ACCESSOR]
})
export class DatePickerDirective implements ControlValueAccessor {
  private innerValue: string;

  @Input('changeMonth') changeMonth:boolean = true;
  @Input('changeYear') changeYear:boolean = true;

  constructor(private el: ElementRef) {
    $(this.el.nativeElement).datepicker({
      changeMonth: true,
      changeYear: true,
      dateFormat: 'dd/mm/yy'
    }).on('change', e => this.onChange(e.target.value));
  }

  public onChange: any = (_) => { /*Empty*/ }
  public onTouched: any = () => { /*Empty*/ }

  get value(): any {
    return this.innerValue;
  };

  //set accessor including call the onchange callback
  set value(v: any) {
    if (v !== this.innerValue) {
      this.innerValue = v;
      this.onChange(v);
    }
  }

  writeValue(val: string) : void {
    this.innerValue = val;
  }

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

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
}
like image 162
Pasp Ruby Avatar answered Nov 16 '22 01:11

Pasp Ruby