I
I
Ivan Stroykin2016-12-19 19:28:56
Angular
Ivan Stroykin, 2016-12-19 19:28:56

How to correctly pick up the value from the Datepicker directive?

Good day,
I'm interested in this question. There is a directive for Datepicker [saUidatepicker] which is embedded in input:

<input type="text" class="form-control datepicker" placeholder="Выберите дату" 
[saUiDatepicker]="{
    dateFormat: 'yy-mm-dd',
    defaultDate: '-7d'
    changesMonth: true,
    minRestrict: '#from'
}" (onChange)="change($event, 'dateFrom')">

In order to take the data from the Datepicker, I prescribe:
(onChange)="change($event, 'dateFrom')"
Can I somehow make the datepicker itself give the value to the input in which it is located?
The Datepicker directive itself:
import {Directive, ElementRef, OnInit, Input, EventEmitter} from '@angular/core';
import {Output} from "@angular/core/src/metadata/directives";

declare var $: any;

@Directive({
    selector: '[saUiDatepicker]'
})
export class UiDatepickerDirective implements OnInit {

    @Input() saUiDatepicker: any;
    @Output() onChange = new EventEmitter<number>();

    constructor(private el: ElementRef) {
    }

    ngOnInit() {
        let onSelectCallbacks = [];
        let saUiDatepicker = this.saUiDatepicker || {};
        let element = $(this.el.nativeElement);

        if (saUiDatepicker.minRestrict) {
            onSelectCallbacks.push((selectedDate)=> {
                $(saUiDatepicker.minRestrict).datepicker('option', 'minDate', selectedDate);
            });
        }
        if (saUiDatepicker.maxRestrict) {
            onSelectCallbacks.push((selectedDate)=> {
                $(saUiDatepicker.maxRestrict).datepicker('option', 'maxDate', selectedDate);
            });
        }

        //Let others know about changes to the data field
        onSelectCallbacks.push((selectedDate) => {
            element.triggerHandler("change");

            let form = element.closest('form');

            if (typeof form.bootstrapValidator == 'function') {
                try {
                    form.bootstrapValidator('revalidateField', element);
                } catch (e) {
                    console.log(e.message)
                }
            }
        });

        let options = $.extend(saUiDatepicker, {
            prevText: '<i class="fa fa-chevron-left"></i>',
            nextText: '<i class="fa fa-chevron-right"></i>',
            onSelect: (selectedDate) => {
                onSelectCallbacks.forEach((callback) => {
                    callback.call(callback, selectedDate)
                });
                this.onChange.emit(selectedDate);
            }
        });

        System.import('script!jquery-ui-npm/jquery-ui.min.js').then(() => {
            element.datepicker(options);
        });
    }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexey Zuev, 2016-12-20
@StivinKing

Usually such custom directives are made compatible with form tools - they are made custom form controls through the implementation of the ControlValueAccessor interface custom -
form-controls-in-angular-2 with Ang... Here is an example of how this can be implemented for the datepicker ( Plunker )

@Component({
  selector: 'saUiDatepicker',
  template: `<input type="text" #input class="form-control datepicker" placeholder="{{placeholder}}" [(ngModel)]="value" (blur)="onBlur()">`,
  providers: [CUSTOM_UI_DATEPICKER_CONTROL_VALUE_ACCESSOR]
})
export class UiDatepickerComponent implements OnInit, ControlValueAccessor {
  private innerValue: any = '';

  private onTouchedCallback: () => void = () => { };
  private onChangeCallback: (_: any) => void = () => { };

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

  set value(newValue: any) {
    if (newValue === this.innerValue) return;

    this.innerValue = newValue;
    this.onChangeCallback(newValue);
  }

  @Input() options: any;
  @Input() placeholder: any;

  @ViewChild('input') el: ElementRef;

  onBlur() {
    this.onTouchedCallback();
  }

  writeValue(value: any) {
    if (value !== this.innerValue) {
      this.innerValue = value;
    }
  }

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

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

  ngOnInit() {
    let options = $.extend(this.options || {}, {
      onSelect: (selectedDate) => {
        this.onChangeCallback(selectedDate);
      }
    });

    System.import('jquery-ui').then(() => {
      const datePicker = $(this.el.nativeElement).datepicker(options);
      if (this.value) {
        datePicker.datepicker("setDate", this.value);
      }
    });
  }
}

Usage in template-driven forms
<form #templateForm="ngForm" (ngSubmit)="submit(templateForm.value)">
  <saUiDatepicker name="data" [(ngModel)]="data" [options]="{...}" 
         placeholder="Выберите дату"></saUiDatepicker>    
  <button type="submit">Submit</button>
</form>

And reactive/model-driven forms
<form [formGroup]="reactiveForm">
   <saUiDatepicker formControlName="data" [options]="{...}" 
       placeholder="Выберите дату"></saUiDatepicker>  
    <pre>{{ reactiveForm.value | json }}</pre> 
</form>

constructor(private fb: FormBuilder) {}
  
ngOnInit() {
  this.reactiveForm = this.fb.group({
      data: ''
  });
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question