Overview

  • How to detect the current device orientation (portrait or landscape).

  • Watch for device rotation and update the Angular Calendar view to display the appropriate view.

  • This project defines three views: full-width landscape mode for desktop devices, mini landscape mode that displays three days and a horizontal scrollbar and a portrait mode that displays a daily calendar.

  • For an introduction to using the Angular calendar component, please see the Angular Appointment Calendar Component (TypeScript + PHP/MySQL) tutorial.

  • Includes a trial version of DayPilot Pro for JavaScript (see License below).

License

Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript. Buy a license.

How to get the current device orientation

To get the current orientation, you can use the following media query string and check if the document matches using window.matchMedia() method:

const landscape = window.matchMedia("(orientation: landscape)").matches;

How to detect device rotation

It is possible to to watch changes of the media query match using an onchange event listener.

The addEventListener() method is available in all modern browsers. Safari supports it since version 14 - in older versions you’ll need to use the addListener() method.

@Component({
  selector: 'calendar-component',
  template: `<daypilot-calendar [config]="config" [events]="events" #calendar></daypilot-calendar>`,
  styles: [``]
})
export class CalendarComponent implements AfterViewInit {

  landscape = window.matchMedia("(orientation: landscape)");

  constructor(private ds: DataService) {
    this.landscape.addEventListener("change", ev => {
      console.log("landscape orientation", this.landscape.matches);
    });
  }
  
  // ...

}

How to switch the Angular Calendar view on device rotation

We will define three Angular calendar views.

1. Full-width landscape view. This view will be used for desktop devices and tablets.

viewFull(): void {
  this.config.columnWidthSpec = "Auto";
  this.config.viewType = "Week";
}

2. Small landscape view. This view will display one week but it uses custom column width so that three days will be visible in the viewport:

viewLandscape(): void {
  const w = window.innerWidth - (this.calendar.control.hourWidth || 0);

  this.config.columnWidthSpec = "Fixed";
  this.config.columnWidth = w / 3;
  this.config.viewType = "Week";
}

3. Portrait view. The portrait mode will display one day.

viewPortrait(): void {
  this.config.columnWidthSpec = "Auto";
  this.config.viewType = "Day";
}

When deciding which view to use, we will also need to check the device width. We will use the small landscape view for devices with up to 800 pixels:

smallWidth =  window.matchMedia("(max-width: 800px)");

The view-switching logic now looks like this:

viewUpdate(): void {
  const isLandscape = this.landscape.matches;
  const isSmall = this.smallWidth.matches;

  if (isLandscape) {
    if (isSmall) {
      this.viewLandscape();
    }
    else {
      this.viewFull();
    }
  }
  else {
    this.viewPortrait();
  }
}

Here is the source code of the Angular calendar with the complete device rotation detection logic:

import {Component, ViewChild, AfterViewInit} from "@angular/core";
import {DayPilot, DayPilotCalendarComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";

@Component({
  selector: 'calendar-component',
  template: `<daypilot-calendar [config]="config" [events]="events" #calendar></daypilot-calendar>`,
  styles: [``]
})
export class CalendarComponent implements AfterViewInit {

  @ViewChild("calendar")
  calendar!: DayPilotCalendarComponent;

  landscape = window.matchMedia("(orientation: landscape)");
  smallWidth =  window.matchMedia("(max-width: 800px)");

  config: DayPilot.CalendarConfig = {
    viewType: "Week",
    // ...
  };

  constructor(private ds: DataService) {
    this.landscape.addEventListener("change", ev => {
      this.viewUpdate();
    });
  }

  viewUpdate(): void {
    const isLandscape = this.landscape.matches;
    const isSmall = this.smallWidth.matches;

    if (isLandscape) {
      if (isSmall) {
        this.viewLandscape();
      }
      else {
        this.viewFull();
      }
    }
    else {
      this.viewPortrait();
    }
  }

  viewLandscape(): void {
    const w = window.innerWidth - (this.calendar.control.hourWidth || 0);

    this.config.columnWidthSpec = "Fixed";
    this.config.columnWidth = w / 3;
    this.config.viewType = "Week";
  }

  viewPortrait(): void {
    this.config.columnWidthSpec = "Auto";
    this.config.viewType = "Day";
  }

  viewFull(): void {
    this.config.columnWidthSpec = "Auto";
    this.config.viewType = "Week";
  }

  ngAfterViewInit(): void {
    this.viewUpdate();

    // ...
  }

}