Making your Code Ready for JSOM

The previous post described how the JSOM model works. This post discusses how to prepare Visual Studio to provide support for JSOM and how to load the JSOM scripts before accessing the object model.

Preparing your Environment for JSOM

If you are using Visual Studio 2010 as the environment for developing with JSOM, you can use the following procedures to improve your development experience.

Intellisense for JSOM

You can enable Intellisense for JSOM to load the object model properties in the VS IDE.

  • If you want to use JSOM as inline in an application page, you can enable Intellisense by adding the following references to the PageHead content placeholder of your page.

<% #if SOME_UNDEFINED_CONSTANT %>          

        <script type="text/ecmascript" src="/_layouts/SP.core.debug.js" />   

        <script type="text/ecmascript" src="/_layouts/SP.runtime.debug.js" />   

        <script type="text/ecmascript" src="/_layouts/SP.debug.js" />   

        <% #endif %>

Notice the pre-processor directive and use of the constant. This ensures that the above <script> tags will be omitted from the actual page rendering. If you do not use this directive, you might get an error when the page gets rendered.

Once these references are added, you can now write your code in the following <script> tags. This makes all of the methods available to the object model.

<script type="text/javascript">

//Leverage the JSOM API here

        </script>
  • To enable Intellisense inside a visual Web Part, add the following references to the .ascx file.

<% #if SOME_UNDEFINED_CONSTANT %>          

<script type="text/javascript" src="/_layouts/MicrosoftAjax.js" />
<script type="text/javascript" src="/_layouts/SP.debug.js" />

<% #endif %>

<script type="text/javascript">

//Leverage the JSOM API here

</script>

  • Similarly, if you have a custom .js file where you want to enable Intellisense for JSOM, you can add references to all of the required JSOM debug script files that are available in the {SharePointRoot}\TEMPLATE\LAYOUTS folder by using the reference comment.

/// <reference name="MicrosoftAjax.js" />

/// <reference name="~/TEMPLATE/LAYOUTS/SP.core.debug.js" />

/// <reference name="~/TEMPLATE/LAYOUTS/SP.debug.js" />

As a best practice, add references for only the required JSOM script files and remove all references before your code goes into production.

Preparing JSOM

The previous blog post stated that JSOM requires a set of files to be downloaded on the client machine to perform any request or response operations. The files need be referenced to ensure that the scripts are downloaded before any call is made for a JSOM operation.

Using JSOM with SharePoint Out-of-the-Box Containers

The good news is that when you create a Page or Web Part which uses the SharePoint default master page, you do not need to do anything before using JSOM.

The following is an example of using JSOM in an application page. It simply updates the value of a label control on the click of a button with the current site title. Notice that no ScriptLink tags are mentioned here simply because the default master page (v4.master) already holds references to the required JSOM scripts that need to be downloaded to the client.

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>

<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>

<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.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=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="LoadECMAScript.aspx.cs" Inherits="ECMAScriptSample.Layouts.ECMAScriptSample.LoadECMAScript" DynamicMasterPageFile="~masterurl/default.master" %>

 

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">

    <% #if SOME_UNDEFINED_CONSTANT %>                   

    <script type="text/ecmascript" src="/_layouts/SP.core.debug.js" />  

     <script type="text/ecmascript" src="/_layouts/SP.runtime.debug.js" />

     <script type="text/ecmascript" src="/_layouts/SP.debug.js" />                                                   

    <% #endif %>

   

    <script type="text/javascript">       

        var web;         

        function getWebTitle() {

            var context = new SP.ClientContext.get_current();

            this.web = context.get_web();

 

            // Load the web object           

            context.load(this.web,'Title');

 

            //Make a query call to execute the above statements

            context.executeQueryAsync(Function.createDelegate(this, this.onSuccess), Function.createDelegate(this, this.onFailure));           

        }

 

        function onSuccess() {

                var control = document.getElementById('ctl00_PlaceHolderMain_lblWebName')

                if (control != null) {

 

                    // Get the title of the site

                    // Update the label control with the value of the site Title

                    control.innerText = this.web.get_title();

                }               

        }

 

        function onFailure() {

            alert("Could not retrieve title for the web");

        }

    </script>      

</asp:Content>

 

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">

    <asp:Label ID="lblWebName" runat="server" Text="Label"></asp:Label>

    <asp:Button ID="btnShowWebName" runat="server" Text="Button" onClick="javascript:getWebTitle()" />

</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>

Using JSOM with Custom Containers

In a case where you have customized or utilized a new master page for your sites, you can very easily ensure that JSOM is loaded before you start accessing it.

When referencing JSOM in your custom container that does not refer to the default SharePoint master page, you have two options:

  • Use the server side ScriptLink class to declaratively register a script. The class provides properties and methods for registering scripts so that they can be requested when the page is being rendered.

<SharePoint:ScriptLink ID="registerSP" runat="server" OnDemand="true" LoadAfterUI="true" Name="SP.js">

  • You can alternatively use the ScriptLink.RegisterOnDemand(page, strFile, localizable) method to register the script for loading on the OnPrerender method of the container (this is the preferred way of loading up the scripts in your custom web parts).

One implication of using the ScriptLink class with the OnDemand attribute set to true is that the loading of the JavaScript files becomes non deterministic. This may sometimes lead to unpredictable results and unwanted errors on the client. For example, a client JavaScript method is called before the JSOM has been loaded in the page load event. In this situation, you may generate a Javascript runtime object expected error.

To facilitate such scenarios, the SOD framework provides methods to ensure that the client scripts are loaded before any execution takes place on the dependent methods. One such method is SP.SOD.executeOrDelayUntilScriptLoaded(func, depScriptFileName). Calling this method before the executing method ensures that the function provided in the first parameter is not executed until the script file name mentioned is not loaded or has not been loaded.

The following is the definition for this method in the init.js file:

function ExecuteOrDelayUntilScriptLoaded(func, depScriptFileName)

{ULSxSy:;

depScriptFileName=depScriptFileName.toLowerCase();

var eventName="sp.scriptloaded-"+depScriptFileName;

return ExecuteOrDelayUntilEventNotified(func, eventName);

}

Internally the ExecuteOrDelayUntilScriptLoaded method maintains a global array of eventsInfo objects. Each eventInfo object contains a property named notified and an array of jobs that represents the functions that need to executed when the event (fileName) occurs. The event is fired by each file by making a call to the NotifyScriptLoadedAndExecuteWaitingJobs("filename") method. This method sets the notified property of the corresponding eventinfo object to true. Unless this property is true, the SOD framework ensures that the associated function is not executed.

If you intend to perform update operations on the SharePoint object, there is one last thing you need to add to your page before you can use the object model for any update operation. You need to add an entry for the FormDigest tag to generate a Security Token based on current user, date and time.

<SharePoint:FormDigest runat="server" />

This generates a security validation when the page is requested and the security token is returned to the user. When the form is submitted to the server, SharePoint verifies that the security validation has not changed. The security validation is specific to a user, site, and time period and expires after a configurable amount of time.

The next couple of posts discuss performing operations by using JSOM.