Using SharePoint CSOM in HTML5 apps

The SharePoint 2010 JavaScript Client Side Object Model (JavaScript CSOM, sometimes called JSOM) offers a powerful API to integrate SharePoint into your single page HTML5 application. It provides access to list data and let’s you manage sites, lists, permissions, notifications and much more.

The use of SharePoint CSOM inside SharePoint Web Part pages is well documented. In this case, your code using CSOM operates inside the context of the SharePoint UI.

But what if you want to create your own unique UI, using your favorite HTML5 UI toolkit, say jQuery UI, ExtJs, Sencha Touch, KendoUI, Twitter Bootstrap, SAPUI5, etc? I mean completely independent of the standard SharePoint UI. In this case you don’t need any of the SharePoint UI resources which SharePoint loads onto its (master) pages.

So let’s find out what JSOM actually needs and remove everything else. After some experimenting I arrived at the following minimal aspx page which includes everything you need for JSOM to connect to the SharePoint server :

 
<!DOCTYPE html>
<%@ Page language="C#" %>
<%@ Register Tagprefix="SharePoint" 
     Namespace="Microsoft.SharePoint.WebControls" 
     Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<html>
<head>
    <!-- the following 5 js files are required to use CSOM -->
    <script src="/_layouts/1033/init.js"></script>
    <script src="/_layouts/MicrosoftAjax.js"></script>
    <script src="/_layouts/sp.core.js"></script>
    <script src="/_layouts/sp.runtime.js"></script>
    <script src="/_layouts/sp.js"></script>

    <!-- include your app code -->
    <script src="app.js"></script>

</head>
<body>
	<SharePoint:FormDigest ID="FormDigest1" runat="server"></SharePoint:FormDigest>
</body>
</html>

This minimal page consists of:

  • Page language declaration
  • Define “sharepoint” tag prefix required for the FormDigest Webcontrol
  • Doctype declaration for HTML5
  • The 5 js files minimally required for CSOM
  • Include your own app code
  • FormDigest control.

When you put this aspx file on your SharePoint server (e.g. by uploading it into the Site Assets library) and request it, the server will return:

<!DOCTYPE html>
<html>
<head>
    <!-- the following 5 js files are required to use CSOM -->
    <script src="/_layouts/1033/init.js"></script>
    <script src="/_layouts/MicrosoftAjax.js"></script>
    <script src="/_layouts/sp.core.js"></script>
    <script src="/_layouts/sp.runtime.js"></script>
    <script src="/_layouts/sp.js"></script>

    <!-- include your app code -->
    <script src="app.js"></script>

</head>
<body>
    <input type="hidden" name="__REQUESTDIGEST" 
           value="0xE...[abbreviated]..35A,02 Apr 2012 08:19:47 -0000" />
</body>
</html>

RequestDigest

As you can see, the FormDigest control renders a hidden input element named “__REQUESTDIGEST” in the document body. The CSOM code will use the DOM to fetch the value of this input element and include it as an HTTP request header in the request to the SharePoint server:

X-RequestDigest: 0xE523...[abbreviated]....

Because CSOM extracts this value from a DOM element, the DOM has to be ready before you call a CSOM request.

Examples

With that, we are ready to use JSOM! Below I provide some examples which illustrate the way you can use the JSOM

You can find the full JSOM reference documentation on MSDN.

Get Web properties

The first example gets the title and description properties of a site (SP.Web class in CSOM).

// define a ClientContext for the specified SP site
var ctx = new SP.ClientContext("/teamsite");

// attach a onRequestFailed function to the client context.
ctx.add_requestFailed(function (sender, args) {
    alert('Request failed: ' + args.get_message());
});

function example () {
    var web = ctx.get_web();

    ctx.load(web);
    ctx.executeQueryAsync(function () {
        console.log("Title:       ", web.get_title());
        console.log("Description: ", web.get_description());
    });
};

window.onload = example;

Please note that:

  • ctx is defined outside of the example function, because a ClientContext is required for all examples that follow.
  • The site is explicitly passed as parameter in the ClientContext constructor, instead of using get_current() method.
  • A common request failure handler is attached to the ClientContext. This keeps the examples cleaner, by focusing on the success handler.
  • A lot of examples on the internet and even in the Microsoft documentation use a
    Function.createDelegate(this, this.onSuccessHandler) pattern by default. The goal is to ensure that the handler runs in the same context/scope as the request. This way, the handler has access to variables declared in setting up the request.
    I prefer to use the closure pattern, which I think is easier to understand.
  • The example function is called when the window.onload event fires (and the DOM is ready).

In all subsequent examples I will only provide an anonymous function which you can substitute in the boilerplate above.

Get all Web properties

You can get all properties of a ClientObject by calling get_objectData().get_properties(). Handy when you are exploring the Object Model! Here’s an example getting all properties for an SP.Web object.

function () {
    var web = ctx.get_web();

    ctx.load(web);
    ctx.executeQueryAsync(function () {
        properties = web.get_objectData().get_properties();

        console.log(properties);
    });
};

Set Web property

When this example runs, the description property of the web is changed, including a timestamp. This way you can more easily see the effect.

function () {
    var web = ctx.get_web();

    web.set_description("This web description property is updated on: " + new Date());
    web.update();

    ctx.executeQueryAsync(function () {
        console.log('Description is updated: ' + web.get_description())
    });
};

Get List items with ctx.load

If you use load method, the items will be return as a Collection. These require an enumerator to loop:

function () {
    var web = ctx.get_web(),
        list = web.get_lists().getByTitle('Contacts'),
        items = list.getItems('');

    ctx.load(items);
    ctx.executeQueryAsync(function () {
        var listEnumerator = items.getEnumerator();
        while (listEnumerator.moveNext()) {
            var item = listEnumerator.get_current();
            console.log("Contact: ", item.get_fieldValues())
        }
    })
};

Get List items with ctx.loadQuery

Alternatively, you can use loadQuery method. Please note that the return value is stored in a var for later processing in the success handler. Now you can use a forEach or for loop to run through the results.

function () {
    var web = ctx.get_web(),
        list = web.get_lists().getByTitle('Contacts'),
        items = list.getItems('');

    var contacts = ctx.loadQuery(items);

    ctx.executeQueryAsync(function () {
        contacts.forEach(function(contact) {
            console.log("Contact: ", contact.get_fieldValues())
        })

        // You can also use a for loop
        for (var i = 0, len = contacts.length; i < len; i++) {
            console.log("Contact: ", contacts[i].get_fieldValues())
        }
    })
};

Use method chaining

Instead of defining variables at intermediary steps of the object ‘path’, you can also chain methods together:

function () {
    var items = ctx
            .get_web()
            .get_lists()
            .getByTitle('Contacts')
            .getItems('');

    var contacts = ctx.loadQuery(items);

    ctx.executeQueryAsync(function () {
        contacts.forEach(function (contact) {
            console.log("Contact: ", contact.get_fieldValues())
        })
    })
};

Create a List item

Create a new item by call list.addItem. Set the field vales and call item.update. This will create the item on the server during the query.

function () {
    var list = ctx
            .get_web()
            .get_lists()
            .getByTitle('Contacts');

    // create a new item on the list
    var contact = list.addItem(new SP.ListItemCreationInformation());
    // You may even leave out the ListItemCreationInformation, 
    // if you don't set any of its properties:
    // var contact = list.addItem();
    
    contact.set_item("Title", "Peel"); // 'Title' is the internal name for 'Last Name'
    contact.set_item("FirstName", "Emma");

    // ensure that contact is saved during the query
    contact.update();

    ctx.executeQueryAsync(function () {
        console.log("Id of new contact: ", contact.get_id()); 
    })
};

Update a List item

Uses item.set_item() method.

function () {
    var id = 415,
        item = ctx
            .get_web()
            .get_lists()
            .getByTitle('Contacts')
            .getItemById(id);

    // Change business phone number.
    // Internal name is WorkPhone
    item.set_item("WorkPhone", "+31 20 123456");

    // ensure that contact is saved during the query
    item.update();

    ctx.executeQueryAsync(function () {
        console.log("New value: ", item.get_item("WorkPhone"));
    })
};

Delete a List item

Use item.deleteObject() to signal an item for deletion.

function () {
    var id = 414, 
        item = ctx
            .get_web()
            .get_lists()
            .getByTitle('Contacts')
            .getItemById(id);

    // delete the selected item
    item.deleteObject();

    ctx.executeQueryAsync(function () {
        console.log("Item deleted")
    })
};

Get List fields

Use list.get_fields() if you want to inspect the List field (columns) definitions.

function () {

    var fields = ctx.loadQuery(
            ctx
            .get_web()
            .get_lists()
            .getByTitle('Contacts')
            .get_fields()
    );

    ctx.executeQueryAsync(function () {
        fields.forEach(function (field, index) {
            var internalName = field.get_internalName(),
                title = field.get_title(),
                hidden = field.get_hidden();

            console.log('Field ', index, ':');
            console.log('Title: ', title);
            console.log('InternalName: ', internalName);
            console.log('Hidden: ', hidden);            
        })
    })
};

Get List views

This final example shows how to fetch the views for a list.

function () {
    var views = ctx.loadQuery(
        ctx.get_web().get_lists().getByTitle('Tasks').get_views()
    );

    ctx.executeQueryAsync(function () {
        views.forEach(function (view) {
            console.log(view.get_title())
        })
    })
};

Hopefully this helps you getting started with building HTML5 web applications using the SharePoint JavaScript CSOM. Let me know if you have suggestions/tips.

Thanks for reading!

25 thoughts on “Using SharePoint CSOM in HTML5 apps

  1. Thanks for a such a nice tutorial. How do you embed this page into your site? Is this just a page in Site Pages ?

    • Thanks, Anatoly. Indeed: you can just upload the .aspx file into the Site Assets library (or any other regular doc library). I have edited the post to make that more clear.

  2. Fantastic Luc! Thank you so much for this article. It was exactly what I needed and works just great! Well done.

    • Hi Rainer,

      That’s a great demo you have there: Twitter Bootstrap meets KendoUI meets SharePoint.

      Next stop: Metro app dev on Windows 8? 🙂

      • Not sure yet. Need to make myself familiar with all that odd left to right scrolling ;-).

        Rainer

  3. I wanted to use the ModalDiaglog, in order to use this you will need to include these two script tags

    You will also need to include the css for the modal dialog as well (depending on your requirements).

  4. Hello Luc,
    Thanks for a great set of examples. I’d like to add my two cents by giving heads-up not to use global variable named exactly ‘ctx’ because a similar global would be very useful when working in context of list views and forms. Can you make minor edits to change that to myCtx or something like that?

    • Hi Alexy,

      Thanks for your comment!

      Completely agree with you on being carefull with global vars. In general one should avoid them altogether by e.g. using module pattern. I didn’t want to add this complexity to the example code. But in a real app, you should!

  5. If I open a fresh browser session, the first attempt to perform a list query always fails, with this error: “The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again”

    Refreshing the page then makes the query work fine. How can I do to make this work in a fresh session?

  6. I’m new to SharePoint and Javascript. Using CSOM, I’m trying to get selected list items, for each selected item query another list and if exists, Update selected List item… else Create List item then Update selected list item. However, I think I’m running into issue of running multiple executeQueryAsync… given the name, it’s asynchronous. Much appreciated if you could tell me how I could do something like this?

  7. Help.
    using this path am unable to load the js libraries. in “function example” i place an alert function whicch get called but after that nothing happens which suggests that libraries are not getting loaded.

    • Are you using standard installation of SP2010? I suggest to check why the libraries don’t load (not authorized, not found, …) using e.g. Chrome developer tools, fiddler or similar tools.

  8. When I run this code ‘clientContext = new SP.ClientContext();’ then I get the error SP.PageContextInfo.get_$g_0(…) is undefined.

    Anyone know how to fix this XD?

  9. Pingback: SharePoint 2013 Using CSOM JavaScript | Share your knowledge

  10. This works perfectly in SP 2013, but the files are kept in a different place. I assume that will be the same for SharePoint Online. Here are the SP13 paths:
    /_layouts/15/init.js
    /_layouts/15/MicrosoftAjax.js
    /_layouts/15/sp.core.js
    /_layouts/15/SP.Runtime.js
    /_layouts/15/SP.js

Leave a comment