Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
calendar component angular 4
<div class="calendar">
<div class="calendar-navs">
<div class="month-nav">
<button (click)="prevMonth()">&lt;</button>
<span class="p4">{{ currentDate.format('MMMM') }}</span>
<button (click)="nextMonth()">&gt;</button>
</div>
<div class="year-nav">
<button (click)="prevYear()">&lt;</button>
<span>{{ currentDate.format('YYYY') }}</span>
<button (click)="nextYear()">&gt;</button>
</div>
</div>
<div class="month-grid">
<div class="day-names">
<div *ngFor="let name of dayNames" class="day-name p9">
{{ name }}
</div>
</div>
<div class="weeks">
<div *ngFor="let week of weeks" class="week">
<ng-container *ngFor="let day of week">
<div class="week-date disabled" *ngIf="!isSelectedMonth(day.mDate)">
<span class="date-text">{{ day.mDate.date() }}</span>
</div>
<div class="week-date enabled"
*ngIf="isSelectedMonth(day.mDate)"
(click)="selectDate(day)"
[ngClass]="{ today: day.today, selected: day.selected }">
<span class="date-text">{{ day.mDate.date() }}</span>
</div>
</ng-container>
</div>
</div>
</div>
</div>
@import '../../styles/vars.scss';
@import '../../styles/typography.scss';
@import '../../styles/colors.scss';
$dayBase: 30px;
.calendar {
display: block;
width: $dayBase * 7;
margin: 0 auto;
* {
box-sizing: border-box;
}
.calendar-navs {
background-color: $cloud;
}
.month-nav {
padding: $base;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.year-nav {
padding: $base;
display: flex;
flex-direction: row;
justify-content: space-between;
font-family: 'Montserrat';
}
.month-grid {
.day-names {
display: flex;
flex-direction: row;
background: $concrete;
border-bottom-right-radius: 3px;
border-bottom-left-radius: 3px;
}
.weeks {
display: flex;
flex-direction: column;
}
.week {
display: flex;
flex-direction: row;
}
.week-date,
.day-name {
text-align: center;
padding: $base;
display: block;
width: $dayBase;
display: flex;
justify-content: center;
align-items: center;
}
.week-date {
height: $dayBase;
position: relative;
.date-text {
z-index: 10;
font-size: 10px;
font-family: 'Montserrat', sans-serif;
}
&::after {
content: '';
height: $dayBase * 0.9;
width: $dayBase * 0.9;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
transition: background-color 150ms linear, color 150ms linear;
z-index: 1;
}
&.enabled {
cursor: pointer;
&:hover {
&:after {
background-color: $seafoam;
}
}
}
&.selected {
color: $white;
&:after {
background-color: $teal;
}
&:hover {
&:after {
background-color: $teal;
}
}
}
&.disabled {
color: $light-blue-grey;
}
}
.today {
font-weight: bold;
}
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import * as moment from 'moment';
import { CalendarComponent, CalendarDate } from './calendar.component';
describe('CalendarComponent', () => {
let component: CalendarComponent;
let fixture: ComponentFixture<CalendarComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CalendarComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CalendarComponent);
component = fixture.componentInstance;
});
describe('Select date', () => {
it ('should emit date when selected', () => {
let selectedDate: CalendarDate = {
selected: false,
today: false,
inRange: false,
mDate: moment()
};
component.onSelectDate.subscribe(x => selectedDate = x);
component.selectDate(selectedDate);
const isSame = moment(selectedDate.mDate).isSame(moment(selectedDate.mDate), 'day');
expect(isSame).toBeTruthy();
});
});
describe('Calendar grid generation', () => {
it('should generate 6 weeks', () => {
component.generateCalendar();
fixture.detectChanges();
expect(component.weeks.length).toEqual(6);
});
it('should generate Feb 2017 correctly', () => {
component.currentDate = moment('2017-02-05');
component.generateCalendar();
fixture.detectChanges();
expect(component.weeks[0][0].mDate.date()).toEqual(29);
expect(component.weeks[5][6].mDate.date()).toEqual(11);
});
});
describe('Year navigation', () => {
it('should go forward 1 year', () => {
component.currentDate = moment('2017-09-10');
fixture.detectChanges();
component.nextYear();
fixture.detectChanges();
expect(component.currentDate.year()).toEqual(2018);
});
it('should go backward 1 year', () => {
component.currentDate = moment('2017-09-10');
fixture.detectChanges();
component.prevYear();
fixture.detectChanges();
expect(component.currentDate.year()).toEqual(2016);
});
});
describe('Month navigation', () => {
it('should go forward 1', () => {
component.currentDate = moment('2017-09-10');
fixture.detectChanges();
component.nextMonth();
fixture.detectChanges();
expect(component.currentDate.month()).toEqual(9);
});
it('should go backward 1', () => {
component.currentDate = moment('2017-09-10');
fixture.detectChanges();
component.prevMonth();
fixture.detectChanges();
expect(component.currentDate.month()).toEqual(7);
});
it('should go to january', () => {
component.currentDate = moment('2017-09-10');
fixture.detectChanges();
component.firstMonth();
fixture.detectChanges();
expect(component.currentDate.month()).toEqual(0);
});
it('should go to december', () => {
component.currentDate = moment('2017-09-10');
fixture.detectChanges();
component.lastMonth();
fixture.detectChanges();
expect(component.currentDate.month()).toEqual(11);
});
});
});
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import * as moment from 'moment';
import * as _ from 'lodash';
export interface CalendarDate {
mDate: moment.Moment;
selected?: boolean;
today?: boolean;
}
@Component({
selector: 'yoshimi-calendar',
templateUrl: './calendar.component.html',
})
export class CalendarComponent implements OnInit, OnChanges {
currentDate = moment();
dayNames = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
weeks: CalendarDate[][] = [];
sortedDates: CalendarDate[] = [];
@Input() selectedDates: CalendarDate[] = [];
@Output() onSelectDate = new EventEmitter<CalendarDate>();
constructor() {}
ngOnInit(): void {
this.generateCalendar();
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.selectedDates &&
changes.selectedDates.currentValue &&
changes.selectedDates.currentValue.length > 1) {
// sort on date changes for better performance when range checking
this.sortedDates = _.sortBy(changes.selectedDates.currentValue, (m: CalendarDate) => m.mDate.valueOf());
this.generateCalendar();
}
}
// date checkers
isToday(date: moment.Moment): boolean {
return moment().isSame(moment(date), 'day');
}
isSelected(date: moment.Moment): boolean {
return _.findIndex(this.selectedDates, (selectedDate) => {
return moment(date).isSame(selectedDate.mDate, 'day');
}) > -1;
}
isSelectedMonth(date: moment.Moment): boolean {
return moment(date).isSame(this.currentDate, 'month');
}
selectDate(date: CalendarDate): void {
this.onSelectDate.emit(date);
}
// actions from calendar
prevMonth(): void {
this.currentDate = moment(this.currentDate).subtract(1, 'months');
this.generateCalendar();
}
nextMonth(): void {
this.currentDate = moment(this.currentDate).add(1, 'months');
this.generateCalendar();
}
firstMonth(): void {
this.currentDate = moment(this.currentDate).startOf('year');
this.generateCalendar();
}
lastMonth(): void {
this.currentDate = moment(this.currentDate).endOf('year');
this.generateCalendar();
}
prevYear(): void {
this.currentDate = moment(this.currentDate).subtract(1, 'year');
this.generateCalendar();
}
nextYear(): void {
this.currentDate = moment(this.currentDate).add(1, 'year');
this.generateCalendar();
}
// generate the calendar grid
generateCalendar(): void {
const dates = this.fillDates(this.currentDate);
const weeks: CalendarDate[][] = [];
while (dates.length > 0) {
weeks.push(dates.splice(0, 7));
}
this.weeks = weeks;
}
fillDates(currentMoment: moment.Moment): CalendarDate[] {
const firstOfMonth = moment(currentMoment).startOf('month').day();
const firstDayOfGrid = moment(currentMoment).startOf('month').subtract(firstOfMonth, 'days');
const start = firstDayOfGrid.date();
return _.range(start, start + 42)
.map((date: number): CalendarDate => {
const d = moment(firstDayOfGrid).date(date);
return {
today: this.isToday(d),
selected: this.isSelected(d),
mDate: d,
};
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment