Outlook Calendar Sync

The event calendar comes with third party calendar integration support through the integration plugin. This needs to be added to the download package or installed separately from a dedicated NPM package.

It includes everything you need to authenticate your users, get their Outlook calendars and provides functions for CRUD operations. It takes care of loading the events and converts them to the required format so that they can be displayed on the Mobiscroll calendar separately or mixed with other calendars and events.

Customizing the interaction, event workflows, whether the events are read-only is up to you. In this live demo, the different calendars are handled as resources and have their own timeline rows. You can manipulate events in the desired calendars, while read-only calendars are greyed out.

This example uses the integration plugin to connect to and load events from Outlook Calendars and it is not available in the trial. Give the live demo a try and see how it can be configured.
Get started with the timeline

Demo

Loading the live demo

Preview in full screen

Display Outlook Calendar events on a Timeline — each calendar as a separate resource row.

Code

mobiscroll.setOptions({
  locale:  ,
  theme: ' ',
  themeVariant: ' '
});

var outlookCalendarSync = mobiscroll.outlookCalendarSync;

var calendarElm = document.getElementById('demo-sync-events-outlook-calendar');
var popupElm = document.getElementById('demo-sync-events-outlook-calendar-popup');
var editButton = document.getElementById('demo-outlook-cal-edit');

var startDate;
var endDate;
var calendarIds = [];
var events = [];
var readonlyCals = [];
var debounce;
var calendarData = {};
var myResources = [];

function toggleContainers(loggedIn) {
  var loggedOutCont = document.getElementById('outlook-cal-sign-in');
  var loggedInCont = document.getElementById('outlook-cal-get-calendars');

  if (loggedIn) {
    loggedOutCont.style.display = 'none';
    loggedInCont.style.display = 'block';
  } else {
    loggedInCont.style.display = 'none';
    loggedOutCont.style.display = 'block';
  }
}

function loadEvents(checked, calendarId) {
  if (checked) {
    loadingEvents(true);
    calendarIds.push(calendarId);
    outlookCalendarSync
      .getEvents([calendarId], startDate, endDate)
      .then(function (resp) {
        var newResource = calendarData[calendarId];
        var newResources = myResources.slice();
        newResources.push({ id: calendarId, name: newResource.name, color: newResource.color });
        myResources = newResources;
        loadingEvents(false);
        resp.forEach(function (event) {
          event.resource = event.outlookCalendarId;
        });
        events = events.concat(resp);
        inst.setOptions({ resources: newResources, data: events });
      })
      .catch(onError);
  } else {
    var index = calendarIds.indexOf(calendarId);
    var newResources = myResources.slice();
    newResources = newResources.filter(function (c) {
      return c.id !== calendarId;
    });
    myResources = newResources;
    if (index !== -1) {
      calendarIds.splice(index, 1);
    }
    events = events.filter(function (event) {
      return event.outlookCalendarId !== calendarId;
    });
    inst.setOptions({ resources: newResources, data: events });
  }
}

function loadingEvents(show) {
  if (show) {
    calendarElm.classList.add('md-loading-events');
  } else {
    calendarElm.classList.remove('md-loading-events');
  }
}

function onError(resp) {
  mobiscroll.toast({
    message: resp.message,
  });
}

function onSignedIn() {
  toggleContainers(true);

  outlookCalendarSync
    .getCalendars()
    .then(function (calendars) {
      var calList = '';

      calendars.sort(function (c) {
        return c.isDefaultCalendar ? -1 : 1;
      });

      for (var i = 0; i < calendars.length; ++i) {
        var c = calendars[i];
        calList +=
          '<label>' +
          '<input mbsc-switch value="' +
          c.id +
          '" data-label="' +
          c.name +
          '" type="checkbox" class="outlook-calendar-switch" checked />' +
          '</label>';

        calendarIds.push(c.id);
        myResources.push({ id: c.id, name: c.name, color: c.hexColor });
        calendarData[c.id] = { name: c.name, color: c.hexColor };

        if (!c.canEdit) {
          readonlyCals.push(c.id);
        }
      }

      inst.setOptions({
        resources: myResources,
        invalid: [
          {
            recurring: {
              repeat: 'daily',
            },
            resource: readonlyCals,
          },
        ],
      });

      var calendarList = document.getElementById('outlook-cal-list');
      calendarList.innerHTML = calList;

      loadingEvents(true);

      outlookCalendarSync
        .getEvents(calendarIds, startDate, endDate)
        .then(function (resp) {
          loadingEvents(false);
          resp.forEach(function (event) {
            event.resource = event.outlookCalendarId;
          });
          events = resp;
          inst.setEvents(events);
        })
        .catch(onError);

      mobiscroll.enhance(calendarList);
    })
    .catch(onError);
}

function onSignedOut() {
  toggleContainers(false);
  popup.close();
  calendarIds = [];
  calendarData = [];
  events = [];
  readonlyCals = [];
  myResources = [];
  inst.setOptions({ resources: undefined, invalid: undefined, data: [] });
}

var inst = mobiscroll.eventcalendar('#demo-sync-events-outlook-calendar', {
  view: {
    timeline: {
      type: 'week',
      eventDisplay: 'fill',
    },
  },
  exclusiveEndDates: true,
  clickToCreate: false,
  dragToCreate: false,
  dragToMove: false,
  dragToResize: false,
  renderHeader: function () {
    return (
      '<div mbsc-calendar-nav class="md-sync-events-outlook-nav"></div>' +
      '<div class="md-spinner">' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '<div class="md-spinner-blade"></div>' +
      '</div>' +
      '<div class="md-outlook-calendar-buttons">' +
      '<button mbsc-button id="outlook-cal-sign-in" class="md-sync-events-outlook-button">Sync my outlook calendars</button>' +
      '<button mbsc-button id="outlook-cal-get-calendars" style="display:none" class="md-sync-events-outlook-button">My Calendars</button>' +
      '<button mbsc-button id="outlook-cal-today">Today</button></div>' +
      '<button mbsc-calendar-prev></button>' +
      '<button mbsc-calendar-next></button>' +
      '</div>'
    );
  },
  onPageLoading: function (args) {
    startDate = args.viewStart;
    endDate = args.viewEnd;
    clearTimeout(debounce);
    debounce = setTimeout(function () {
      if (outlookCalendarSync.isSignedIn()) {
        loadingEvents(true);
        outlookCalendarSync
          .getEvents(calendarIds, startDate, endDate)
          .then(function (resp) {
            loadingEvents(false);
            resp.forEach(function (event) {
              event.resource = event.outlookCalendarId;
            });
            events = resp;
            inst.setEvents(events);
          })
          .catch(onError);
      }
    }, 200);
  },
  onEventCreate: function (args) {
    if (outlookCalendarSync.isSignedIn()) {
      var event = args.event;
      var calendarId = event.resource;
      if (readonlyCals.indexOf(calendarId) !== -1) {
        mobiscroll.toast({
          message: 'This calendar is readonly',
        });
      } else {
        outlookCalendarSync
          .addEvent(calendarId, event)
          .then(function (resp) {
            inst.removeEvent(event);
            resp.resource = event.resource;
            inst.addEvent(resp);
            events.push(resp);
            mobiscroll.toast({
              message: 'Event created on "' + calendarData[calendarId].name + '" calendar',
            });
          })
          .catch(function (error) {
            inst.removeEvent(args.event);
            onError(error);
          });
      }
    }
  },
  onEventUpdate: function (args) {
    if (outlookCalendarSync.isSignedIn()) {
      mobiscroll
        .confirm({
          title: 'Are you sure you want to update this event?',
          message: 'This action will affect your outlook Calendar event.',
          okText: 'Update',
        })
        .then(function (result) {
          if (result) {
            var event = args.event;
            var calendarId = event.outlookCalendarId;
            outlookCalendarSync
              .updateEvent(calendarId, event)
              .then(function () {
                mobiscroll.toast({
                  message: 'Event updated on "' + calendarData[calendarId].name + '" calendar',
                });
              })
              .catch(function (error) {
                inst.updateEvent(args.oldEvent);
                onError(error);
              });
          } else {
            inst.updateEvent(args.oldEvent);
          }
        });
    }
  },
  onEventDelete: function (args) {
    if (outlookCalendarSync.isSignedIn()) {
      mobiscroll
        .confirm({
          title: 'Are you sure you want to delete this event?',
          message: 'This action will remove the event from your outlook Calendar as well.',
          okText: 'Delete',
        })
        .then(function (result) {
          if (result) {
            var event = args.event;
            var calendarId = event.outlookCalendarId;
            outlookCalendarSync
              .deleteEvent(calendarId, event)
              .then(function () {
                inst.removeEvent(event);
                events = events.filter(function (ev) {
                  return event.id !== ev.id;
                });
                mobiscroll.toast({
                  message: 'Event deleted from "' + calendarData[calendarId].name + '" calendar',
                });
              })
              .catch(onError);
          }
        });
    }
    return false;
  },
});

var popup = mobiscroll.popup('#demo-sync-events-outlook-calendar-popup', {
  anchor: document.getElementById('outlook-cal-get-calendars'),
  width: 400,
  touchUi: false,
  showOverlay: false,
  scrollLock: false,
  contentPadding: false,
  display: 'anchored',
});

// Sign in
calendarElm.addEventListener('click', function (ev) {
  if (ev.target.id === 'outlook-cal-sign-in') {
    if (!outlookCalendarSync.isSignedIn()) {
      outlookCalendarSync.signIn().catch(onError);
    }
  } else if (ev.target.id === 'outlook-cal-today') {
    inst.navigate(new Date());
  } else if (ev.target.id === 'outlook-cal-get-calendars') {
    popup.open();
  }
});

// Switch click
popupElm.addEventListener('change', function (ev) {
  if (ev.target.classList.contains('outlook-calendar-switch')) {
    loadEvents(ev.target.checked, ev.target.value);
  }
});

// Edit click
editButton.addEventListener('change', function (ev) {
  var isEditable = ev.target.checked;
  inst.setOptions({
    clickToCreate: isEditable,
    dragToCreate: isEditable,
    dragToMove: isEditable,
    dragToResize: isEditable,
  });
});

// Sign out
popupElm.addEventListener('click', function (ev) {
  if (ev.target.id === 'outlook-cal-sign-out') {
    outlookCalendarSync.signOut().catch(onError);
  }
});

// Init outlook client
outlookCalendarSync.init({
  clientId: '<YOUR_OUTLOOK_CLIENT_ID>',
  redirectUri: '<YOUR_OUTLOOK_REDIRECT_URI>',
  onSignedIn: onSignedIn,
  onSignedOut: onSignedOut,
});
  

Duplicate Session

You have signed in on a different machine. To keep everything in sync, you have been signed out of this session.

If you need to invite team members, manage seats and accounts you can do it from the licenses page.

Duplicate Session

We noticed you are logged in on a different machine and have closed your old session.

If you need to invite team members, manage seats and accounts you can do it from the licenses page.