Introduction

When working with the SharePoint API via Javascript it is essential to work with the Javascript Object Model (JSOM). JSOM is the use of JavaScript with the SharePoint client side API which allows you to work with SharePoint without deploying code to the server itself. Due to SP Online relying on sand-boxed approaches, JSOM (or CSOM) is typically what would be used for code.

JSOM has a few key elements to keep in mind:

  • Work is done through a ClientContext object which acts as your window to operating with SharePoint. These are tied to a specific SP site and can be instantiated to the current site as well as a different site than the user is on.
  • When working with methods in the context to get such things as items or lists you will not be able to read the properties until the object is loaded. Likewise, operations are not executed until explicitly told to by calling ClientContext.executeQueryAsync.
  • The context works somewhat like a queue, operations are not completed until an execute is called. Each execute represents a single call to the server. It is good practice to avoid calling execute until necessary.

Table of Contents

Note that some code needs to be examined prior to running to substitute proper values where needed. I.e. Adding a field to a list may require a pre-existing list and adjusting the script to point to that list for the example to work.


General JSOM

These are general examples on some common snippets or patterns when working with JSOM objects

Enumerating Through Collections

  • Object must support getEnumerator function
var enumerator = yourObjCollection.getEnumerator();
		
while (enumerator.moveNext()) {
	var curObj = enumerator.get_current();
	//i.e. alert(curItem.get_title());
}

Targeting Current Web

//Targets the SPWeb the user is currently browsing
var ctx = new SP.ClientContext.get_current();

Targeting Specific Web

//Targets the SPWeb via URL (Server Relative or Absolute)
var ctx = new SP.ClientContext("/sites/yoursite");
//Use '/' for top level SPWeb at root of domain
var rootDomainWeb = new SP.ClientContext("/");
//For the root web of the current site collection leverage _spPageContextInfo
var curSiteColRootCtx = new SP.ClientContext(_spPageContextInfo.siteServerRelativeUrl);

Fields

Creating (Basic)

var ctx = new SP.ClientContext.get_current();
var curWeb = ctx.get_web();
     
var myList = curWeb.get_lists().getByTitle('MyList');

ctx.load(myList);
 
ctx.executeQueryAsync(
    function(){ 
		//Create the field
		var fields = myList.get_fields()
		fields.addFieldAsXml('<Field ID="{c10f042e-ab13-435c-ab93-9885f0d48d02}" Name="myInternalName" DisplayName="A Multi User Column" Group="GroupName" Type="UserMulti" Mult="TRUE"></Field>', true, SP.AddFieldOptions.addToDefaultContentType)
		ctx.executeQueryAsync(
			function (){ alert('Created field!'); },
			function (){ alert('Error: ' + args.get_message()); } 
		);
	}, 
    function(sender, args){ alert('Error: ' + args.get_message()); }
);

Getting (Person or Group)

  • Person or Group (multiple OR single)
var itemId = 1;
var ctx = new SP.ClientContext.get_current();
var customList = ctx.get_web().get_lists().getByTitle('CustomList');
var listItem = customList.getItemById(itemId);
 
ctx.load(listItem);
ctx.executeQueryAsync(
	function(){ 
		//People Picker Multi OR Single value
		var usrOutput = [];
		var usrGrps = listItem.get_item("PersonOrGroup");
		//Multi fields return arrays, singles do not. Unify to produce array in either case.
		var userItems = [].concat( usrGrps );

		userItems.forEach(function(userOrGroup){
			usrOutput.push("Name: " + userOrGroup.get_lookupValue() + "\nID: " + userOrGroup.get_lookupId() + "\nEmail: " + userOrGroup.get_email());
		});
		
		alert(usrOutput.join("\n\n")); 
	}, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Getting (Managed Metadata)

var itemId = 1;
var ctx = new SP.ClientContext.get_current();
var customList = ctx.get_web().get_lists().getByTitle('CustomList');
var listItem = customList.getItemById(itemId);
 
ctx.load(listItem);
 
ctx.executeQueryAsync(
	function(){ 
		//MMS Multi Value 
		var mmsValues = [];
		var managedMeta = listItem.get_item("ManagedMetadata");
		var managedMetaSingle = listItem.get_item("ManagedSingle");
		
		//You can detect if a field is single with the following:
		//if(managedMetaSingle instanceof SP.Taxonomy.TaxonomyFieldValue)
		
		//Read multiple select taxonomy field
		var mmsEnum = managedMeta.getEnumerator();
		
		while (mmsEnum.moveNext()) {
			var mmsItem = mmsEnum.get_current();
			mmsValues.push('Label: ' + mmsItem.get_label() + ' Guid: ' + mmsItem.get_termGuid());
		}
		
		//Read single taxonomy field
		mmsValues.push('Label: ' + managedMetaSingle.get_label() + ' Guid: ' + managedMetaSingle.get_termGuid());
		
		alert(mmsValues.join("\n\n"));
	}, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

List Items

Creating (basic)

var ctx = new SP.ClientContext.get_current();
var customList = ctx.get_web().get_lists().getByTitle('CustomList');
	
var itemCreateInfo = new SP.ListItemCreationInformation();
var listItem = customList.addItem(itemCreateInfo);
listItem.set_item('Title', 'My Title');
listItem.update();

ctx.load(listItem);
ctx.executeQueryAsync(
	function(){ alert('Item created: ' + listItem.get_id()); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Creating (Advanced – All Field Types)

  • Single Line of Text
  • Multiple Lines of Text
  • Choice
  • Number and Currency
  • Date and Time
  • Yes/No
  • Person or Group
  • Hyperlink or Picture
  • Lookup
  • Managed Metadata (single)
var ctx = new SP.ClientContext.get_current();
var customList = ctx.get_web().get_lists().getByTitle('CustomList');
	
var itemCreateInfo = new SP.ListItemCreationInformation();
var listItem = customList.addItem(itemCreateInfo);
//Simple values
listItem.set_item('Title', 'My Title');
listItem.set_item('SingleLineOfText', 'Single Line of Text');
listItem.set_item('MultipleLinesOfText', 'Multiple <br/><br/>lines');
listItem.set_item('Choice', 'Choice 2');
listItem.set_item('Number', '10000');
listItem.set_item('Currency', '10000.55');
listItem.set_item('DateAndTime', new Date());
listItem.set_item('YesNo', false); //'No', 'False', 0, 'Yes', 'True', 1, true, false (all work)
//Users are added via their integer ID on the current site
listItem.set_item('PersonOrGroup', _spPageContextInfo.userId);
//URL is added by setting a FieldUrlValue object
var urlVal = new SP.FieldUrlValue();
urlVal.set_url("http://www.migee.com");
urlVal.set_description("Description of Link");
listItem.set_item('HyperlinkOrPicture', urlVal);
//Lookup column is set to the item ID in the list the lookup points to
listItem.set_item('LookupToSelfOnTitle', 1); 
//For managed metadata use the term ID from MMS
listItem.set_item('ManagedMetadata', "caa6bb9c-a7a1-48af-89e8-39cd77acdcff");

//Update and load new item
listItem.update();
ctx.load(listItem);
ctx.executeQueryAsync(
	function(){ console.log("added"); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Getting (by ID)

var itemId = 1;
var ctx = new SP.ClientContext.get_current();
var customList = ctx.get_web().get_lists().getByTitle('CustomList');
var listItem = customList.getItemById(itemId);

ctx.load(listItem);

ctx.executeQueryAsync(
	function(){ 
		alert('Item title: ' + listItem.get_item("Title")); 
	}, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Getting (by CAML Query)

var ctx = new SP.ClientContext.get_current();
var customList = ctx.get_web().get_lists().getByTitle('CustomList');

var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><Query><Where><Geq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>1</Value></Geq></Where></Query><RowLimit>10</RowLimit></View>');
var listItemCol = customList.getItems(camlQuery);

ctx.load(listItemCol);

ctx.executeQueryAsync(	
	function(){ 
		var listItems = [];
		var listEnum = listItemCol.getEnumerator();
		
		while (listEnum.moveNext()) {
			var item = listEnum.get_current();
			listItems.push('ID: ' + item.get_id() + ' Title: ' + item.get_item('Title'));
		}
		
		alert(listItems.join("\n")); 
	}, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Updating

var itemId = 1;
var ctx = new SP.ClientContext.get_current();
var customList = ctx.get_web().get_lists().getByTitle('CustomList');
var listItem = customList.getItemById(itemId);
listItem.set_item('Title', 'New Title');
listItem.update();

ctx.executeQueryAsync(
	function(){ alert('Item updated'); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Deleting

var itemId = 1;
var ctx = new SP.ClientContext.get_current();
var customList = ctx.get_web().get_lists().getByTitle('CustomList');
var listItem = customList.getItemById(itemId);
listItem.deleteObject();

ctx.executeQueryAsync(
	function(){ alert('Item deleted: ' + itemId); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Lists

Creating

var ctx = new SP.ClientContext.get_current();
var curWeb = ctx.get_web();
	
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title('My Custom List');
//To view all list types, view the SP.ListTemplateType enumeration on a SharePoint Website
listCreationInfo.set_templateType(SP.ListTemplateType.genericList);

var myList = curWeb.get_lists().add(listCreationInfo);
ctx.load(myList);

ctx.executeQueryAsync(
	function(){ alert('List created: ' + myList.get_id().toString()); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Updating

var ctx = new SP.ClientContext.get_current();
var curWeb = ctx.get_web();
	
var myList = curWeb.get_lists().getByTitle('My Custom List');
myList.set_title("My Updated Custom List");

myList.update();
ctx.load(myList);

ctx.executeQueryAsync(
	function(){ alert('List name updated!'); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Deleting

var ctx = new SP.ClientContext.get_current();
var curWeb = ctx.get_web();
	
var myList = curWeb.get_lists().getByTitle('My Custom List');
myList.deleteObject();

ctx.executeQueryAsync(
	function(){ alert('List deleted!'); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Web Scope

Read Group Users

//Often helpful to use '_spPageContextInfo.webTitle' OR web variable and use get_title() here for groups prefixed with web title
var groupName = "Approvers" 
//Groups are usually inherited, for this example we grab the root web using the OOTB spPageContextInfo helper
var ctx = new SP.ClientContext(_spPageContextInfo.siteServerRelativeUrl);
var siteColWeb = ctx.get_web();

//Get groups, then query for specific group by name
var collGroup = siteColWeb.get_siteGroups();
//Use the helper
var oGroup = collGroup.getByName(groupName); 
var collUser = oGroup.get_users();
ctx.load(collUser);

ctx.executeQueryAsync(
	function(){
		 console.log("Query success");
		var userInfo = '';
	 
		var userEnumerator = collUser.getEnumerator();
		while (userEnumerator.moveNext()) {
			var oUser = userEnumerator.get_current();
			userInfo += '\nUser: ' + oUser.get_title() + 
				'\nID: ' + oUser.get_id() + 
				'\nEmail: ' + oUser.get_email() + 
				'\nLogin Name: ' + oUser.get_loginName() + "<br/></br/>";
		}
		
		alert("Users in '" + groupName +"' group: " + userInfo);
	}, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Permission Check

var ctx = new SP.ClientContext.get_current();
var curWeb = ctx.get_web();

//In this example we check to see if user can delete list items on the current web. 
//Output SP.PermissionKind for all possible permissions. Not all pertain to Web scope!
var basePerm = new SP.BasePermissions();
basePerm.set(SP.PermissionKind.deleteListItems);
var result = curWeb.doesUserHavePermissions(basePerm);

ctx.executeQueryAsync(
	function(){ alert(result.get_value() ? "Has permissions" : "Does not have permissions") }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Create Property Bag Item

var ctx = new SP.ClientContext.get_current();
var curWeb = ctx.get_web();
	
var propBag = curWeb.get_allProperties();
propBag.set_item("MyProp", "12345");
curWeb.update();

ctx.executeQueryAsync(
	function(){ alert('Property Bag Value Added!'); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Read Property Bag

var ctx = new SP.ClientContext.get_current();
var curWeb = ctx.get_web();
	
var propBag = curWeb.get_allProperties();
ctx.load(propBag);

ctx.executeQueryAsync(
	function(){ alert('Property Bag Key "MyProp" is set to "' + propBag.get_item("MyProp") + '"!'); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Update Property Bag Item

Delete Property Bag Item

var ctx = new SP.ClientContext.get_current();
var curWeb = ctx.get_web();
	
var propBag = curWeb.get_allProperties();
//setting to null will completely remove key/value from property bag
propBag.set_item("MyProp", null);
curWeb.update();

ctx.executeQueryAsync(
	function(){ alert('Property Bag Value "MyProp" removed!'); }, 
	function(sender, args){ alert('Error: ' + args.get_message()); }
);

Users

Reading

//This is the user to look up. Note that it must be prefixed with the auth and membership type.
//Typically the prefix will always be i:0#.f|membership| 
var targetUser = "i:0#.f|membership|admin@YOURTENANT.onmicrosoft.com";

//Can look in Central Admin/SPO Admin area to confirm OR use commands similar to:
//yourctx.get_web().get_currentUser().get_loginName() <-- use to view full current user login name


//Global variable
var userProfileProperties;

// Ensure that the SP.UserProfiles.js file is loaded before the custom code runs.
SP.SOD.executeFunc('SP.js', 'SP.ClientContext', function() {
	// Make sure PeopleManager is available 
   SP.SOD.executeFunc('userprofile', 'SP.UserProfiles.PeopleManager', function() {
		getUserProperties();
   });
});

function getUserProperties() {
    var clientContext = new SP.ClientContext.get_current();
    var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);

	//Properties from user profiles (These are CASE SENSITIVE)
    var profilePropertyNames = ["PreferredName", "Department"];
    var userProfilePropertiesForUser = 
        new SP.UserProfiles.UserProfilePropertiesForUser(
            clientContext,
            targetUser,
            profilePropertyNames);


    userProfileProperties = peopleManager.getUserProfilePropertiesFor(userProfilePropertiesForUser);

    clientContext.load(userProfilePropertiesForUser);
    clientContext.executeQueryAsync(onRequestSuccess, onRequestFail);
}

// This function runs if the executeQueryAsync call succeeds.
function onRequestSuccess() {
    var messageText = "\"PreferredName\" property is " 
        + userProfileProperties[0];
    messageText += "<br />\"Department\" property is " 
        + userProfileProperties[1];
    alert(JSON.stringify(userProfileProperties));
}

// This function runs if the executeQueryAsync call fails.
function onRequestFail(sender, args) {
    alert(args.get_message());
}

Content Types

Listing

var ctx = new SP.ClientContext.get_current();
var web = ctx.get_web();
var cts = web.get_contentTypes(); 
ctx.load(cts);
ctx.executeQueryAsync(onRequestSuccess, onRequestFail);
 
// This function runs if the executeQueryAsync call succeeds.
function onRequestSuccess() {
   var enumerator = cts.getEnumerator();
          
    while (enumerator.moveNext()) {
        var curCt = enumerator.get_current();
        console.log("CTID: " + curCt.get_id() + " | " + curCt.get_name());
    }
}
 
// This function runs if the executeQueryAsync call fails.
function onRequestFail(sender, args) {
    alert(args.get_message());
}

2 Comments

  • This is awesome. I am beginning to learn JSOM and I find this information very helpful.

    Thanks!

  • HI when using the add listitem code I am getting
    Record save failed error: Field or property “Title” does not exist.
    when it obviously does. its the same for any field I try in the list Do you have any ideas why please?