To understand the code examples in this article, you need to be familiar with some important architectural aspects of JSOM. With that foundation, you can examine some examples of CRUD operations, starting with simple reads before proceeding to creating, updating and deleting. Finally, you’ll find a discussion on interacting with SharePoint security.
You need to know the following two important things about JSOM before getting started with it:
Authentication: JSOM provides no ability to impersonate or login. All code executes within the user context established by the browser. So your JSOM code will run as whomever you’re logged in to SharePoint as in the browser. There’s nothing you can do about that.
Context: JSOM code requires a SharePoint context. It must be run on a page that has been downloaded from a SharePoint site, so it is not a candidate for running on non-SharePoint sites or apps, except SharePoint-hosted apps.
This chapter will focus on the capabilities of JSOM regardless of whether it originated in a farm solution, a sandbox solution or an app. The focus here is learning how to work with JSOM in preparation for layering in the situation-specific elements later.
MicrosoftAjax.js – typically loaded via ScriptResource.axd
SP.Runtime.js – loaded from the LAYOUTS folder
SP.JS – also loaded from the LAYOUTS folder
These libraries, together, allow us to work with JSOM and interact with the SharePoint server and the client UI. We don’t typically inspect or work directly inside these files, they are just prerequisites for our JSOM code. In fact, as with any other default, out-of-the-box SharePoint file, we don’t want to crack these open and edit them directly.
There is some messiness we need to deal with, though. It isn’t all entirely abstracted away from us. But let’s get through a little bit more architecture first.
One of the items that IS abstracted away is the plumbing aspect of actually calling back into SharePoint. We don’t need to worry about packaging the data, sending it up the wire, waiting for a response and so on. All of that is handled for us, which a lot of developers find nice. The call back to SharePoint goes to a REST service named client.svc and is done asynchronously – meaning that the call is made but we don’t wait for a response. Instead, once the call is sent up, our code continues running, and when the response comes back from the server, one of two callback functions we registered will be called, depending on whether the call succeeded or failed on the server. The important point here is the asynchronous nature of JSOM.
The next core architectural concept to tackle is Client Context. Server-side code often revolves around the idea of context and specifically the SPContext object; similarly client-side code revolves around the Client Context – perhaps even more so than on the server-side Context.
Client Context in JSOM is our connection back to SharePoint; it is the center of our world from which all things originate. Establishing the Client Context is the starting point of all our code.
To get a client context in JSOM, you have two options: new or get_current. The former, new, is going to create a new context for the web whose relative URL we specify as a parameter – or for the current web if we don’t supply a parameter. The latter, get_current, returns the current context for the page, creating it first if it does not exist already. Several examples of getting a context object, along with explanatory comments, are shown in SNIPPET 1.
The first line in this function establishes our context. Don’t worry about not understanding the details of the code at this point. For now, I want you just to look at the lines of code as work that needs to happen.
next line, which gets the collection of lists in our current web. Same, too, with the next line, which gets the list we are looking for. It is only when the browser reads and executes final line, shown in FIGURE 1 that things happen and get interesting. The function executeQueryAsync does not get added to the batch, but does cause the batch to get sent to the server for processing.
SNIPPET 2 shows a full example of a JSOM method, including the executeQueryAsync call, with comments to help you understand what is happening.
As the batch hits the wire to go up to the server, any code following the executeQueryAsynch call begins processing immediately. It is an asynchronous call; it does not wait for the batch to return. As part of the executeQueryAsynch call, we register two callback functions: one if the batch processes successfully on the server, and one if it encounters an unhandled error.
While all this is happening on the client, the server receives the batch (on the client.svc REST endpoint), rips open the XML payload, and begins processing it. All of the work is done by the regular server-side object model interacting with the SharePoint databases as required.
If the server processes the batch with no unhandled exceptions, the JSON results object is sent back to the client with an indication that everything ran OK, and so the success callback is called. If, however, an unhandled exception occurred while the server was processing the batch, the results go back to the client (again as JSON) and call the failure callback.
That is, in a nutshell, how the JSOM processes a batch of commands. While we don’t deal with many of the plumbing aspects of adding commands to the batch and handling the results to get things to the right callback, it is nonetheless important to understand this process. Arguably, this is the most difficult part of JSOM, which is unfortunate as it impacts everything we do in JSOM.
To close out this discussion of the batching process, I’ll wrap up with the reason the batching model is used: It’s all about performance. Sending commands over the wire is the slowest part of client-server interaction. If our client-side code hit the wire with every command issued and had a corresponding response from the server, performance would be horrible. The amount of overhead involved would bring our application to a crawl. By reducing the chattiness of our application, and therefore the number of times traffic hits the wire, we can improve performance.
The ability to include the try/catch/finally information as part of the batch would be better; essentially saying: Try these things up on the server. If an error occurs, do these things, then no matter what, do these things. NOW hit the wire again and come back down to the client and tell me what happened.
Fortunately, that’s exactly what we get in JSOM.
SNIPPET 3 shows a full example of exception handling in JSOM. We start by getting our client context, as we talked about previously. Then, on line 3, we create an instance of an ExceptionHandlingScope object and call its StartScope method (line 4) to indicate that we’re beginning an exception handing block. Next we need to indicate that we’re beginning our try block. We do that by calling the startTry method on our scope (line 5). Now we can do whatever code we want that could cause an error. In this case, I’m trying to get a list that doesn’t exist (line 8). To signify the end of the try block and clean things up, we dispose of our try object on line 9.
Next we need to specify the steps we want to happen if an error happens in the try. We do this in a similar manner by instantiating and disposing of a catch block (line 11 to start the block, line 13 to close the catch block). Inside the block, we indicate the steps to take on the server if an error happened anywhere in the try block.
The finally part of our exception handling happens exactly the same as the try and the catch. Start the scope (line 15), indicate what you want to have happen up on the server regardless of whether an error occurs (line 16), and then dispose of the finally block (line 17).
The last step is to simply clean up the exception scope (line 19) and then call executeQueryAsync (line 20) to commit the whole batch – try/catch/finally and all – up to the server to be processed.
That’s how we do exception handling in JSOM to maintain the integrity of our batch and keep our application from being excessively chatty, even if something goes wrong.
Even if we properly set up our server-side error handling as shown in SNIPPET 3, it may still be necessary to be able to detect that the error happened on the server when things get back down to the client. Fortunately, it’s both possible and easy to do so. Remember, though, that the error has already happened and been dealt with on the server as part of our batch. Most of the time, this is sort of informational only. You may or may not want to tell the user about the error.
The first important thing to know is that if an error occurs and is handled as part of our batch, it is not considered a failed batch when things get back down to the client. The onSuccess handler is still called. The onFail callback is only called if an unhandled exception occurs on the server within our batch.
SNIPPET 4 shows an example of how to detect from the client that an error happened and was handled on the server as part of our batch. Inside the onSuccess callback, we can check the ExceptionHandlingScope object we set up back in SNIPPET 3 to see whether an error happened and was handled. Specifically we use the get_hasException function to check the HasException property of the scope.
If that returns true, we know an error happened and was handled on the server. If it returns false, no error happened. Remember, we wouldn’t even be in the onSuccess callback if an exception happened on the server and wasn’t handled.
Once we know that an error occurred, we can take whatever client-side actions we want to take. We can get information about the error by checking the ErrorMessage property of the ExceptionHandlingScope object via the get_errorMessage function, as shown in SNIPPET 4, line 7.
SNIPPET 5 shows our first example, which we’ll go through in detail. Just like some things we’ve seen already, we start with getting our context in line 2. In this example, we are instantiating a new context object but not supplying a parameter, so we’ll get a connection to the current web. Once we have that, we can instantiate the objects we’re going to deal with, in this case the web and the lists collection for the web.
One thing unique to client-side programming in SharePoint is the need to fill up our objects so that their properties get populated with values. This is distinctly different from the server-side object model in which merely instantiating or retrieving an object causes its properties to be populated.
We populate our objects by passing the object we wish to fill up into the Load method of the client context object. You can see an example of this in the commented out line 6 of SNIPPET 5. The line is commented out because of an important detail about loading up objects that we’ll discuss next: If this line were not commented out and so executed, most of the properties on that object would be filled with their values when the batch is committed. That likely isn’t what we want.
Traversing the wire is the most expensive part of our operations from a time and performance perspective. To help reduce the impact of this factor, we want to avoid retrieving any data that we do not need. This makes perfect sense. If we’re not going to use a piece of data: Why bother retrieving it and pulling it down? Applied to objects and their properties, this means that we only want to populate the properties we’re going to work with.
This is the important detail about the Load statement. We reduce the amount of data retrieved by specifying which properties we want filled up as part of the Load statement. In line 4 of SNIPPET 5, we’re loading our Web object, but just the Title and ServerRelativeUrl properties because that’s all we’re going to work with. Notice the syntax on line 4. We specify the field names as a comma-delimited series of individual strings, each enclosed in either single or double quotes.
This syntax is used when we are filling up a single object. If you look at the code in line 7, you’ll see a slightly different syntax: the use of the word Include and then the names of the properties we want filled up, in this case Title and Id. This syntax is used only for loading up a collection of other objects (here, lists), but other object collections, as well. This syntax specifies which properties of the items in the collection will be populated.
Finally, we need to commit our batch by calling executeQueryAsync on line 8. This sends our commands up the wire to the SharePoint server. If no errors happen while the commands are executing on the server, the response will come back to the OnSucceed callback we registered in the executeQueryAsync call earlier.
In our success callback, we can begin to work with the objects we instantiated and the properties we asked to have filled up with their values. In lines 12-14 of SNIPPET 5, you can see that I’m accessing the ServerRelativeUrl and Title properties of my Web object, as well as the Count property of the Lists collection.
So we need to fill up the properties of our objects before we work with them, and we do this with the Load function, as we’ve seen. But what happens if we don’t? If we try to work with a property that has not been populated with a value, we will get a PropertyOrFieldNotInitializedException.
Get used to seeing this. Even if you’ve worked with JSOM a lot, you will see this error. Fortunately, the fix is easy. You just need to make sure you are loading every property you try to work with.
Unfortunately there’s more to it than just filling up properties in the simple manner we’ve seen, and this it makes things a little more complicated in some cases. When we fill up an object via the Load function, it’s reasonable to expect that if we don’t limit the properties that are filled up, they will ALL be populated. But things don’t work that way. Some properties are not filled up when you just call Load, unless you specify which properties you want populated. In general, when you do not specify which properties to load, only the scalar properties are filled up.
Scalar properties are any properties that return values of one of these data types (or an array of one of these data types):
Properties that return other types of values, specifically collections and JSOM client objects, must be explicitly loaded. This is why, in SNIPPET 5, we had to explicitly call Load on line 7 to populate the lists collection, even though it is a property of the web object that we already loaded. True, in this snippet, we limited the properties of the web object that were loaded, But even if we had simply called currCtx.Load(myWeb) to load all properties of the web object, the lists collection would not be populated because it is a collection of JSOM client objects, not a scalar property.
Because every good rule needs an exception, some scalar properties are not filled up, even if we just accept the filling up of only the default properties by not specifying any properties to load. TABLE 1 shows which of the scalar properties for various objects are not filled up by default and must be explicitly requested if you need them.
You really shouldn’t look at this as a problem because you really ought to be specifying exactly which properties you are going to work with later--no more, no less. This would mean that all the properties you need – regardless of their type – are properly populated when you need them. If you take that approach, then this problem vanishes.
You need to understand the details of loading objects, though, because you need to remember that collection and non-scalar properties and even certain scalar properties must be explicitly requested.
That wraps up the general information you need to know about reading data from SharePoint.
So far, we’ve seen reading data from SharePoint, but we’ve stopped basically at the web or list level. A far more common scenario is to continue further down and start working with list items. One of the most common approaches for getting to one or more list items is the same approach we’d use in server-side code – a straightforward Collaborative Application Markup Language (CAML) Query.
In SNIPPET 6, we start by getting our context and the list that contains the items we want to work with – here an Announcements list simply called News. In line 5, we create a new object, one we haven’t seen before but that ought to be familiar to you - SP.CamlQuery. Like its server-side cousin, this object allows us to specify the CAML query that expresses the criteria used to define the items we want to retrieve; in this case, items that have a Title value of xyz. The actual XML that makes up the CAML query is on lines 6-11 in SNIPPET 6. This is a pretty simple CAML query, which as I said, filters on the Title column. If you look at this CAML statement, it should look familiar to anyone who has worked with its server-side equivalent. The syntax is slightly different, but not disconcertingly so – it’s really just the addition of the <View> and <Query> elements.
Next we pass the CamlQuery object into the getItems method of the targetList object and store the results in the listItems variable (line 12). On line 13 we load the listItems object (filling up only the Title property) and on line 14 commit our batch to the server.
When the batch returns from the server, hopefully to our success method, we can start to work with the items in the collection of results. In this approach, we do that by getting an enumerator on line 18 and iterating through the collection one item at a time in the while loop beginning on line 19. You can see how we access the individual fields on a listItem by using the get_item method and passing in the InternalName of the field whose value we wish to retrieve. This will work for any field type, though for some like Hyperlink fields, you need to go a little further to get meaningful values.
In SNIPPET 6, we filled up the listItems variable with the results of the CAML query and it held a collection of listItem objects that we could loop through via the enumerator. This is called an in-place load. Another approach, which honestly gives us the same results but may be more familiar to some developers, is to do what’s called a queryable load, as seen in SNIPPET 7. In this approach, the call to fill up the listItems object uses the loadQuery function (line 11) instead of the Load function. The results of that call are stored in a separate variable – results – on line 11.
After committing our batch on line 12 and returning back into the onQueryableLoadSucceed, what we get back is not a listItemCollection object as we did before, but rather an IEnumerable collection of listItem objects. What that means is that in the success callback, we can loop through the results a little more easily – using a simple for loop instead of getting the enumerator manually and looping through the collection with it. Again, not a huge difference, but one that may be more comfortable for some developers. There are no performance benefits to one approach over the other.
The only significant, noticeable difference between the two methods is related to object identity. In the case of an in-place load, object identity is maintained by the client context object. What this means is that if you query the server via an in-place load to retrieve an object, update some properties of that object, and then re query the server to re-load the same object, the properties that you modified on the client are maintained at their updated values. Context understands that these are the same objects you retrieved and worked with before and so it merges the two instances into a single identity.
This is not the case with queryable loads. In a queryable load, object identity is not maintained so the collection of objects retrieved from the server will have only the values the server has, not anything that may have been previously edited on the client but not yet committed to the server.
From a real-world point of view, what this boils down to is a general guideline: Use an in-place load for objects you will be updating and a queryable load for objects that you will just be reading. That’s just a general guideline and certainly not one cast in stone. If you are more familiar with one or the other of the approaches, there is likely not a meaningful reason to not just use that one approach all the time.
The next operation we need to take a look at is the creation of SharePoint constructs – lists, listitems, etc. This operation is different from its server-side equivalent in that anything creatable via JSOM has a corresponding CreationInformation object. Creating something entails instantiating a CreationInformation object, filling its properties, adding it to the parent collection, and then committing the batch to the server. The full list of creatable objects can be determined from the available CreationInformation objects:
SNIPPET 8 shows an example of creating a List. The rest of the creatable objects are dealt with similarly.
In SNIPPET 8, you can see the use of the ListCreationInformtion object. We create an instance of the object and set a few of its properties – specifically the templateType, in this case an Announcements list, the title, and quickLaunchOption. We then pass the ListCreationInformation
object in to the add function on the lists collection of the current web and commit our batch. That’s all it takes to create a list using JSOM.
Before we can update an item, any item, we need to retrieve it. Typically we need to retrieve the target item’s parent container first, but in a few cases we get the item directly. Depending on what type of item we’re trying to update, we’ll get a different container:
- For webs, we get the Webs property of the parent site collection or the web property of context
- For Lists, we get the Lists property of the parent web
- For list items, we get either the items collection of the parent List, use a CAML query like we saw in SNIPPET 6 and SNIPPET 7, or use a function of the parent List object to get the item directly, which is what we’ll see in SNIPPET 9.
- And so on – other items are going to be similar
Updating list items
In SNIPPET 9, we have code that goes through and gets the Announcements list. This should look familiar as we’ve seen similar code several times already. Next we retrieve the item we wish to work with. On LINE 6 we’re using the getItemById function of the list object and passing in the ItemId.
That works fine for simple value field types like text and numbers. For complex field types, we need to use the specific field value object for the field type. Complex field types include:
So, for example, setting a URL field - which consists of two parts, the hyperlink value and the description, or text of the hyperlink - requires the use of a FieldUrlValue object.
An example of this object is shown in lines 8-11 of SNIPPET
9. Usage of the other field value
objects is similar to the FieldUrlValue object:
- Create the field value object (SNIPPET 9, line 8)
- Set its properties (SNIPPET 9, lines 9 & 10)
- Use the set_item function to update the item (SNIPPET 9,
Updating other objects
As before, after setting the properties, we simply need to update and then commit the batch as seen on lines 12 and 14 of SNIPPET 9.
One final thing to know whenever you are trying to change something in SharePoint via JSOM - you must have a FormDigest control on your page. It can be directly on the ASPX page, but is more commonly included via the MasterPage. FormDigest is a cryptographic protection against script replay attacks. For regular JSOM work, just make sure it’s available – again, typically from the Master Page. An example of a FormDigest tag is shown in SNIPPET 11.
Deleting objects is pretty straightforward: Simply retrieve the object, and then call its deleteObject method. SNIPPET 12 shows several examples of deleting various objects.
One of the nice things about JSOM in SharePoint 2013 is the ability to interact with the security infrastructure of SharePoint. Even if you never use this capability to manage security – setting permissions, managing users and groups, etc. – the ability to check security asynchronously and present or update the UI accordingly is a huge advantage.
Looking in SNIPPET 13 at the ability to check security, we see our standard code for getting context, and in this case, getting our web object. Next we need to load up the properties on our web object (line 4). Following best practices, and also because the effectiveBasePermissions property isn’t filled by default (see TABLE 1 earlier in this chapter), we specify that we only want the permission information. Then, as always, we post our batch back to the server.
In our success callback, we specify the permissions we want to check for (Edit List Items or Full Permissions), storing them in a variable, perms. Notice that we’re using the SP.PermissionKind enumeration in line 8 to specify the rights we want to check.
Then we use the get_effectiveBasePermissions function on our web object, which returns an SP.BasePermissions object that includes a has function. We use the has function to check whether the current user has the permissions we specify in the parameter. We can now simply react according to whether the user has the permissions we’ve specified. In a real application, we would do something besides popping up an alert box, such as hiding or showing UI elements depending on whether the user has the permissions for which we checked.
In addition to Web, the List and ListItem objects also have a get_effectiveBasePermissions function to allow us to check permissions at those levels. While Folder is a securable object in SharePoint, there is no direct way to work with Folder-level permissions in JSOM. Similar to the server-side object model, the way to do this is to get the folder object as a ListItem – using one of the methods we saw earlier for retrieving List Items – either a CAML query or getting it by ID. Once you have the List Item that represents the folder, you can work with the permissions that way.
SNIPPETS 14 through 17 show sample code for some common security programming operations:
- Getting SharePoint groups
- Adding a user to a SharePoint group
- Removing a user from a SharePoint group
- Creating a new permission level, or role
The code is commented and pretty straightforward, so I won’t walk you through each snippet.
Security in apps
Security programming, and in fact security in general, is very different in apps when compared to regular SharePoint sites. The app security model is focused more on app and user-specific permissions as opposed to groups. In an App Web, it is possible to add user permissions directly or add new group permissions. However, it is not possible to create or delete groups, or add users to an existing group, which severely limits the possibilities for managing security in an App. I hope that this is a scenario we see improving as the App Model matures.
To help clarify what works inside an App, TABLE 4 breaks out some of the common security programming scenarios and shows which work inside the App Web and which do not.