How can we help you today?

Workaround for Showing Occurrences of Recurring Event in ShortPoint Events Element


Problem


You have a recurring event in your event list:



When you connect above list to Events ShortPoint element, you would not see the recurring event occurrences:



Reason


Recurrences have been handled differently in SharePoint and requesting all list items of calendar does not return all occurrences of events if its recurring event. 


Solution


Step 1: Add Events ShortPoint element


In the page where you would want to add Events ShortPoint, add ShortPoint and select Events



Step 2: Connect using REST API Connection


Go to Connect Tab and select REST API Connection Type



In REST API URL, provide below URL:


<https://your-site>/_api/web/lists/getbytitle('<Events List Title>')/items?$select=*,Duration,RecurrenceData


<https://your-site>: Replace with your site URL (for example https://contoso.sharepoint.com)

<Events List Title>: Replace with title of your events list (for example Events)


Example URL: https://shortpoint.sharepoint.com/_api/web/lists/getbytitle('Calendar')/items?$select=*,Duration,RecurrenceData


Step 3: Use custom mapping to expand the recurrences of recurring event



Enable the Advanced Mapping and in Map Results and use the code given below:


Work around code to show events from the next few days:


// REST API URL should look like this (you can use either getbyid or getbyname)
// https://MYSHAREPOINTSITE.sharepoint.com/_api/web/lists/getbyid('34ea5a3c-220d-49e0-9f38-528c70da81bd')/items?$select=*,Duration,RecurrenceData,EventType,MasterSeriesItemID

var spEventsParser = { parseEvents: parseEvents, formatString: formatString, parseDate: parseDate, parseEvent: parseEvent, cloneObj: cloneObj }; function parseEvents(e, t, n) { for (var a = [], r = 0; r < e.length; r++)e[r]._SHORTPOINT_Recurring_Event_ID = r, a = a.concat(this.parseEvent(e[r], t, n)); return a; } function formatString(e) { var t = e.split("'"); return e = t.join(""), t = e.split('"'), e = t.join(""), t = e.split("="), (e = t.join(" ")).trim(), e.split(" "); } function parseDate(e, t) { if ("string" == typeof e) { if (t) { if (e.lastIndexOf("Z") == e.length - 1) { var n = e.substring(0, e.length - 1); return new Date(n); } return new Date(e); } return new Date(e); } return e; } function parseEvent(e, t, n) { if (e.fRecurrence) { t = t || this.parseDate(e.EventDate, e.fAllDayEvent), n = n || this.parseDate(e.EndDate, e.fAllDayEvent); var a = [], r = ["su", "mo", "tu", "we", "th", "fr", "sa"], D = ["first", "second", "third", "fourth"], s = 0, i = 0, f = /<windowEnd>(.+)<\/windowEnd>/.exec(e.RecurrenceData) || [], o = (f[0], f[1]); if (o && new Date(o) <= new Date) return []; if (-1 != e.RecurrenceData.indexOf("<repeatInstances>") && (s = e.RecurrenceData.substring(e.RecurrenceData.indexOf("<repeatInstances>") + 17), s = parseInt(s.substring(0, s.indexOf("<")))), -1 != e.RecurrenceData.indexOf("<daily ")) if (x = (x = e.RecurrenceData.substring(e.RecurrenceData.indexOf("<daily "))).substring(7, x.indexOf("/>") - 1), -1 != (y = this.formatString(x)).indexOf("dayFrequency")) for (var c = parseInt(y[y.indexOf("dayFrequency") + 1]), g = !0, d = this.parseDate(e.EventDate, e.fAllDayEvent); g;) { if (i++, new Date(d).getTime() >= t.getTime()) { var u = new Date(d), l = e.Duration % 86400; u.setSeconds(u.getSeconds() + l), (m = this.cloneObj(e)).EventDate = new Date(d), m.EndDate = u, m.fRecurrence = !1, m.Id = e.Id, m.ID = m.Id, a.push(m); } d.setDate(d.getDate() + c), (new Date(d) > n || s > 0 && s <= i) && (g = !1); } else -1 != y.indexOf("weekday") && (e.RecurrenceData = e.RecurrenceData + "<weekly mo='TRUE' tu='TRUE' we='TRUE' th='TRUE' fr='TRUE' weekFrequency='1' />"); if (-1 != e.RecurrenceData.indexOf("<weekly ")) { x = (x = e.RecurrenceData.substring(e.RecurrenceData.indexOf("<weekly "))).substring(8, x.indexOf("/>") - 1); for (var y = this.formatString(x), h = (c = parseInt(y[y.indexOf("weekFrequency") + 1]), g = !0, (d = this.parseDate(e.EventDate, e.fAllDayEvent)).getDay()); g;) { for (var w = h; w < 7; w++) { if (-1 != y.indexOf(r[w]) && (s > i || 0 == s)) if (i++, new Date(d).getTime() >= t.getTime()) (I = new Date(d)).setDate(I.getDate() + (w - h)), (u = new Date(I)).setSeconds(u.getSeconds() + e.Duration), (m = this.cloneObj(e)).EventDate = new Date(I), m.EndDate = u, m.fRecurrence = !1, m.Id = e.Id, m.ID = m.Id, a.push(m); } d.setDate(d.getDate() + (7 * c - h)), h = 0, (new Date(d) > n || s > 0 && s <= i) && (g = !1); } } if (-1 != e.RecurrenceData.indexOf("<monthly ")) { x = (x = e.RecurrenceData.substring(e.RecurrenceData.indexOf("<monthly "))).substring(9, x.indexOf("/>") - 1); y = this.formatString(x), c = parseInt(y[y.indexOf("monthFrequency") + 1]), g = !0, d = this.parseDate(e.EventDate, e.fAllDayEvent); for (var O = parseInt(y[y.indexOf("day") + 1]); g;) { if (i++, new Date(d).getTime() >= t.getTime()) if ((I = new Date(d)).setDate(O), I.getMonth() == d.getMonth()) (u = new Date(I)).setSeconds(u.getSeconds() + e.Duration), (m = this.cloneObj(e)).EventDate = new Date(I), m.EndDate = u, m.fRecurrence = !1, m.Id = e.Id, m.ID = m.Id, a.push(m); d.setMonth(d.getMonth() + c), (new Date(d) > n || s > 0 && s <= i) && (g = !1); } } if (-1 != e.RecurrenceData.indexOf("<monthlyByDay ")) { x = (x = e.RecurrenceData.substring(e.RecurrenceData.indexOf("<monthlyByDay "))).substring(14, x.indexOf("/>") - 1); y = this.formatString(x), c = parseInt(y[y.indexOf("monthFrequency") + 1]), g = !0, d = this.parseDate(e.EventDate, e.fAllDayEvent); for (var v = y[y.indexOf("weekdayOfMonth") + 1], E = new Date; g;) { if (i++, new Date(d).getTime() >= t.getTime()) { if ((I = new Date(d)).setDate(1), -1 != y.indexOf("weekday")) if (0 == I.getDay() ? I.setDate(I.getDate() + 1) : 6 == I.getDay() && I.setDate(I.getDate() + 2), "last" == v) { for (; I.getMonth() == d.getMonth();)E = new Date(I), 5 == I.getDay() ? I.setDate(I.getDate() + 3) : I.setDate(I.getDate() + 1); I = new Date(E); } else for (w = 0; w < D.indexOf(v); w++)5 == I.getDay() ? I.setDate(I.getDate() + 3) : I.setDate(I.getDate() + 1); else if (-1 != y.indexOf("weekend_day")) if (0 != I.getDay() && 6 != I.getDay() && I.setDate(I.getDate() + (6 - I.getDay())), "last" == v) { for (; I.getMonth() == d.getMonth();)E = new Date(I), 0 == I.getDay() ? I.setDate(I.getDate() + 6) : I.setDate(I.getDate() + 1); I = new Date(E); } else for (w = 0; w < D.indexOf(v); w++)0 == I.getDay() ? I.setDate(I.getDate() + 6) : I.setDate(I.getDate() + 1); else if (-1 != y.indexOf("day")) { if ("last" == v) (I = I.setMonth(I.getMonth() + 1)).setDate(0); else I.setDate(I.getDate() + D.indexOf(v)); } else { for (w = 0; w < r.length; w++)-1 != y.indexOf(r[w]) && (I.getDay() > w ? I.setDate(I.getDate() + (7 - (I.getDay() - w))) : I.setDate(I.getDate() + (w - I.getDay()))); if ("last" == v) { for (; I.getMonth() == d.getMonth();)E = new Date(I), I.setDate(I.getDate() + 7); I = new Date(E); } else for (w = 0; w < D.indexOf(v); w++)I.setDate(I.getDate() + 7); } if (I.getMonth() == d.getMonth()) (u = new Date(I)).setSeconds(u.getSeconds() + e.Duration), (m = this.cloneObj(e)).EventDate = new Date(I), m.EndDate = u, m.fRecurrence = !1, m.Id = e.Id, m.ID = m.Id, a.push(m); } d.setMonth(d.getMonth() + c), (new Date(d) > n || s > 0 && s <= i) && (g = !1); } } if (-1 != e.RecurrenceData.indexOf("<yearly ")) { x = (x = e.RecurrenceData.substring(e.RecurrenceData.indexOf("<yearly "))).substring(8, x.indexOf("/>") - 1); y = this.formatString(x), c = parseInt(y[y.indexOf("yearFrequency") + 1]), g = !0, d = this.parseDate(e.EventDate, e.fAllDayEvent); var p = parseInt(y[y.indexOf("month") + 1]) - 1; for (O = parseInt(y[y.indexOf("day") + 1]); g;) { if ((I = new Date(d)).setMonth(p), I.setDate(O), new Date(d).getTime() <= I.getTime()) if (i++, new Date(d).getTime() >= t.getTime()) (u = new Date(I)).setSeconds(u.getSeconds() + e.Duration), (m = this.cloneObj(e)).EventDate = new Date(I), m.EndDate = u, m.fRecurrence = !1, m.Id = e.Id, m.ID = m.Id, a.push(m); d.setFullYear(d.getFullYear() + c), (new Date(d) > n || s > 0 && s <= i) && (g = !1); } } if (-1 != e.RecurrenceData.indexOf("<yearlyByDay ")) { var x; x = (x = e.RecurrenceData.substring(e.RecurrenceData.indexOf("<yearlyByDay "))).substring(13, x.indexOf("/>") - 1); for (y = this.formatString(x), c = parseInt(y[y.indexOf("yearFrequency") + 1]), g = !0, d = this.parseDate(e.EventDate, e.fAllDayEvent), p = parseInt(y[y.indexOf("month") + 1]) - 1, v = y[y.indexOf("weekdayOfMonth") + 1], O = 0, w = 0; w < r.length; w++)-1 != y.indexOf(r[w]) && "true" == y[y.indexOf(r[w]) + 1].toLowerCase() && (O = w); for (; g;) { var I; if ((I = new Date(d)).setMonth(p), new Date(d).getTime() <= I.getTime() && (i++, new Date(d).getTime() >= t.getTime())) { I.setDate(1); var m, R = I.getDay(); if (O < R ? I.setDate(I.getDate() + (7 - R + O)) : I.setDate(I.getDate() + (O - R)), "last" == v) for (E = new Date(I); E.getMonth() == p;)I = new Date(E), E.setDate(E.getDate() + 7); else I.setDate(I.getDate() + 7 * D.indexOf(v)); if (I.getMonth() == p) (u = new Date(I)).setSeconds(u.getSeconds() + e.Duration), (m = this.cloneObj(e)).EventDate = new Date(I), m.EndDate = u, m.fRecurrence = !1, m.Id = e.Id, m.ID = m.Id, a.push(m); } d.setFullYear(d.getFullYear() + c), d.setMonth(p), d.setDate(1), (new Date(d) > n || s > 0 && s <= i) && (g = !1); } } return a; } return e.EventDate = new Date(this.parseDate(e.EventDate, e.fAllDayEvent)), e.EndDate = new Date(this.parseDate(e.EndDate, e.fAllDayEvent)), t && n ? new Date(t) <= e.EventDate && new Date(n) >= e.EndDate ? [e] : [] : [e]; } function cloneObj(e) { var t; if (null == e || "object" != typeof e) return e; if (e instanceof Date) return (t = new Date).setTime(e.getTime()), t; if (e instanceof Array) { t = []; for (var n = 0, a = e.length; n < a; n++)t[n] = this.cloneObj(e[n]); return t; } if (e instanceof Object) { for (var r in t = {}, e) e.hasOwnProperty(r) && (t[r] = this.cloneObj(e[r])); return t; } throw new Error("Unable to copy obj! Its type isn't supported."); }

// --- User Settings Start ---
// Change number of days ahead to show:
var numberOfDays = 20;

// Enable or disable Daylight Saving Time functionality here (change to true/false)
// If enableDayLightSaving is set to true and we're inside the configured DST period, then the time will be adjusted accordingly
var enableDayLightSaving = true;
// How many hours to add when DST is active? (usually +1)
var dstHours = +1;

// Set the period that DST starts and ends here
// Note that there's no need to set the year
// Start DST:   13 Mar, 02:00 — 1 hour forward
var dstStartDate = new Date('Mach 13, 2000 02:00:00');
// End DST:     06 Nov, 02:00 — 1 hour backward
var dstEndDate = new Date('November 06, 2000 02:00:00');

// Add an offset in hours to all the events
var generalTimeOffset = 0;
// --- User Settings End ---


var todayDate = new Date();
todayDate.setHours(0, 0, 0, 0);

var deadlineDate = new Date(todayDate);
deadlineDate.setDate(todayDate.getDate() + numberOfDays);

var items = data.d.results;

return handleEvents(items, numberOfDays);

function handleEvents(items, amountOfDays) {
    var _ = shortpoint.base.libs._;
    var $ = shortpoint.$;

    var DELETED_RECURRENCE_ITEM = 3;
    var MODIFIED_RECCURENCE_ITEM = 4;

    var exceptionalEvents = [];
    var resultEvents = [];

    items.forEach(function (event) {
        // Filter the events to get the regular and exceptional events arrays
        var isExceptionalItem = event.EventType == DELETED_RECURRENCE_ITEM
            || event.EventType == MODIFIED_RECCURENCE_ITEM;
        if (isExceptionalItem) {
            event.EventDate = new Date(event.EventDate);
            event.EndDate = new Date(event.EndDate);
            exceptionalEvents.push(event);
        }
    });

    var parsedEvents = spEventsParser.parseEvents(items, null, deadlineDate);

    // Filtering out useless events to not loop over them later
    // 1. Occurances of a recurring event that was created in the past should be filtered out.
    // 2. Multi-day events that started in the past should be kept.
    var parsedEvents2 = _.filter(parsedEvents, function (event) {
        return todayDate < event.EventDate ||
            (event.EventDate < todayDate && event.Duration > 86400); //86400 is 24h in seconds
    });

    // If deleted or modified then we need to remove it from the itemsWithRecurrency array that was generated in spEventsParser.parseEvents
    parsedEvents2.forEach(function (event) {
        // Find all exceptions that match this recurring item's ID
        var exceptions = exceptionalEvents.filter(function (exceptionEvent) {
            if (exceptionEvent.MasterSeriesItemID == event.ID &&
                exceptionEvent.EventDate.getFullYear() == event.EventDate.getFullYear() &&
                exceptionEvent.EventDate.getMonth() == event.EventDate.getMonth() &&
                exceptionEvent.EventDate.getDate() == event.EventDate.getDate()
            ) {
                return true;
            }
            return false;
        });

        // If there are any exceptions for this event, then we push the modified, and not push the deleted ones
        if (exceptions.length) {
            var exceptionEvent = exceptions[0]; // take the exceptional event that we found (should be only 1 for each event in itemsWithRecurrency)
            // If the exceptional event is of type "deleted" then it won't be added to the list
            if (exceptionEvent.EventType == MODIFIED_RECCURENCE_ITEM) { // If it's a modified event then it will be added instead of the original.
                exceptionEvent.EventDate = spEventsParser.parseDate(exceptionEvent.EventDate, exceptionEvent.fAllDayEvent);
                exceptionEvent.EndDate = spEventsParser.parseDate(exceptionEvent.EndDate, exceptionEvent.fAllDayEvent);
                resultEvents.push(exceptionEvent);
            }
        } else {
            // Otherwise if we didn't find an exceptions for this event then we just push it. (wasn't modified or deleted)
            resultEvents.push(event);
        }
    });

    resultEvents.forEach(function (event) {
        // #region Trim events that span multiple days so that they don't span longer than the number of days specified
        // (ex: event that starts few days ago and spans for 2 months will be trimmed to the number of days specified)
        event.OriginalEventDate = event.EventDate; // save original start date
        if (event.EventDate < todayDate && todayDate <= event.EndDate) {
            event.EventDate = todayDate;
        }
        event.OriginalEndDate = event.EndDate; // save original end date
        if (event.EventDate <= deadlineDate && event.EndDate > deadlineDate) {
            event.EndDate = deadlineDate;
        }
        // #endregion

        // #region Apply changes based on DST configuration
        var localTime = event.EventDate.getTime();
        var localEndTime = event.EndDate.getTime();
        var regionTimeoffset = dstHours * 60000;

        var applyDst = false;
        if (enableDayLightSaving &&
            // Check if today is after DST start date
            dstStartDate.getMonth() < todayDate.getMonth() && dstStartDate.getDate() < todayDate.getDate() &&
            dstStartDate.getHours() < todayDate.getHours() && dstStartDate.getMinutes() < todayDate.getMinutes() &&
            // Check if today is before DST end date
            todayDate.getMonth() < dstEndDate.getMonth() && todayDate.getDate() < dstEndDate.getDate() &&
            todayDate.getHours() < dstEndDate.getHours() && todayDate.getMinutes() < dstEndDate.getMinutes()
        ) {
            applyDst = true;
        }

        if (applyDst) {
            event.EventDate.setTime(localTime + regionTimeoffset);
            event.EndDate.setTime(localEndTime + regionTimeoffset);
        }
        // #endregion Apply changes based on DST configuration

        // #region Apply general time offset
        event.EventDate.setTime(event.EventDate.getTime() + (generalTimeOffset * 60000));
        event.EndDate.setTime(event.EndDate.getTime() + (generalTimeOffset * 60000));
        // #endregion Apply general time offset
    });

    resultEvents = _.sortBy(resultEvents, function (item) {
        return item.EventDate;
    });

    return resultEvents;
}


There are some user setting variables in this script, you can edit them as you like.



Click on Connect 


Step 4: Map Columns


In the Items tab, map the columns the way you want:



Display events form in a pop-up (Optional):


Map the url to the display form of the event and then add #Id in the Link field and select lightbox in Linking options


<https://your-site>/Lists/<Events List Title>/DispForm.aspx?ID=#DisplayId


<https://your-site>: Replace with your site URL (for example https://contoso.sharepoint.com)

<Events List Title>: Replace with title of your events list (for example Events)


Example URL: https://contoso.sharepoint.com/Lists/Events/DispForm.aspx?ID=



Click Insert + and you are done!


Now you can see the Events ShortPoint Element with the occurrence(s)!







Did you find it helpful? Yes No

Send feedback
Sorry we couldn't be helpful. Help us improve this article with your feedback.

World's best intranet sites are designed using ShortPoint

Get started today! Learn more
See all 31 topics

Start a trial

Ignite your vision. Install ShortPoint directly on your site, or play in sandbox mode. No credit card required.

Get started today

World’s best intranet sites are designed using ShortPoint

Thousands of companies using ShortPoint everyday to design, brand and build award winning intranet sites.

Get started Learn more