ayyappa maddi
ayyappa maddi

Reputation: 961

JQuery UI Datepicker in angular2


I am new to Angular2.
I am trying to implement JQuery ui datepicker in angular2.

I have written a datePicker directive, there i enabled datepicker. Here i am able to select date but finding difficulty to emit selected date to the parent component.

to overcome this i created an object on window object and passing component reference to that object. from there i am calling component function.

I feel this is not a best practice to do.

Can someone help me to do in right way.

import { Directive, ElementRef, Input, NgZone,HostListener,Output,EventEmitter } from '@angular/core';
    declare  var $:any;
    @Directive({
      selector: '[uiDatePicker]',
     })
    export class UiDatePickerDirective {
      @Input('uiDatePicker') setDate: string;
      @Output() onSelectDate = new EventEmitter();  
      private el: HTMLElement;
      constructor(el: ElementRef,public zone:NgZone) {
        this.el = el.nativeElement;

        window.angularComponentRef = {
          zone: this.zone, 
          component: this
        };
      }

      doEmitDate(dateText:string){
          this.onSelectDate.emit(dateText);
      }
      ngOnInit() {
        $(this.el).datepicker({
         onSelect: function(dateText:string) {
            window.angularComponentRef.component.doEmitDate(dateText);
         }
        });
       }
}

Here i dont like to use window.angularComponentRef.component object. As it is just storing the reference in global object. this is not good for an application.

Upvotes: 1

Views: 5097

Answers (2)

kravits88
kravits88

Reputation: 13049

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(() => UiDatePickerDirective),
    multi: true
};

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

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

    constructor(private el: ElementRef) {
    }

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


    public onChange: any = (_: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;
        $(this.el.nativeElement).datepicker("setDate", this.innerValue);
    }

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

    registerOnTouched(fn: any): void {
        this.onTouched = fn;
    }
}
<input type="text" uiDatePicker [(ngModel)]="note.ValidTo"/>

This is a modified version from here.

Upvotes: 2

hotforfeature
hotforfeature

Reputation: 2588

For all intents and purposes, you can use the var self = this ideology and closures to maintain a reference to the component.

If you aren't doing any pre-processing in the onSelect callback, you can further simplify things by passing a bound doEmitDate function as the onSelect handler.

import { Directive, ElementRef, Input, NgZone,HostListener,Output,EventEmitter } from '@angular/core';
declare  var $:any;

@Directive({
  selector: '[uiDatePicker]',
})
export class UiDatePickerDirective {
  @Input('uiDatePicker') setDate: string;
  @Output() onSelectDate = new EventEmitter();
  private el: HTMLElement;

  constructor(el: ElementRef, public zone: NgZone) {
    this.el = el.nativeElement;
  }

  doEmitDate(dateText:string){
    this.onSelectDate.emit(dateText);
  }

  ngOnInit() {
    const component = this;
    $(this.el).datepicker({
      onSelect: function(dateText: string) {
        component.doEmitDate(dateText);
      }
    });

    // Or if you're not doing anything else in the onSelect callback
    $(this.el).datepicker({
      onSelect: this.doEmitDate.bind(this)
    });
  }
}

Upvotes: 1

Related Questions