In this final part of the series we’re going to complete the holiday sync app by importing the selected calendar exceptions into Project Server.
We’ll start from where we finished up in Part 2 with our app loading data from both existing project server calendars and our external web service, so to follow this article make sure you start with the solution from the end of Part 2.
Part 3: Importing data into Enterprise Calendars from our App
Now that we have a list of calendar exceptions that we want to import we need to use some JSOM to actually import those exceptions.
To break-down what we need to do here I’m going to review this JSOM in three steps;
Step 1 Prepare context and get objects to update
// Get the Project Server context var projContext = PS.ProjectContext.get_current(); // Get our Calendar Collection var eCalColl = projContext.get_calendars(); var eCalendar = eCalColl.getByGuid(calUid); var eCalBaseExcep = eCalendar.get_baseCalendarExceptions();
In step 1 we instantiate our object variables using the PS.js JSOM library to first get our calendar collection, then get our calendar by GUID from that collection and finally we get our base calendar exceptions from our calendar.
Next we’ll update those collections.
Step 2 Create the exception(s)
// Step 2 Loop through and add each exception for (var i = 0; i < exceptions.length; i++) { var excepInfo = new PS.CalendarExceptionCreationInformation(); // Set the exception properties excepInfo.set_name(exceptions[i].Descriptor); excepInfo.set_start(exceptions[i].Date); excepInfo.set_finish(exceptions[i].Date); // Finally add the exception info to the base calendar object eCalBaseExcep.add(excepInfo); } // Update the collection eCalColl.update();
Now we’re going to create each calendar exception using the PS.CalendarExceptionCreationInformation constructor, you’ll find one of those constructors for most of the objects in JSOM, if you want more on this see MSDN; http://msdn.microsoft.com/en-us/library/office/jj669390.aspx.
Once we have our excepInfo object we set the required properties; Name, Start and Finish, then finish by adding that item to our exception collection before moving to the next exception to be added. Finally we update the calendar collection object with all the exceptions created.
Now as we’re working asynchronously the last step is to execute the above update(s);
Step 3 Update the calendar asynchronously
// Finally asynchronously execute the update projContext.executeQueryAsync(Function.createDelegate(this, function () { // Success update our grid and finish up this.grid.setSelectedRows([]); // Display the results and remove the progress msg SP.UI.Notify.addNotification("Exceptions added successfully", false); }), Function.createDelegate(this, function (call, error) { // Handle Error alert(error.get_message()); }));
So using the JSOM executeQueryAsync function we execute the change and handle the result, here we simply want to notify the user of the result.
Full code block follows, paste this into the bottom of the App.js:
// Function to add calendar exceptions via JSOM HolidaySync.prototype.addCalendarException = function (calUid, exceptions) { // Show a progress message this.notifyMsg = SP.UI.Notify.addNotification('<img src="/_layouts/images/loadingcirclests16.gif" style="vertical-align: top;"/> Importing...', true); // Step 1 Get the Project Server context and objects var projContext = PS.ProjectContext.get_current(); // Get our Calendar Collection var eCalColl = projContext.get_calendars(); var eCalendar = eCalColl.getByGuid(calUid); var eCalBaseExcep = eCalendar.get_baseCalendarExceptions(); //CSOM Ref (no JSOM): http://msdn.microsoft.com/en-us/library/office/microsoft.projectserver.client.calendarexceptioncollection_di_pj14mref_members.aspx // Step 2 Loop through and add each exception for (var i = 0; i < exceptions.length; i++) { // Create our Calendar Exception Info //http://msdn.microsoft.com/en-us/library/office/jj669390.aspx var excepInfo = new PS.CalendarExceptionCreationInformation(); // Append the year to the name to prevent future duplicates var exName = exceptions[i].Descriptor + " " + new Date(exceptions[i].Date).getFullYear(); // Set the exception properties excepInfo.set_name(exName); excepInfo.set_start(exceptions[i].Date); excepInfo.set_finish(exceptions[i].Date); // Finally add the exception to the collection eCalBaseExcep.add(excepInfo); } // Update the collection eCalColl.update(); // Step 3 Asynchronously execute the update projContext.executeQueryAsync(Function.createDelegate(this, function () { // Success update our grid and finish up this.grid.setSelectedRows([]); // Display the results and remove the progress msg SP.UI.Notify.addNotification("Exceptions added successfully", false); SP.UI.Notify.removeNotification(this.notifyMsg); }), Function.createDelegate(this, function (call, error) { // Handle Error SP.UI.Notify.removeNotification(this.notifyMsg); alert(error.get_message()); })); };
Final bit: Import Button
Okay we’re almost done, just one last thing to do and that is to handle the click of the import button. A bit of jQuery will handle that for us, and in which we need to do just one more thing which is to check for any duplicates being imported to prevent import errors.
Paste the following in the main code block of App.js (should be right after the ‘$(“#importBtn”).click(…’ function:
// Button to import selected exceptions $("#importBtn").click(Function.createDelegate(this, function () { var selectedRows = holidaySync.grid.getSelectedRows(); // Use helper function to check for any duplicates before importing var exceptionsToImport = Helpers.removeDuplicates(selectedRows, holidaySync.data); // Import the exceptions if (exceptionsToImport.length > 0) { holidaySync.addCalendarException(holidaySync.data.calendarId, exceptionsToImport); } else { // Mark all existing holidaySync.grid.setSelectedRows([]); alert("All selected exceptions already exist."); } }));
What we need to do in that function is call our removeDuplicates helper function which was created back in part 1 of this series. The function will return a filtered array of exceptions that we can then pass as a parameter to our addCalendarException function.
Now we should be able to test it and see the following:
All Done
This app documented here is now available on the SharePoint App store, so please rate it if you use it!
Source Download / Repository
You can browse or download the full source code for the completed app on the following GitHub repository: