SharePoint

SharePoint Calendar

Lipiec 25, 2016 0
Podziel się:

Sharepoint Calendar has been around since a beginning of a SharePoint although this functionality is really great it can cause some problems for each developer. Let`s have a look on somke major functionalities that this app provides:

  • Integration with Outlook
  • Support for recurring events
  • Ability to add colourfull overlays (up to 9 overlays in standard)

Those main features provided above make the calendar a powerfull app but what are the issues if we look from a perspective of a developer?

Let`s first have a look on the Calendar issues:

  1. It is only possible to add up to nine overlays with pre-defined colours
  2. It is not possible to  sign up for an event although functionality still exists in SharePoint by default it is disabled
  3. Unable to extract recuring – in code in any other place than Server Object Model – SPQuery, or SPServices that uses SOAP – actually this is depreceated
  4. REST does not retrieve manage metadata in get methods – there are some workarounds but there is a bug,
  5. REST call will not retrieve xml from Recurring event – extra call for each recurrence need to be made
  6. Does not support Client Side Rendering (CSR) – basically javascript file is not added to the calendar view – in a web part there is no option to add JSLink
  7. Does not support filtering by a column
  8. There is no option to add more columns to calendar view

calendar

As it is stated above the calendar have quite a few issues regarding development let`s have a look on extracting recuring events. When using Server Object Model SPQuery we are able to expand recurrences as shown below, but this in the only place we are able to do so.

  private SPQuery query { get; set; } = new SPQuery();
        private void GetCalendarData(SPList list)
        {
            query.ExpandRecurrence = true;
            SPListItemCollection listColl = list.GetItems(this.query);
            foreach (SPListItem item in listColl)
            {
                if(item==null) throw new ArgumentNullException(nameof(item));
            }
        }

queryInfo       siteQuery

If we have a look on JSOM SP.CamlQuery we are able to see that there is no option for expanding recurrence as well.

SP.Caml

The only option if we are not using SPQuery is to write our own code that will expand recurences, but before we will get to it first we need to know how SharePoint saves recurences. When adding recurrence to SharePoint we are able to chose certain data, such as, when to start when to finish etc. all the data is stored as a xml file in column ows_RecurrenceData example of such a xml is shown below.

recurrence

This sounds like not a big deal just converting a xml to objects and it`s done but there are few tricks regarding recurrences, such as, when user delete just a single occurence from it then new item is created which is joined with a recurrence item with a deletion dates etc. which makes life much harder for every developer.

 

Just to summarize if we want to use CSOM and we do not want to write our own functions for extracting recurrences we are stuck with SPServices that uses SOAP underneath and it is depreceated. If we are using SOM we can use expand in SPQuery but neither Site Data Query or Cross List Query Cache are able to expand recurrences, which means we will have to write up our own code that will do it for us.

There is a large amount of links where we can find, how to retrieve data from SharePoint calendar and display it on custom calendar some of them use angular, I will only show a bit of codes that allow to do this without using rest due to the issues that this brings.

this.listId = listId;
this.viewQuery = viewQuery;
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
var spContext = new SP.ClientContext.get_current();
var list = _this.getListFromScope(spContext, _this);
var items = list.getItems(_this.getCalendarQuery(_this));

if (_this.additionalFields !== "")
_this.includeFields += _this.additionalFields;

spContext.load(items, 'Include(' + _this.includeFields + ')');
spContext.load(list);
spContext.executeQueryAsync(
function (response) {
if (_this.$scope) {
_this.setScopeListId(list, _this);
_this.convertItemsToEventSource(items, _this);
} else {
var events = _this.isUpcomingEvent ?
_this.convertItemsToEventSource(items, _this) :
_this.convertItemsToSmallCallendar(items, _this);
success(events, list.get_id().toString());
}
},
function (events, args) {
_this.setError(args.get_message(), _this);
});
});
var itemEnumerator = itemColl.getEnumerator();
var events = [];
while (itemEnumerator.moveNext()) {
var event = this.convertItemToEventSource(itemEnumerator.get_current(), _this);
if (event)
events.push(event);
}
if (_this.$scope)
_this.setEventSources(events, _this);
else
return events;
if (!item) return null;
        var color = _this.getLookupValue(item, Puma.Calendar.Constants.CalendarCategoryColorCode, false);
        if (color.indexOf("#") <= -1)
            color = "#" + color;
        var newItem = {
            description: item.get_item(Puma.Calendar.Constants.Description),
            duration: 0,
            end: _this.getDate(item.get_item(Puma.Calendar.Constants.EndDate)),
            start: _this.getDate(item.get_item(Puma.Calendar.Constants.EventDate)),
            allDay: item.get_item(Puma.Calendar.Constants.AlDayEvent),
            recurent: item.get_item(Puma.Calendar.Constants.Recurrence),
            id: item.get_id(),
            Calendar_x0020_Category: _this.getLookupValue(item, Puma.Calendar.Constants.CalendarCategory, false),
            Calendar_x0020_CategoryId: _this.getLookupValue(item, Puma.Calendar.Constants.CalendarCategory, true),
            location: item.get_item(Puma.Calendar.Constants.Location),
            title: item.get_item(Puma.Calendar.Constants.Title),
            color: color,
            Region: _this.getTaxonomyFieldValue(item.get_item(Puma.Calendar.Constants.PumaRegion)),
            Puma_x0020_Location: _this.getTaxonomyFieldValue(item.get_item(Puma.Calendar.Constants.PumaLocation)),
            BU: _this.getTaxonomyFieldValue(item.get_item(Puma.Calendar.Constants.PumaBU)),
            attachments: item.get_item(Puma.Calendar.Constants.CalendarLinks)
        };

        _this.addAditionalFields(item, newItem, _this);
        return newItem;</pre>

 

 

What actualy happen in this code is we choose fields to retrieve users can specify additional fields they want to display on a calendar, there is a code to expand recurrences I`ve used custom code from one of the shown below links. We retrieve custom color codes which is actually a lookup field, we also retrieve attachments and display if they exist,  we add filter on a start if user decides to have pre-defined filters. All data is connected to the calendar – angular a full calendar. Whole layout of the calendar is almost same as a SharePoint calendar with custom filters, colours etc.

calendar

Just to summarize the calendar has vast amount of options and extending them can be tricky. Does not support any new functionalities from SharePoint 2013 such as JsLink – it seems like nothing has changed since SharePoint 2010 in calendar. We can retrieve data from calendar using CSOm but recurrences could be tricky. Adding Manage Metadata columns and filtering on them could be difficult.

References:

http://www.nothingbutsharepoint.com/2012/04/26/use-spservices-to-get-recurring-events-as-distinct-items-aspx/

https://github.com/OfficeDev/PnP/tree/master/Samples/Core.DisplayCalendarEvents

http://fullcalendar.io/

http://angular-ui.github.io/ui-calendar/

http://sympmarc.com/2015/07/07/retrieving-expanded-calendar-events-with-rest-vs-soap/

 

 

Oceń ten post
Kategorie: SharePoint
Kosyna
Autor: Piotr Kosyna
Senior SharePoint developer, currently working in Sii mainly on SharePoint 2013 farm solutions and SharePoint online.

Imię i nazwisko (wymagane)

Adres email (wymagane)

Temat

Treść wiadomości

Zostaw komentarz