Getting started with the Project Server 2013 JavaScript object model

In Project Server 2013, the JavaScript object model can be used in Project Online, mobile, and on-premise development. This topic provides a brief overview of the JavaScript object model and then describes how to create an application page that retrieves and iterates through projects by using the JavaScript object model.

Using the Project Server JavaScript object model

Using the JavaScript object model is a great way to create an app that runs client-side (as opposed to managed client code which needs to run remotely). Apps can use the JavaScript object model to retrieve or change objects by sending asynchronous calls to the server. Apps that use the JavaScript object model are typically deployed as custom SharePoint Add-ins, application pages, and Web Parts. For more information, see "Types of SharePoint components that can be in an app for SharePoint" in Host webs, add-in webs, and SharePoint components in SharePoint 2013.

The JavaScript object model implements the main functionality of Project Server 2013, but the JavaScript object model and the server object model do not have one-to-one parity. The entry point to the JavaScript object model is the ProjectContext object, which represents the client context for Project Server 2013 and provides access to server content and functionality. The JavaScript object model for Project Server 2013 is defined in the PS.js file, which is located in the default path %ProgramFiles%\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS on the application server. Project Server 2013 also installs the PS.Debug.js file in the same location. PS.Debug.js is an unminified version of PS.js that provides IntelliSense information.

The JavaScript object model allows Forms authentication, and all requests are authenticated as the current user. For more information about security and other considerations for designing custom apps and solutions, see Authentication, authorization, and security in SharePoint 2013, Important aspects of the SharePoint Add-in architecture and development landscape, and SharePoint Add-ins compared with SharePoint solutions.

Note

To access data from a SharePoint site remotely, SharePoint 2013 provides a cross-domain library that enables you to make client-side cross-domain calls. For more information, see Access SharePoint 2013 data from add-ins using the cross-domain library.

Many concepts and processes for using the JavaScript object model for Project Server 2013 resemble those in related client object models. For more information about the Project Server 2013 managed client object model, see Microsoft.ProjectServer.Client. For more information about the SharePoint 2013JavaScript object model and managed client object model, see Complete basic operations using JavaScript library code in SharePoint 2013 and Complete basic operations using SharePoint 2013 client library code.

Walkthrough: Creating an application page that retrieves and iterates through projects

Learn how to create an application page that displays the ID, name, and created date of each published project in a site.

Prerequisites for creating an application page that retrieves and iterates through projects

To develop the application page that is described in this topic, you must install and configure the following products:

  • SharePoint Server 2013
  • Project Server 2013 with at least one published project
  • Visual Studio 2012
  • Office Developer Tools for Visual Studio 2012

You must also have permissions to deploy the extension to SharePoint Server 2013 and to retrieve projects.

Note

These instructions assume that you are developing on the computer that is running Project Server 2013.

Creating the application page in Visual Studio 2012

The following steps create a SharePoint project and an application page that contains a table and label. The table displays information about the projects and the label displays error messages.

  1. On the computer that is running Project Server 2013, run Visual Studio 2012 as an administrator.

  2. Create an empty SharePoint 2013 project, as follows:

    1. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.

    2. In the list of template categories, choose the Office SharePoint category, and then choose the SharePoint 2013 Project template.

    3. Name the project GetProjectsJSOM, and then choose the OK button.

    4. In the SharePoint Customization Wizard dialog box, choose Deploy as a farm solution, and then choose the OK button.

  3. In Solution Explorer, edit the value of the Site URL property for the ProjectsJSOM project to match the URL of the Project Web App instance (for example, https://ServerName/PWA).

  4. Open the shortcut menu for the GetProjectsJSOM project, and then add a SharePoint "Layouts" mapped folder.

  5. In the Layouts folder, open the shortcut menu for the GetProjectsJSOM folder, and then add a new SharePoint application page named ProjectsList.aspx.

    Note

    This example does not use the code-behind file that Visual Studio 2012 creates for the application page.

  6. Open the shortcut menu for the ProjectsList.aspx page and choose Set as Startup Item.

  7. In the markup for the ProjectsList.aspx page, define a table and a message placeholder inside the "Main" asp:Content tags, as follows.

    <table width="100%" id="tblProjects">
        <tr id="headerRow">
            <th width="25%" align="left">Project name</th>
            <th width="25%" align="left">Created date</th>
            <th width="50%" align="left">Project ID</th>
        </tr>
    </table>
    <div id="divMessage">
                <span id="spanMessage" style="color: #FF0000;"></span>
    </div>
    

Retrieving the projects collection

The following steps retrieve and initialize the projects collection.

  1. After the closing div tag, add a SharePoint:ScriptLink tag that references the PS.js file, as follows.

     <SharePoint:ScriptLink name="PS.js" runat="server" ondemand="false" localizable="false" loadafterui="true" />
    
  2. Below the SharePoint:ScriptLink tag, add script tags, as follows.

     <script type="text/javascript">
         // Paste the remaining code snippets here, in the order that they are presented.
     </script>
    
  3. Declare a global variable to store the projects collection, as follows.

    var projects;
    
  4. Call the SP.SOD.executeOrDelayUntilScriptLoaded method to ensure that the PS.js file is loaded before your custom code runs.

    SP.SOD.executeOrDelayUntilScriptLoaded(GetProjects, "PS.js");
    
  5. Add a function that connects to the current context and retrieves the projects collection, as follows.

     function GetProjects() {
         // Initialize the current client context.
         var projContext = PS.ProjectContext.get_current();
         // Get the projects collection.
         projects = projContext.get_projects();
         // Register the request that you want to run on the server.
         // This call includes an optional "Include" parameter to request only the
         // Name, CreatedDate, and Id properties of the projects in the collection.
         projContext.load(projects, 'Include(Name, CreatedDate, Id)');
         // Run the request on the server.
         projContext.executeQueryAsync(onQuerySucceeded, onQueryFailed);
     }
    

    Some client objects that you retrieve through the context contain no data until they are initialized; that is, you cannot access the property values of the object until the object is initialized. Moreover, for properties of type ValueObject, you must explicitly request the property before you can access its value. (If you try to access a property before it is initialized, you receive a PropertyOrFieldNotInitializedException exception.)

    To initialize an object, you call the load method (or the loadQuery method) and then the executeQueryAsync method.

    • Calling the load function or the loadQuery function registers a request that you want to run on the server. You pass in a parameter that represents the object that you want to retrieve. If you are working with a ValueObject property, then you also request the property in the parameter.

    • Calling the executeQueryAsync function sends the query request to the server asynchronously. You pass in a success callback function and a failure callback function to invoke when the server response is received.

    To reduce network traffic, request only the properties that you want to work with when you call the load function. In addition, if you are working with multiple objects, group multiple calls to the load function before you call the executeQueryAsync function when it is possible.

Iterating through the projects collection

The following steps iterate through the projects collection (if the server call is successful) or render an error message (if the call fails).

  1. Add a success callback function that iterates through the projects collection, as follows.

     function onQuerySucceeded(sender, args) {
         // Get the enumerator and iterate through the collection.
         var projectEnumerator = projects.getEnumerator();
         while (projectEnumerator.moveNext()) {
             var project = projectEnumerator.get_current();
             // Create the row for the project's information.
             var row = tblProjects.insertRow();
             // Insert cells for the Id, Name, and CreatedDate properties.
             row.insertCell().innerText = project.get_name();
             row.insertCell().innerText = project.get_createdDate();
             row.insertCell().innerText = project.get_id();
         }
     }
    
  2. Add a failure callback function that renders an error message, as follows.

    function onQueryFailed(sender, args) {
        $get("spanMessage").innerText = 'Request failed: ' + args.get_message();
    }
    
  3. To test the application page, on the menu bar, choose Debug, Start Debugging. If you are prompted to modify the web.config file, choose OK.

Complete code example

Following is the complete code from the ProjectsList.aspx file.

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ProjectsList.aspx.cs" Inherits="GetProjectsJSOM.Layouts.GetProjectsJSOM.ProjectsList" DynamicMasterPageFile="~masterurl/default.master" %>
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
    <table width="100%" id="tblProjects">
    <tr id="headerRow">
        <th width="25%" align="left">Project name</th>
        <th width="25%" align="left">Created date</th>
        <th width="50%" align="left">Project ID</th>
    </tr>
</table>
<div id="divMessage">
        <span id="spanMessage" style="color: #FF0000;"></span>
</div>
<SharePoint:ScriptLink name="PS.js" runat="server" ondemand="false" localizable="false" loadafterui="true" />
<script type="text/javascript">
    // Declare a variable to store the published projects that exist
    // in the current context.
    var projects;
    // Ensure that the PS.js file is loaded before your custom code runs.
    SP.SOD.executeOrDelayUntilScriptLoaded(GetProjects, "PS.js");
    // Get the projects collection.
    function GetProjects() {
        // Initialize the current client context.
        var projContext = PS.ProjectContext.get_current();
        // Get the projects collection.
        projects = projContext.get_projects();
        // Register the request that you want to run on the server.
        // This call includes an optional "Include" parameter to request only the
        // Name, CreatedDate, and Id properties of the projects in the collection.
        projContext.load(projects, 'Include(Name, CreatedDate, Id)');
        // Run the request on the server.
        projContext.executeQueryAsync(onQuerySucceeded, onQueryFailed);
    }
    function onQuerySucceeded(sender, args) {
        // Get the enumerator and iterate through the collection.
        var projectEnumerator = projects.getEnumerator();
        while (projectEnumerator.moveNext()) {
            var project = projectEnumerator.get_current();
            // Create the row for the project's information.
            var row = tblProjects.insertRow();
            // Insert cells for the Id, Name, and CreatedDate properties.
            row.insertCell().innerText = project.get_name();
            row.insertCell().innerText = project.get_createdDate();
            row.insertCell().innerText = project.get_id();
        }
    }
    function onQueryFailed(sender, args) {
        $get("spanMessage").innerText = 'Request failed: ' + args.get_message();
    }
</script>
</asp:Content>
<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
Application Page
</asp:Content>
<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
My Application Page
</asp:Content>

See also