Calendar

The Ignite UI for Angular Calendar component is developed as a native Angular component. Use it to provide your application with three easy and intuitive ways to display date information. Users can select a single date, multiple dates or pick a range of dates.

Calendar Demo

Usage

To get started with the Ignite UI for Angular Calendar, let's first import the IgxCalendarModule in the application's AppModule, typically this is the app.module.ts file. Note that the IgxCalendar is also dependent on the BrowserAnimationsModule, so it needs to be added to the AppModule as well:

// app.module.ts
...
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { IgxCalendarModule } from 'igniteui-angular';
@NgModule({
    ...
    imports: [..., BrowserAnimationsModule, IgxCalendarModule],
    ...
})
export class AppModule {}

You will usually also import the IgxCalendarComponent in the AppComponent file (or your editor will auto-import them for you) when declaring types that are part of the calendar API:

import { IgxCalendarComponent } from 'igniteui-angular';
...

@ViewChild('calendar', { read: IgxCalendarComponent }) public calendar: IgxCalendarComponent;
Note

Note that the IgxCalendarComponent uses the Intl WebAPI for localization and formatting of dates. Consider using the appropriate polyfills if your target platform does not support them.

Selection

Instantiating the IgxCalendarComponent is as easy as placing its selector element in the template. This will display the current month in the calendar and use single selection mode. We switch to any of the other selection modes - multi and range, by setting the selection property:

<!-- app.component.html -->
<!-- Single selection mode -->
<igx-calendar></igx-calendar>
<!-- Multi selection mode -->
<igx-calendar selection="multi"></igx-calendar>
<!-- Range selection mode -->
<igx-calendar selection="range"></igx-calendar>

Notice that the calendar header is not rendered when the selection is either multi or range:

Localization and formatting

Due to their very nature, localization and formatting are essential to any calendar. In the IgxCalendarComponent those are controlled and customized through the following properties - locale, formatOptions, formatViews.
Let's go ahead and try those along with other customizations from the IgxCalendarComponent API. Say we are having visitors on our page coming from countries from EFTA (European Free Trade Association) countries, so we need to display the calendar in the corresponding culture. First thing we need to set is the weekstart, which controls the starting day of the week. It defaults to 0, which corresponds to Sunday, so we set a value of 1.

In the markup below we are also binding the formatOptions and formatViews properties to customize the display formatting. Finally we are binding the locale property to a value, based on the user's location choice:

<!-- app.component.html -->
<igx-calendar #calendar
    weekstart="1"
    [locale]="locale"
    [formatOptions]="formatOptions"
    [formatViews]="formatViews">
</igx-calendar>
<select id="locations" (change)="changeLocale($event)">...</select>

All property values are set in the AppCоmponent file:

// app.component.ts
@ViewChild('calendar', { read: IgxCalendarComponent }) public calendar: IgxCalendarComponent;

public formatOptions: any;
public formatViews: any;
public locale: string;
public select: HTMLSelectElement;

public ngOnInit() {
    this.select = document.getElementById("locations") as HTMLSelectElement;
    this.locale = this.select.value;
    this.formatOptions = { day: "2-digit", month: "long", weekday: "long", year: "numeric" };
    this.formatViews = { day: true, month: true, year: true };
}

// change the calendar locale
public changeLocale(event) {
    this.locale = event.target.value;
}

Great, we should now have a calendar with customized dates display that also changes the locale representation based on the user location. Let's have a look at it:

Events

Let's build on top of that sample a bit. We will require the user to enter a date range that does not exceed 5 days. We need to change the selection mode of the calendar to "range" and prompt the user to correct the selection, if the range is not valid. To do this we will use the onSelection event:

<!-- app.component.html -->
<igx-calendar #calendar
    ...
    selection="range"
    (onSelection)="verifyRange($event)">
</igx-calendar>

The value passed in the onSelection event is the collection of dates selected, so we can read its length to base our logic upon it. If we alert the user for the invalid selection, we also reset the selection to contain only the first date from the range using the selectDate method:

// app.component.ts
...
public verifyRange(dates: Date[]) {
    if (dates.length > 5) {
        this.calendar.selectDate(dates[0]);
        this.dialog.open();
    }
}

Let's try this out by playing around with selecting ranges:

Templating

We have seen how to make use of the IgxCalendarComponent API (properties, events, methods) so that we configure the calendar per our requirements and interact with it programmatically. Now we want to go further and customize its look, benefiting from the header and subheader templating capabilities.

To do that we need to decorate a ng-template inside the calendar with igxCalendarHeader or igxCalendarSubheader directive and use the context returned to customize the way the date is displayed. The template decorated with the igxCalendarHeader directive is rendered only when the calendar selection is set to single. The igxCalendarSubheader is available in all selection modes.

In our example we slightly modify the default template and will make the header display the full date and modify the subheader to include the weekday:

<!-- app.component.html-->
<igx-calendar>
    <!-- Modify the header to display the month (in titlecase), day and weekday -->
    <ng-template igxCalendarHeader let-parts>
        {{ parts.month.combined | titlecase }} {{parts.day.combined }} {{ parts.weekday.combined }}
    </ng-template>
    <ng-template igxCalendarSubheader let-parts>
        <span class="date__el" (click)="parts.monthView()">{{ parts.month.combined }}</span>
        <span class="date__el" (click)="parts.yearView()">{{ parts.year.combined }}</span>
    </ng-template>
</igx-calendar>
Note

Keep in mind that for Internet Explorer and Edge browsers the date parts will be empty strings, because neither implement the Intl API providing this functionality. (See formatToParts)

To support those browsers we are going to use alternative template using ngIf directive:

<!-- app.component.html-->
<igx-calendar #component locale="fr">
    <div *ngIf="formatParts; else parseTemplate">
        <ng-template igxCalendarHeader let-parts>
            {{ parts.month.combined | titlecase }} {{ parts.day.combined }} {{ parts.weekday.combined }}
        </ng-template>
        <ng-template igxCalendarSubheader let-parts>
            <span class="date__el" (click)="parts.monthView()">{{ parts.month.combined }}</span>
            <span class="date__el" (click)="parts.yearView()">{{ parts.year.combined }}</span>
        </ng-template>
    </div>

    <!-- Parse template for browsers not supporting Intl parts-->
    <ng-template #parseTemplate>
        <ng-template igxCalendarHeader let-parts>
            {{ getDatePart(parts, component, 'month') | titlecase }} {{ getDatePart(parts, component, 'day') }} {{ getDatePart(parts, component, 'weekday') }}
        </ng-template>
        <ng-template igxCalendarSubheader let-parts>
            <span class="date__el" (click)="parts.monthView()">{{ getDatePart(parts, component, 'month') }}</span>
            <span class="date__el" (click)="parts.yearView()">{{ getDatePart(parts, component, 'year') }}</span>
        </ng-template>
    </ng-template>
</igx-calendar>

Note that ngIf evaluates the value of the formatParts expression to control which template to use. Let's have a look at the alernative #parseTemplate template: the expressions in the curly brackets invokes the getDatePart method that returns the evaluated value, in our case this is a formatted date part (year, weekday, month, etc.). The parameters passed to the getDatePart are necessary so that formatting is based on the IgxCalendarComponent locale and format options:

// app.component.ts
public intlDateTimeFormat = new Intl.DateTimeFormat() as any;
public formatParts: boolean = this.intlDateTimeFormat.formatToParts;

public getDatePart(val: any, component: any, datePart: string) {
    const date = val.date as Date;
    const locale = component.locale;
    const formatOptions: Intl.DateTimeFormatOptions = {};
    formatOptions[datePart] = component.formatOptions[datePart];

    return date.toLocaleString(locale, formatOptions);

    // instead of toLocaleString we can use Intl.DateTimeFormat.format as well:
    // const partFormatter = new Intl.DateTimeFormat(locale, formatOptions);
    // return partFormatter.format(date);
}

Having implemented this conditional templating and date parsing we should get consistent formatting across all browsers, let's verify that:

Disabled dates

This section demonstrates the usage of disabledDates functionallity. Different single dates or range elements could be added to Array, and passed to the disabledDates descriptor.

this.calendar.disabledDates = [{ type: DateRangeType.Between, dateRange: [
    new Date(2018, 8, 2),
    new Date(2018, 8, 8)
])];

The DateRangeType is used to specify the range that is going to be disabled. For example, DateRangeType.Between will disable the dates between two specific dates in Array. Code snippet above. Check the API table below for all available DateRangeType values.

This feature is covering the situations when we may need to restrict some dates to be selectable and focusable.

Let's create a sample that is disabling dates within specific range of dates:

export class CalendarSample6Component {
    @ViewChild("calendar") public calendar: IgxCalendarComponent;
    public today = new Date(Date.now());
    public range = [
        new Date(this.today.getFullYear(), this.today.getMonth(), 3),
        new Date(this.today.getFullYear(), this.today.getMonth(), 8)
    ];

    public ngOnInit() {
        this.calendar.disabledDates = [{ type: DateRangeType.Specific, dateRange: this.range }];
    }
}

This is the result.

Special dates

Special dates feature is using almost the same configuration principles as Disabled dates. The difference here is dates styling and interaction. You are able to select and focus Special dates.

Lets add a Special dates to our igxCalendar, we are going to create a DateRangeDescriptor item of type DateRangeType.Specific and pass array of dates as dateRange:

export class CalendarSample7Component {
    @ViewChild("calendar") public calendar: IgxCalendarComponent;
    @ViewChild(IgxSnackbarComponent) public snackbar: IgxSnackbarComponent;
    public range = [];

    ...
    public selectPTOdays(dates: Date[]) {
        this.range = dates;
    }

    public submitPTOdays(eventArgs) {
        this.calendar.specialDates =
            [{ type: DateRangeType.Specific, dateRange: this.range)];

        this.range.forEach((item) => {
            this.calendar.selectDate(item);
        });

        ...
    }
}
<article class="sample-column calendar-wrapper">
    <span>Request Time Off</span>
    <igx-calendar #calendar
        selection="multi"
        (onSelection)="selectPTOdays($event)">
    </igx-calendar>
    <button igxButton="raised" (click)="submitPTOdays($event)">Submit Request</button>
</article>

We are going to use the selected dates array to define Special dates descriptor.

Result:

Views

There are separate views provided by the IgxCalendarModule that can be used independently:

Keyboard navigation

When the igxCalendar component is focused, use:

  • PageUp key to move to the previous month,
  • PageDown key to move to the next month,
  • Shift + PageUp keys to move to the previous year,
  • Shift + PageDown keys to move to the next year,
  • Home key to focus the first day of the current month that is into view,
  • End key to focus the last day of the current month that is into view,
  • Tab key to navigate through the subheader buttons;

When prev or next month buttons (in the subheader) are focused, use:

  • Space or Enter key to scroll into view the next or previous month.

When months button (in the subheader) is focused, use:

  • Space or Enter key to open the months view.

When year button (in the subheader) is focused, use:

  • Space or Enter key to open the decade view.

When a day inside the current month is focused, use:

  • Arrow keys to navigate through the days,
  • Arrow keys to navigate to previous/next month as well,
  • Enter key to select the currently focused day.

When a month inside the months view is focused, use:

  • Arrow keys to navigate through the months,
  • Home key to focus the first month inside the months view,
  • End key to focus the last month inside the months view,
  • Enter key to select the currently focused month and close the view.

When an year inside the decade view is focused, use:

  • Arrow keys to navigate through the years,
  • Enter key to select the currently focused year and close the view.

API References

Additional Resources

Our community is active and always welcoming to new ideas.

View page on GitHub