Alexandr Semenets
Alexandr Semenets

Reputation: 59

How i can use mdbootstrap in Angular 2?

In my task i use http://mdbootstrap.com/javascript/date-picker How I can use date-picker in angular 2 component, i must add this code in jquery to typescript component $('.datepicker').pickadate(); in my component.

my_component.ts

import { Component, OnInit, ElementRef } from '@angular/core';
declare var $: any;

@Component({
// selector: 'clients',
templateUrl: './src/client/app/views/clients.html',
})
export class ClientsModel implements OnInit {
constructor(private _elmRef: ElementRef) {}
/* this code not work*/
ngOnInit() {
    $(this._elmRef.nativeElement)
        .find('#date-picker-example')
        .on('click', function(){
            $('#date-picker-example').pickadate();
        });
}
}

my_component.html

<div class="md-form col-xl-2 col-lg-3 col-md-4 col-sm-6 col-xs-12" style="margin-top: 1%;">
     <input type="text" id="date-picker-example" class="form-control datepicker">
     <label for="date-picker-example">Date begin</label>
</div>

Upvotes: 2

Views: 1487

Answers (2)

Jared Phelps
Jared Phelps

Reputation: 473

I don't think you can get around using jQuery if you want to use the MDB datepicker. I wrote a wrapper around it for my own project, hopefully it's helpful to you as well. I based it off this article that shows you how to make your own custom component that works with [(ngModel)]. I also had the requirement to have the date saved in a format that was different from the date displayed, which added some complexity you may not have to deal with.

It's important to note that the MDB datepicker uses pickadate.js internally, so you have that entire API available as well.

import { Component, forwardRef, ViewChild, ElementRef, Input, OnChanges, SimpleChanges } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';

const noop = () => {
};

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

// Wrapper component for MDB's date picker, which is in turn a wrapper for pickadate.js.
// Uses the approach outlined here: http://almerosteyn.com/2016/04/linkup-custom-control-to-ngcontrol-ngmodel
@Component({
  selector: 'date-picker',
  template: `<input #element class="form-control" [attr.data-value]="value">`,
  providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class DatePickerComponent implements ControlValueAccessor, OnChanges {

  // we need the native element here because we have to call the .pickadate() function on our element.
  @ViewChild('element') element: ElementRef;

  //The string representation of the currently selected date in the yyyy-mm-dd format.
  private innerValue: any = '';

  // A js date object representing the currently selected date.
  private innerValueDate: Date = null;

  // The format that actually gets displayed to the user, but not bound to anything directly.
  private dateFormat: string = 'd mmm yyyy';

  // The jquery object that is our api to pickadate.js.
  private pickerObject: any;

  //Placeholders for the callbacks which are later provided by the Control Value Accessor
  private onTouchedCallback: () => void = noop;
  private onChangeCallback: (_: any) => void = noop;

  // Minimum date the user can select
  @Input() minDate: Date;

  // If true and date is null, valid will return false, invalid will return true.
  @Input() required: boolean;

  // True after the user has opened and closed the date picker.  No way to reset it currently.
  public touched: boolean;

  //get accessor used in the template.
  get value(): string {
    return this.innerValue;
  };

  ngOnInit() {
    // Wire up the pickadate plugin to our native element.
    let element: any = $(this.element.nativeElement);

    let $pickerInput = element.pickadate({
      format: this.dateFormat,
      // If you are using non-standard formats when setting the value, pickadate requires that you pass in
      // formatSubmit tells the plugin how to parse them.
      formatSubmit: 'yyyy-MM-dd',
      onSet: context => {
        // For ngModel to work we need to let angular know this control has been touched.
        this.touched = true;
        this.onTouchedCallback();

        // Parse the date and set our internal tracking values.
        this.setValue(context.select);

        // Let angular know our value has changed.
        this.onChangeCallback(this.innerValue);
      },
      onClose: () => {
        this.touched = true;
        this.onTouchedCallback();

        // hack to get around this MDB date picker bug:  https://github.com/amsul/pickadate.js/issues/160
        $(document.activeElement).blur();
      }
    });

    // Keep track of the picker object we just created so we can call its apis later.
    this.pickerObject = $pickerInput.pickadate('picker');
    this.pickerObject.set('min', this.minDate);
  }

  // Properties to give this some of the same behavior/interface as a native control.
  get valid(): boolean {
    return this.required ? !!this.value : true;
  }

  get invalid(): boolean {
    return !this.valid;
  }

  get errors(): any {
    return this.valid ? null : { required: true };
  }

  // Used if you want to show the date picker programatically.
  public showDatePicker($event) {
    this.pickerObject.open();

    // If you don't stopPropagation() on this event, the picker doesn't open.
    // https://github.com/amsul/pickadate.js/issues/481
    if ($event) {
      $event.stopPropagation();
    }
  }

  // writeValue, registerOnChange, and registerOnTouched are from ControlValueAccessor interface
  writeValue(value: any) {
    this.setValue(value);
    this.pickerObject.set('select', this.innerValueDate);
  }

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

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

  // Get notified when minDate changes so we can tell the pickadate plugin to respond accordingly.
  ngOnChanges(changes: SimpleChanges): void {
    // this actually gets called before ngOnInit, so the pickerObject may not be there yet.
    if (this.pickerObject && changes['minDate']) {
      this.pickerObject.set('min', this.minDate);
    }
  }

  // ***** Helper functions ******//
  // Parse and test the new value, but don't notify angular or anything in here.
  private setValue(value) {
    if (!value) {
      this.innerValue = '';
      this.innerValueDate = null;
    } else {
      let newValueDate: Date = new Date(Date.parse(value));
      if (!this.datesAreEqual(this.innerValueDate, newValueDate)) {
        this.innerValue = this.formatDate(newValueDate);
        this.innerValueDate = newValueDate;
      }
    }
  }

  // Compare two dates' values to see if they are equal.
  datesAreEqual(v1: Date, v2: Date) {
    if (v1 === null && v2 === null) {
      return true;
    } else if (!v1 || !v2) {
      return false;
    }
    return v1.getTime() === v2.getTime();
  }

  // There are lots more robust ways of formatting dates but since this is just an internal representation,
  // we can just do something simple and convert the date to yyyy-mm-dd.
  formatDate(d: Date) {
    if (d === null) {
      return null;
    }
    return d.getFullYear() + '-' + ('0'+(d.getMonth()+1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2);
  }
}

Upvotes: 0

anshuVersatile
anshuVersatile

Reputation: 2068

Avoid using jQuery while with angular cause it has it's own architecture for selectors. When it is essential then ok so answer to your question is like you can do

<input type="text" id="date-picker-example" class="form-control datepicker" (click)="dPicker($event)">

and in your component

dPicker(e)
{
            $(e.target).pickadate();
}

Upvotes: 1

Related Questions