Skip to content

Instantly share code, notes, and snippets.

@er-ant
Created November 1, 2017 05:46
Show Gist options
  • Save er-ant/fcdfcae92e048f1c78bd13d59e1a9d9a to your computer and use it in GitHub Desktop.
Save er-ant/fcdfcae92e048f1c78bd13d59e1a9d9a to your computer and use it in GitHub Desktop.
Component code example
import {
Component, forwardRef, Input, Output, EventEmitter, ElementRef,
trigger, state, animate, transition, style, keyframes
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { IWeekDay, WEEKDAYS, IMonth, MONTHS } from './datepicker.fixture';
interface IDate {
dayWeekNumber?: number;
day?: number;
month?: number;
year?: number;
}
/**
* @whatItDoes Flexible datepicker.
*
* @input showCalendar Manage displaying of calendar.
* @input weeks Enable weeks in the calendar. Disabled by default.
*
* If you call this datepicker by any action, add id 'calendarTrigger'
* to a wrapper.
*
* @example
* <app-datepicker [(ngModel)]="campaign.annualReportDate" [weeks]="true">
* </app-datepicker>
*/
@Component({
selector: 'app-datepicker',
templateUrl: './datepicker.component.html',
styleUrls: ['./datepicker.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatepickerComponent),
multi: true
}
],
animations: [
trigger('calendarAnimation', [
transition('* => left', [
animate(180, keyframes([
style({ transform: 'translateX(105%)', offset: 0.5 }),
style({ transform: 'translateX(-130%)', offset: 0.51 }),
style({ transform: 'translateX(0)', offset: 1 })
]))
]),
transition('* => right', [
animate(180, keyframes([
style({ transform: 'translateX(-105%)', offset: 0.5 }),
style({ transform: 'translateX(130%)', offset: 0.51 }),
style({ transform: 'translateX(0)', offset: 1 })
]))
])
])
],
})
export class DatepickerComponent implements ControlValueAccessor {
public readonly months: Array<IMonth> = MONTHS;
private _propagateChange: any = () => null;
public weekDays: Array<IWeekDay> = WEEKDAYS;
public templateMonth: number = 1;
public templateYear: number = 2017;
public showCalendar: boolean;
public choosenDate: IDate = <IDate> {};
public calendarData: Array<IDate[]>;
public animate: string;
@Input()
public weeks: boolean = false;
@Input()
public set openCalendar(value: boolean) {
if (this.showCalendar !== value) {
this.showCalendar = value;
if (!this.showCalendar) {
window
.document
.removeEventListener('click', this.closeDatepickerListener.bind(this),
true);
} else {
window
.document
.addEventListener('click', this.closeDatepickerListener.bind(this),
true);
}
}
}
@Output()
public closeDatepicker: EventEmitter<boolean> = new EventEmitter();
public writeValue(value: string) {
if (value) {
let incomingDate = new Date(value);
this.choosenDate = {
day: incomingDate.getDate(),
month: incomingDate.getMonth() + 1,
year: incomingDate.getFullYear()
}
this.templateMonth = this.choosenDate.month;
this.templateYear = this.choosenDate.year;
this.calendarData = this.buildMonth();
} else {
let today = new Date();
this.templateYear = today.getFullYear();
this.calendarData = this.buildMonth();
}
}
public registerOnChange(fn: Function) {
this._propagateChange = fn;
}
public registerOnTouched() { }
constructor(private _ref: ElementRef) {
this.setToday();
}
private prepareRowArray(row: Array<IDate>): void {
let firstDay = new Date(this.templateYear, this.templateMonth - 1, 1);
if (firstDay.getDay() !== 0) {
for (let i = -firstDay.getDay() + 1; i <= 0; i++) {
let date = new Date(this.templateYear, this.templateMonth - 1, i);
row.push({
day: date.getDate(),
month: date.getMonth() + 1,
year: date.getFullYear()
})
}
}
}
private closeDatepickerListener(event): void {
let datepickerWrapper = window.document.getElementById('calendarTrigger');
if (!this._ref.nativeElement.contains(event.target)) {
if (datepickerWrapper &&
datepickerWrapper !== event.target &&
!datepickerWrapper.contains(event.target)) {
this.closeDatepicker.emit(true);
}
}
}
private finishRowArray(row: Array<IDate>): void {
let lastMonthDayWeek = new Date(this.templateYear, this.templateMonth, 0).getDay();
if (lastMonthDayWeek !== 6) {
for (let i = lastMonthDayWeek, j = 1; i < 6; i++, j++) {
let date = new Date(this.templateYear, this.templateMonth, j);
row.push({
day: date.getDate(),
month: date.getMonth() + 1,
year: date.getFullYear()
})
}
}
}
private triggerAnimation(direction: string): void {
this.animate = direction;
setTimeout(() => this.animate = 'reset', 185);
}
public setToday(): void {
let today = new Date();
this.selectDay({
day: today.getDate(),
month: today.getMonth() + 1,
year: today.getFullYear()
})
this.templateMonth = this.choosenDate.month;
this.templateYear = this.choosenDate.year;
this.calendarData = this.buildMonth();
}
public dateToString(date: IDate): string {
return (`${date.year}-${date.month}-${date.day}`);
}
public buildMonth(): Array<IDate[]> {
let rowNumber = 0;
let monthTemplate: Array<IDate[]> = [[]];
let lastMonthDay = new Date(this.templateYear, this.templateMonth, 0).getDate();
this.prepareRowArray(monthTemplate[rowNumber]);
for (let i = 1; i <= lastMonthDay; i++) {
monthTemplate[rowNumber].push({day: i, month: this.templateMonth,
year: this.templateYear});
if (monthTemplate[rowNumber].length % 7 === 0) {
rowNumber++;
monthTemplate[rowNumber] = [];
}
}
this.finishRowArray(monthTemplate[rowNumber]);
return monthTemplate;
}
public monthTitle(): string {
return this.months.find(item => item.number === this.templateMonth).title;
}
public selectDay(day: IDate): void {
if (this.templateMonth !== day.month) {
this.templateMonth = day.month;
this.templateYear = day.year;
this.calendarData = this.buildMonth();
} else {
this.closeDatepicker.emit(true);
}
this.choosenDate = day;
this._propagateChange(this.dateToString(this.choosenDate));
}
public prevMonth(): void {
this.templateMonth--;
if (this.templateMonth < 1) {
this.templateMonth = 1;
} else {
this.triggerAnimation('left');
}
this.calendarData = this.buildMonth();
}
public nextMonth(): void {
this.templateMonth++;
if (this.templateMonth > 12) {
this.templateMonth = 12;
} else {
this.triggerAnimation('right');
}
this.calendarData = this.buildMonth();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment