Custom SharePoint Solutions with HTML and JavaScript: For SharePoint 2013 and SharePoint Online (2015)
8. Working with the JavaScript Object Model
Brandon Atkinson1
(1)
VA, US
So far, you’ve been introduced to several different ways to create custom solutions in SharePoint using HTML and JavaScript. In this chapter, we’ll continue to explore using the Etherson method to create custom web parts along with the JavaScript Object Model. We looked briefly at the JavaScript Object Model, or JSOM, in Chapter 2. In this chapter, we’ll look at how to work with lists, libraries, files, sites, and social data using JSOM. You’ll be introduced to a variety of ways of working with SharePoint data and begin to fully see the power of this technology.
JSOM has the power to provide you with a wide range of options for your development needs. You can create new lists and sites; you can read files and interact with social data. By the end of this chapter, you’ll have a solid grasp on how to write JSOM code and know what it is capable of doing.
Note
Code that utilizes the JavaScript Object Model runs under the context of the user who is logged in. This means that the code only has the ability to perform actions that the user’s permission level will allow. For instance, if you have code to create a new subsite in the site collection, but the user who is logged in does not have that permission, it will run but produce an error. Keep this in mind as you build your solutions and ensure that you do not show users options that they cannot utilize.
Getting Set Up
Before getting started, we need to add some additional data to the Demo List we’ve been using throughout this book. Adding some additional data will allow us to query for more data and apply filters. Navigate to the Demo List and add a few more list items with various statuses. The updated list is shown in Figure 8-1.
Figure 8-1.
Demo List with more items added to it
Now that we have some additional data in the list, let’s begin to look at using JSOM to query for data. The examples in this chapter will utilize the Etherson method introduced in Chapter 4. Navigate to the Webparts folder in your site and create a new folder named Chapter 8, as shown in Figure 8-2.
Figure 8-2.
Chapter 8 folder in the Webparts document library
Each example in this chapter will follow the same pattern. We’ll look at the HTML file rendered in the Content Editor Web Part, the JavaScript file used to retrieve and render data, and finally, the results. Along the way, we’ll dive into each file and explain what is happening.
Working with Lists
Lists are everywhere in SharePoint! The large majority of things you will interact with in SharePoint as a user is a list. The following examples will demonstrate some various ways to interact with lists via code.
Get List Data
In this example, we’ll simply retrieve some list data to show the user.
HTML
Create a new HTML file in Visual Studio and name it JSOMGetListData.html. The HTML for this example is very simple, and only consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/webparts/chapter 8/JSOMGetListData.js"></script>
<div id="divGetListData"></div>
First, you’ll notice that we have to load a couple of SharePoint JavaScript files: sp.runtime.js and sp.js. These two files are very important because they provide the necessary code needed to properly run JSOM code. In SharePoint 2010, all the JavaScript needed was always loaded on every page. This made JavaScript development easier because you never had to worry about whether core SharePoint scripts were loaded or not. In SharePoint 2013, only the bare-bones code is loaded for what is needed on the page. This helps SharePoint load pages much faster; but it also means that if you need a specific library, you need to ensure that it’s loaded. In our case, we’ll need both of these files.
Next, we load in our custom JavaScript file called JSOMGetListData. This file contains all the code to load data into the DIV on the page, which has an ID of divGetListData. All in all, there is not much on this page.
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMGetListData.js. The JavaScript file is more complex in comparison and consists of the following lines:
$(function () {
getListData();
});
function getListData() {
var clientContext = new SP.ClientContext();
var oWebsite = clientContext.get_web();
this.collList = oWebsite.get_lists();
clientContext.load(collList);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded() {
var listInfo = '';
var listEnumerator = collList.getEnumerator();
while (listEnumerator.moveNext()) {
var oList = listEnumerator.get_current();
listInfo += 'Title: ' + oList.get_title() + ' - Created: ' +
oList.get_created().toString() + '<br />';
}
$("#divGetListData").html(listInfo);
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
Most of the JSOM examples in this book follow the same pattern as this example. Let’s dive into each line in detail to fully understand what is going on. The script begins with a jQuery Document.ready method, which simply calls a custom function called getListData that makes the JSOM call and is where the substantial code resides.
First, we create a new variable called clientContext and set it using the following line:
var clientContext = new SP.ClientContext();
The client context is a SharePoint object, which is really the entry point for all JSOM calls. It holds a lot of information about the context of the current site, user, web, and so forth. In this example, we simply ask for the context to be returned without passing any parameters. This will automatically return the context for the current site. You could also ask for the context of other sites by passing in a URL; for instance, SP.ClientContext(' http://www.site.com ').
Next, we create another variable called oWebsite and set it using the following line:
var oWebsite = clientContext.get_web();
This will give us the current site, or web, in the site collection that the user is executing the code from. We need this web in order to grab all the lists. Next, we create one more variable called collList by using the following line:
this.collList = oWebsite.get_lists();
This variable is populated with all the lists from the oWebsite variable. The collList variable is declared a little differently from the others, as there is no var keyword here, rather this. The reason for this is that the this keyword will make this variable global so that it can be accessed later by the functions needed to process the data.
The next line is often a source of headaches when you first start using JSOM:
clientContext.load(collList);
This line is “loading” the query into the client context to send to SharePoint. What this means is that at this point you have not actually sent any requests to SharePoint for data. In most JavaScript development, you would think that a line like this.collList = oWebsite.get_lists(); would return all the lists immediately and you could start using them. In JSOM, this is not the case. You have to load any requests you would like to make and then submit them later using the following line:
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
Not until you call the executeQueryAsync function does a request to SharePoint actually take a place. This is very important to understand when using JSOM and it trips up a lot of developers when they are first starting out. The reason for having to load all your requests before submitting them is a feature called batch processing. Basically, SharePoint allows you to load multiple requests for data and then only make one execute call to get all the data you need. This allows for better performance on the server where your JSOM call is actually processed. None of the examples in this book actually utilizes batch processing, but it’s an important concept to know about.
The executeQueryAsync method allows you to specify a success function and a failure function, which are called after SharePoint returns the results of the query. These are declared using the Function.createDelegate method, as shown earlier. Once you have specified these, you need to create the function to actually process the results.
function onQuerySucceeded() {
var listInfo = '';
var listEnumerator = collList.getEnumerator();
while (listEnumerator.moveNext()) {
var oList = listEnumerator.get_current();
listInfo += 'Title: ' + oList.get_title() + ' - Created: ' +
oList.get_created().toString() + '<br />';
}
$("#divGetListData").html(listInfo);
}
This function begins with a new variable called listInfo, which will be used to hold all the results of the query before displaying them on the page. Next, we get an enumerator from the collList variable using the collList.getEnumerator() method and we put it in a variable calledlistEnumerator. We need to loop through all the results that are returned, and the enumerator allows us to do this. Using a while loop, we loop through each item that was returned using the listEnumerator.get_current() method. During each loop, we grab the title and the created date from the current item. We include more HTML and add the content to the listInfo variable using +=. This allows us to keep adding content to the listInfo variable rather than overwriting it each time.
Finally, we output the contents of the listInfo variable to the DIV in our HTML page using $("#divGetListData").html(listInfo);.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The results will display all the lists in the current site, as shown in Figure 8-3.
Figure 8-3.
Get List Data results in the Content Editor Web Part
Create a New List
In this example, we’ll create a new list. We won’t do anything fancy, just create a new list and set its title.
HTML
Create a new HTML file in Visual Studio and name it JSOMCreateList.html. The HTML for this example is a little more complex than the previous example, and it consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/webparts/chapter 8/JSOMCreateList.js"></script>
<div>
<strong>Enter a name for the list:</strong>
<input type="text" id="txtListName" />
<input type="button" id="btnSubmitListName" value="Submit" />
</div>
<div id="divCreateListResults"></div>
Just as before, we need to load in the sp.runtime.js and sp.js files, as well as a reference to our custom JavaScript file. The HTML is a little more complex, with several elements on the page. First, there is some simple text wrapped in a <strong> tag to make it bold on the page. Next, there is an INPUT of type Text that is just a simple textbox for the user to input the name of the list that they wish to create. There is a button for the user to submit the new list request and, finally, a DIV where we can output the results of the list creation. Each element has an ID so that we can easily target it with jQuery.
Note
In order to create a new list via JSOM, the user executing the code must have at least Manage Lists permissions in SharePoint. The page will be rendered no matter the permission level; however, SharePoint will throw an error if the user does not have adequate permissions.
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMCreateList.js. In comparison, the JavaScript file is more complex, and it consists of the following lines:
$(function () {
bindButtonClick();
});
function bindButtonClick() {
$("#btnSubmitListName").on("click", function () {
var listName = $("#txtListName").val();
createList(listName);
});
}
function createList(listName) {
var clientContext = new SP.ClientContext();
var oWebsite = clientContext.get_web();
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title(listName);
listCreationInfo.set_templateType(SP.ListTemplateType.genericList);
this.oList = oWebsite.get_lists().add(listCreationInfo);
clientContext.load(oList);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded() {
var results = oList.get_title() + ' successfully created!';
$("#divCreateListResults").html(results);
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
In this example, we don’t need to fire any actions on the page load; however, we do need to wire up a button click event when the page loads. In the Document.ready function, we fire the bindButtonClick function. In this function, we use the jQuery on operator to wire a click event on thebtnSubmitListName button in the HTML. When the user clicks the button, we grab the text from the textbox on the page and pass it to the createList() function using the following lines:
function bindButtonClick() {
$("#btnSubmitListName").on("click", function () {
var listName = $("#txtListName").val();
createList(listName);
});
}
The createList() function takes a variable called listName, which is the text the user inputs on the page. Next, we grab a reference to the current client context and get the current web. Then, we create the list using the following code:
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title(listName);
listCreationInfo.set_templateType(SP.ListTemplateType.genericList);
this.oList = oWebsite.get_lists().add(listCreationInfo);
clientContext.load(oList);
In order to create a new list, we use an SP.ListCreationInformation() object. We can instantiate a new ListCreationInformation object using the following line:
var listCreationInfo = new SP.ListCreationInformation();
All this line does is create a new object and assign it a new variable called listCreationInfo. Next, we set the title and template using the following lines:
listCreationInfo.set_title(listName);
listCreationInfo.set_templateType(SP.ListTemplateType.genericList);
The set_title method takes the listName that was passed into the function. The set_templateType method takes a built-in value of SP.ListTemplateType, which, in this case, we pass in genericList. The available values here would be anything you would expect to see if creating the list in the browser using the SharePoint UI, IE: Announcements, Calendar, Task, and so forth. Next, we add the list to the web using the following line:
this.oList = oWebsite.get_lists().add(listCreationInfo);
clientContext.load(oList);
Just like in the previous example, after we add the list to the site, we then “load” the list to the client context. Finally, we call the executeQueryAsync function, which will actually make the call to SharePoint to create the list. Once the call is completed, we process the results with the following function:
function onQuerySucceeded() {
var results = oList.get_title() + ' successfully created!';
$("#divCreateListResults").html(results);
}
In this function, using the oList.get_title() method, we can get the title of the list that was just created. This is a nice check to ensure that the list was indeed created, since we get the title from the list itself rather than using the text that the user inputted. Once we have the list title, we use jQuery to add the success message to the divCreateListResults DIV on the page.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will now show the textbox and button for the user to input a new list name. Type My Custom List and then click the Submit button. The results will display the success message, as shown in Figure 8-4.
Figure 8-4.
Create new list code after it has been run
Since this is all done using JavaScript and AJAX the list will get created and the user will be notified as expected. However, the left navigation on the page will not be updated since the page has not been refreshed. You could absolutely change this code to refresh the page on success, but for this example we’ll simply refresh the page in the browser. Figure 8-5 shows the page after a refresh where the new list is displayed in the left navigation.
Figure 8-5.
The new list as displayed in the left navigation pane
Delete a List
In this example, we’ll simply delete the list we just created in the previous section.
HTML
Create a new HTML file in Visual Studio and name it JSOMDeleteList.html. The HTML for this example is almost identical to the previous example, and it consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/webparts/chapter 8/JSOMDeleteList.js"></script>
<div>
<strong>Enter the name of the list to delete:</strong>
<input type="text" id="txtListName" />
<input type="button" id="btnSubmitListName" value="Submit" />
</div>
<div id="divDeleteListResults"></div>
The only difference here is that we updated the text on the page to indicate that this is web part will delete a list, and we changed the ID of the results DIV to divDeleteListResults.
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMDeleteList.js. The JavaScript file consists of the following lines:
$(function () {
bindButtonClick();
});
function bindButtonClick() {
$("#btnSubmitListName").on("click", function () {
var listName = $("#txtListName").val();
deleteList(listName);
});
}
function deleteList(listName) {
var clientContext = new SP.ClientContext();
var oWebsite = clientContext.get_web();
this.oList = oWebsite.get_lists().getByTitle(listName);
oList.deleteObject();
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded() {
$("#divDeleteListResults").html("List successfully deleted!");
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
The script starts with the familiar jQuery Document.ready function that binds a button click to a function:
function bindButtonClick() {
$("#btnSubmitListName").on("click", function () {
var listName = $("#txtListName").val();
deleteList(listName);
});
}
This function is nearly identical to the previous example—with the exception of deleteList, the new function name to delete the list. This function is smaller and more to the point, with only a couple of relevant lines:
this.oList = oWebsite.get_lists().getByTitle(listName);
oList.deleteObject();
After obtaining a reference to the client context and current web, we use the getByTitle() method on the web object to locate the list that we wish to delete, and then assign it to a variable called oList. Next, we call the oList.deleteObject() method to actually perform the delete. You’ll notice that there is no “load” method here on the client context object. When deleting a list, you do not need to perform this step. After the deleteObject() line, you can simply call the executeQueryAsync() method to perform the delete operation.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will now show the textbox and button for the user to input a list name to delete. Type My Custom List and then click the Submit button. The results will display the success message, as shown in Figure 8-6.
Figure 8-6.
Delete List code after it has successfully run
Since this is all done using JavaScript and AJAX, the list will get deleted and the user will be notified as expected. However, the left navigation on the page will not be updated because the page has not been refreshed. As before, we could update this code to refresh the page on success, but for this example, we’ll simply refresh the page in the browser. Figure 8-7 shows the page after a refresh where the list is no longer displayed in the left navigation.
Figure 8-7.
The deleted list has been removed from the left navigation
Working with List Items
The only thing more plentiful in SharePoint than lists, are list items. You’ll find that a lot of your interactions in SharePoint are with list items, and thus a lot of your code will involve them as well. In this section we’ll explore some of the ways to work with list items via code.
Get List Items
In this example, we’ll simply retrieve some list items and display them to the user.
HTML
Create a new HTML file in Visual Studio and name it JSOMGetListItems.html. The HTML for this example continues to follow the minimalist pattern of the previous examples, and it consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/webparts/chapter 8/JSOMGetListItems.js"></script>
<div id="divListItems"></div>
For this example, we’ll simply grab all the list items from the Demo List and display them in the divListItems DIV on the page.
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMGetListItems.js. The script to retrieve list items should look very familiar to the other scripts that we’ve seen so far, and it consists of the following lines:
$(function () {
retrieveListItems();
});
function retrieveListItems() {
var clientContext = new SP.ClientContext();
var oList = clientContext.get_web().get_lists().getByTitle('Demo List');
var camlQuery = new SP.CamlQuery();
this.collListItem = oList.getItems(camlQuery);
clientContext.load(collListItem);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded(sender, args) {
var listItemInfo = '';
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
listItemInfo += '<strong>ID: </strong> ' + oListItem.get_id() +
' <strong>Title:</strong> ' + oListItem.get_item('Title') +
'<br />';
}
$("#divListItems").html(listItemInfo);
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
For this example, since we’ll just be fetching all the items from the list, we’ll call the retrieveListItems() function using the jQuery Document.ready function. After obtaining a reference to the client context, we get a reference to the Demo List with the following line:
var oList = clientContext.get_web().get_lists().getByTitle('Demo List');
This line may at first glance appear to be intimidating because it’s quite long. However, it’s actually quite easy to read. First, we get the current web, and then we get all the lists in the web, and, finally, we get the list by its title. JSOM and REST both follow this type of pattern when querying for objects, making the code easy to understand. Next, we need to create a CAML Query to let SharePoint know which items we are looking for:
var camlQuery = new SP.CamlQuery();
this.collListItem = oList.getItems(camlQuery);
CAML (Collaborative Application Markup Language) Query is a query language used in SharePoint to define the query for list items. You can specify which items to return based on criteria much like a SQL query, although they look nothing alike. In this example, we simply create an empty query using the new SP.CamlQuery() method. When you query a list, you must provide a CAML query, even if no parameters are defined. If you pass an empty query, as in this example, you are in effect asking for all items to be returned. In practice, this is not a great idea, since a lot of lists contain hundreds or thousands of items. After we’ve created the query, we pass it to the oList.getItems() method to perform the query. Just as in the other examples, we use a global variable called collListItems using the this keyword. Finally, we “load” the query and execute it.
Note
CAML Query is quite a complex and deep topic. We’ll only scratch the surface of CAML in this book; it’s that large. We’ll dig a bit deeper into CAML in the next section, but you can learn more about how to build these queries at http://msdn.microsoft.com/en-us/library/ms467521(v=office.15).aspx .
Once we retrieve the list items, we process them in the onQuerySucceeded function:
function onQuerySucceeded(sender, args) {
var listItemInfo = '';
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
listItemInfo += '<strong>ID: </strong> ' + oListItem.get_id() +
' <strong>Title:</strong> ' + oListItem.get_item('Title') +
'<br />';
}
$("#divListItems").html(listItemInfo);
}
This function starts off with declaring an empty variable called listItemInfo. This variable will hold the entire HTML that will be displayed on the page. Next, we get the enumerator for the collListItem variable, which you will remember is available on any collection of items that gets returned from SharePoint. We loop through the items using the listItemEnumerator.moveNext() method. Inside the loop, we grab each item using the listItemEnumerator.get_current() method. We then build some HTML for each item in the result set displaying the ID and Title, and stuff it in the listItemInfo variable. Finally, we set the HTML to the divListItems DIV on the page with jQuery.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will now show all the items in the Demo List, as shown in Figure 8-8.
Figure 8-8.
List items from the Demo List displayed in the Content Editor Web Part
Limit Results with CAML Query
As I mentioned, it’s usually not a good idea to query for all items in a list. There are certainly times where this is needed or makes sense; for instance, you may have a list with very few items, or you have an administrator task where you need to view all the items. If you’ve worked with SharePoint in the past, you already know that SharePoint automatically limits list results, which default at 2,000 results in a query. In either case, most users will never need to see all the items in a list and the query will be limited to only show the items the user needs to see.
CAML allows you to limit the results based on a wide variety of parameters, which gives you complete control over what is displayed to the user. In the previous example, we passed in an empty CAML query by creating a new SP.CamlQuery object, which returned all the list items. You can pass in a CAML query by using the set_viewXml() method on the CamlQuery object, as seen in the following “JavaScript” section.
JavaScript
Update the JSOMGetListItems.js from the previous example and update the section where you declare the SP.CamlQuery() object with the following lines:
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml(
'<View><Query><Where><Geq><FieldRef Name=\'ID\'/>' +
'<Value Type=\'Number\'>5</Value></Geq></Where></Query>' +
'<RowLimit>10</RowLimit></View>'
);
this.collListItem = oList.getItems(camlQuery);
In this example, we limit the results by specifying that we only want items with an ID greater than or equal to 5. This is done using the GEQ element, which stands for “greater than or equal to.” Before the GEQ element, we use a Where element and specify the FieldRef of ID, which is the ID of the list item. If all this seems like Latin, don’t worry, there are tools you can download to help you write CAML. We won’t go deeply into the finer details of writing CAML queries; for this section, you should take away that you can fine-tune your queries with great detail.
Note
At first glance, CAML may appear quite confusing and overly complex. After you have been working with CAML for a while, you may still be thinking the same thing! Luckily, there are several great free tools available to help you craft your CAML statements. I personally like SharePoint CAML Query Helper, which is free and can be downloaded on CodePlex. Visit https://spcamlqueryhelper.codeplex.com to download a copy.
Results
Update the JavaScript file and upload it, overwriting the previous version. Refresh the page with the Content Editor Web Part and you will see that the results now only show items with an ID greater than or equal to 5, as shown in Figure 8-9.
Figure 8-9.
The results of the Demo List query limited by a CAML query
Add List Items
In this example, we’ll add a new item to the demo list.
HTML
Create a new HTML file in Visual Studio and name it JSOMAddListItems.html. The markup for this page will allow a user to add an item to the Demo List, providing a Title and a Description. It consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/Webparts/chapter 8/JSOMAddListItems.js"></script>
<div id="AddListData">
<div>
Title:
<br />
<input type="text" id="txtTitle" />
</div>
<div>
Description:
<br />
<textarea cols="20" id="txtDesc"></textarea>
</div>
<br />
<div>
<input id="btnSubmit" type="button" value="Submit" />
</div>
</div>
<div id="divResult"></div>
We provide an INPUT of type TEXT for the list item Title, and a TEXTAREA for the Description. Each element on the page has an ID so that we can easily target it with jQuery.
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMADDListItems.js. The script to add list items looks similar to the script for creating a new List. It consists of the following lines:
$(function () {
bindButtonClick();
});
function bindButtonClick() {
$("#btnSubmit").on("click", function () {
addListItem();
});
}
function addListItem() {
var title = $("#txtTitle").val();
var desc = $("#txtDesc").val();
var clientContext = new SP.ClientContext();
var oList = clientContext.get_web().get_lists().getByTitle('Demo List');
var itemCreateInfo = new SP.ListItemCreationInformation();
this.oListItem = oList.addItem(itemCreateInfo);
oListItem.set_item('Title', title);
oListItem.set_item('Description', desc);
oListItem.set_item('Status', 'On-time');
oListItem.update();
clientContext.load(oListItem);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onAddSucceeded),
Function.createDelegate(this, this.onAddFailed)
);
}
function onAddSucceeded(sender, args) {
$("#divResult").html("Item successfully added!");
}
function onAddFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
After we attach a button click event with jQuery, the first thing we do on the click event is grab the values that the user is providing with the following lines:
var title = $("#txtTitle").val();
var desc = $("#txtDesc").val();
Next, we get the reference to the current client context, as well as the Demo List. Then, in order to create a new list item, we have to instantiate an SP.ListItemCreationInformation object. This object allows you to create a new list item for a list and set its properties. This is done with the following code:
var itemCreateInfo = new SP.ListItemCreationInformation();
this.oListItem = oList.addItem(itemCreateInfo);
oListItem.set_item('Title', title);
oListItem.set_item('Description', desc);
oListItem.set_item('Status', 'On-time');
oListItem.update();
Once we create a new SP.ListItemCreationInformation object, we add it to the list using the addItem() method on the list object. Next, we set individual properties using the set_item() method on the list item object. This method takes two parameters. The first parameter is the field or column for which you want to set the value, and the second parameter is the value itself. For the Title and Description, we simply pass in the values we retrieved earlier. For the Status column, we simply hard-code a value of On-time. Finally, we update the item using the update() method, and then load it into the client context and execute the query. In the success function, we simply output to the screen that the list item creation was successful.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will show the textboxes for the user to input the details, and will then display a success message when an item is added, as shown in Figure 8-10.
Figure 8-10.
Adding a new item to the Demo List
We can then navigate to the Demo List to confirm that a new item was added. Figure 8-11 shows the Demo List with a new list item added and with the values supplied by the HTML page.
Figure 8-11.
A new list item added to the Demo List
Delete List Items
This example will show you how to delete list items, in this case we’ll delete the item we added in the previous example.
HTML
Create a new HTML file in Visual Studio and name it JSOMDeleteListItems.html. The HTML for this file is much smaller, as all we need to capture from the user is an ID corresponding to the list item that they wish to delete. This is accomplished with the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/Webparts/chapter 8/JSOMDeleteListItems.js"></script>
<div>
Enter ID to Delete: <input type="text" id="txtId" />
</div>
<div>
<input id="btnSubmit" type="button" value="Submit" />
</div>
<div id="divResult"></div>
This example is overly simplified, in that a user will most likely not know the ID of a certain list item to delete. A more real-world example would most likely show the user a list of items and allow them to click one to delete it. In such a scenario, you would have the list item IDs on the page and could easily access it. We’ll keep a simple textbox to keep the example streamlined.
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMDeleteListItems.js; include the following code:
$(function () {
bindButtonClick();
});
function bindButtonClick() {
$("#btnSubmit").on("click", function () {
deleteListItem();
});
}
function deleteListItem() {
var id = $("#txtId").val();
var clientContext = new SP.ClientContext();
var oList = clientContext.get_web().get_lists().getByTitle('Demo List');
this.oListItem = oList.getItemById(id);
oListItem.deleteObject();
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded(sender, args) {
$("#divResult").html("Item successfully deleted!");
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
The deleteListItem() function will be called on the button click event on the page. Using the following line, the first thing that we do is grab the ID that the user entered on the page:
var id = $("#txtId").val();
Next, we get the current client context and a reference to the Demo List. Deleting the item is accomplished with the following lines:
this.oListItem = oList.getItemById(id);
oListItem.deleteObject();
We use the getItemById() method on the list object passing in the ID that the user submitted. Then, we call the deleteObject() method to actually perform the deletion. Similar to deleting a list earlier in the chapter, this is all that is required to delete the list item. We do not need to load the delete call into the client context; we simply need to execute the query. The success function will simply notify the user that the delete was successful.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will show the textbox for the user to input the ID, and will then display a success message when an item is deleted, as shown in Figure 8-12.
Figure 8-12.
Deleting a list item using JSOM
Working with Document Libraries
Since one of SharePoint’s strengths lies in document management, you need to know how to work with document libraries via code. Since document libraries are really just lists in SharePoint, you already have some experience here!
Create a New Folder
In this example, we’ll demonstrate how to create a new folder in an existing document library.
HTML
Create a new HTML file in Visual Studio and name it JSOMCreateFolder.html. The markup for this page is quite simple, allowing the user to enter a name for the folder they wish to create. It consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/Webparts/chapter 8/JSOMCreateFolder.js"></script>
<div>
<strong>Enter a name for the folder:</strong>
<input type="text" id="txtFolderName" />
<input type="button" id="btnSubmit" value="Submit" />
</div>
<div id="divResults"></div>
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMCreateFolder.js; include the following code:
$(function () {
bindButtonClick();
});
function bindButtonClick() {
$("#btnSubmit").on("click", function () {
createFolder();
});
}
function createFolder() {
var folderName = $("#txtFolderName").val();
var clientContext = new SP.ClientContext();
var oWebsite = clientContext.get_web();
var oList = oWebsite.get_lists().getByTitle("Documents");
var folderCreateInfo = new SP.ListItemCreationInformation();
folderCreateInfo.set_underlyingObjectType(SP.FileSystemObjectType.folder);
folderCreateInfo.set_leafName(folderName);
this.oListItem = oList.addItem(folderCreateInfo);
this.oListItem.update();
clientContext.load(oList);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded() {
$("#divResults").html("Folder successfully created!");
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
After using jQuery to wire up the button click, the createFolder() function begins with grabbing the name of the folder that the user entered on the page:
var folderName = $("#txtFolderName").val();
Next, we get a reference to the current client context and the current web, and then we reference the Shared Documents folder with the following line:
var oList = oWebsite.get_lists().getByTitle("Documents");
This example will create a new folder in the Shared Documents library. Since all document libraries are really lists in SharePoint, we can use the getLists().getByTitle() method to retrieve the library. Next, we create a new SP.ListItemCreationInformation object for the folder:
var folderCreateInfo = new SP.ListItemCreationInformation();
At first glance, this may seem strange, as we are creating a new folder and not a list item. In SharePoint, folders are list items even though they look and act just like you would expect a folder to. For this reason, the same SP.ListItemCreationInformation object is used. Now that the object is created, we need to set some properties using the following lines:
folderCreateInfo.set_underlyingObjectType(SP.FileSystemObjectType.folder);
folderCreateInfo.set_leafName(folderName);
this.oListItem = oList.addItem(folderCreateInfo);
this.oListItem.update();
First, since this is not a standard list item, we need to specify the object type using the set_underlyingObjectType() method, passing in SP.FileSystemObjectType.folder as the parameter. Next, we set the folder name using the set_leafName() method, passing in the name that the user is submitting from the page. Finally, we add the new folder to the list and update it, and then load the query on the client context. The success function will simply output to the screen a message informing the user that the folder was successfully created.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will show the textbox for the user to input the name of the folder to be created, and will then display a success message when completed, as shown in Figure 8-13.
Figure 8-13.
Creating a new folder with JSOM
We can then navigate to the Documents library to visually verify that the new folder was created, as shown in Figure 8-14.
Figure 8-14.
New folder created via JSOM
Working with Files
Lists and libraries are not the only areas where your coding skills will be used. In this section, we’ll look at working with files via code.
Create a New File
In this example, we’ll create a new text file and add it to a document library.
HTML
Create a new HTML file in Visual Studio and name it JSOMCreateDocument.html. The markup for this page will allow the user to enter a name for a new text file, as well as the content for the file itself. It consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/Webparts/chapter 8/JSOMCreateDocument.js"></script>
<div id="CreateFile">
<div>
<strong>Enter a title for the document:</strong>
<br />
<input type="text" id="txtDocumentTitle" />
</div>
<div>
<strong>Enter content for the document:</strong>
<br />
<textarea cols="20" id="txtDocumentContent"></textarea>
</div>
<br />
<input type="button" id="btnSubmit" value="Submit" />
</div>
<div id="divResults"></div>
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMCreateDocument.js; include the following code:
$(function () {
bindButtonClick();
});
function bindButtonClick() {
$("#btnSubmit").on("click", function () {
createDocument();
});
}
function createDocument() {
var docTitle = $("#txtDocumentTitle").val() + ".txt";
var docContent = $("#txtDocumentContent").val();
var clientContext = new SP.ClientContext();
var oWebsite = clientContext.get_web();
var oList = oWebsite.get_lists().getByTitle("Documents");
var fileCreateInfo = new SP.FileCreationInformation();
fileCreateInfo.set_url(docTitle);
fileCreateInfo.set_content(new SP.Base64EncodedByteArray());
for (var i = 0; i < docContent.length; i++) {
fileCreateInfo.get_content().append(docContent.charCodeAt(i));
}
this.newFile = oList.get_rootFolder().get_files().add(fileCreateInfo);
clientContext.load(this.newFile);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded() {
$("#divResults").html("Document successfully created!");
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
The first thing that we need to do is grab the document title and content that the user entered on the page. This is accomplished with the following lines:
var docTitle = $("#txtDocumentTitle").val() + ".txt";
var docContent = $("#txtDocumentContent").val();
Notice that we append .txt to the end of the document title. This will let SharePoint know that we intend to create a text file, as it will use the extension in the name to determine the file type. Next, we get a reference to the current client context, as well as the web and document library where we would like to save the new document. Now we need to create a new SP.FileCreationInformation object and set its properties:
var fileCreateInfo = new SP.FileCreationInformation();
fileCreateInfo.set_url(docTitle);
fileCreateInfo.set_content(new SP.Base64EncodedByteArray());
You should now begin to see a pattern with creating objects in JavaScript with SharePoint. Just about anything you create has a CreationInformation object associated with it. Once we have the object created, we set the URL of the file using the set_url() method. Finally, we set the content of the file to an empty byte array using the SP.Base64EncodedByteArray() object. You don’t need to worry too much about the details of this object for now; just know that this is what the JSOM code expects when setting the content of a new file. Now that we have the empty array created, we need to populate it using the following code:
for (var i = 0; i < docContent.length; i++) {
fileCreateInfo.get_content().append(docContent.charCodeAt(i));
}
This is a simple loop that will take each character in the text that the user submitted and append it to the empty array in the file content. Once the loop is complete and the text has been entered into the document, we add it to the library:
this.newFile = oList.get_rootFolder().get_files().add(fileCreateInfo);
We then load the query on the client context and execute it. The success function will simply output to the screen that the file creation was successful.
Note
In this example, we are creating a simple text file. In most real-world scenarios, a text file would not be the intended result, but perhaps a Word file or an Excel file instead. You could absolutely change this example to generate a Word document by simply changing the .txt to .docx. This simple change would, in fact, create a new Word document with the content in it. However, it could only be opened in Word on the client machine, not Office Web Apps. Luckily, there are Office JavaScript files available via Microsoft to allow you to create and manipulate Office files from the browser. You can find more information at http://msdn.microsoft.com/en-us/library/office/fp160953%28v=office.15%29.aspx .
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will show textboxes for the user to input the title of the document and the content, and will then display a success message when the new document has been created, as shown in Figure 8-15.
Figure 8-15.
Creating a new document from a Content Editor Web Part
We can navigate to the Documents folder and find that the new text document has been created. You can click the document and it will open in the browser and display the contents the user entered from the page, as shown in Figure 8-16.
Figure 8-16.
New text document created in the Documents folder
Read a File
In this section, we’ll see how to read the file we created in the previous example.
HTML
Create a new HTML file in Visual Studio and name it JSOMReadDocument.html. The markup for this page is extremely simple, with only a reference to the custom JavaScript file and a DIV to output the document contents. It consists of the following lines:
<script type="text/javascript" src="/apress/Webparts/chapter 8/JSOMReadDocument.js"></script>
<div id="divReadDocument" />
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMReadDocument.js; include the following code:
$(function () {
readDocument();
});
function readDocument() {
var siteUrl = _spPageContextInfo.webAbsoluteUrl;
var documentLibrary = "/Shared Documents/"
var fileUrl = "New Text Doc.txt";
var fullUrl = siteUrl + documentLibrary + fileUrl;
$.ajax({
url: fullUrl,
type: "GET"
})
.done(function (data) {
$("#divReadDocument").html(data);
})
.fail(function () {
alert("error");
});
}
At first glance, this code should seem concise and you’ll notice there is no JSOM code here at all. The beauty of reading a text file from SharePoint is that all you need is jQuery. Since this is a chapter about JSOM, this code should probably be somewhere else, but since we created a document, you should also know how to read it. There is a simple jQuery Document.ready function, which will fire the code to read the file. We’ll intentionally keep this code simple and hard-code the file name for the document we just created:
var siteUrl = _spPageContextInfo.webAbsoluteUrl;
var documentLibrary = "/Shared Documents/"
var fileUrl = "New Text Doc.txt";
var fullUrl = siteUrl + documentLibrary + fileUrl;
The first thing we do is get the current web’s full URL by using _spPageContextInfo.webAbsoluteUrl. Next, we hard-code the document library portion of the URL and the file name. Finally, we put them all together into a new variable called fullUrl. You could absolutely have done all of that in one line, but you’ll find it’s easier to debug your code later if you break it up into smaller lines. Once we have the URL for the file, we use a jQuery AJAX call to get the document:
$.ajax({
url: fullUrl,
type: "GET"
})
.done(function (data) {
$("#divReadDocument").html(data);
})
.fail(function () {
alert("error");
});
When retrieving a text file via AJAX in jQuery, the content will be returned as text and we can simply output that to the page without any modifications. We use the jQuery .done function, setting the content of the file to a new variable called data. Then we set the data to the HTML of the results DIV on the page.
Note
Just as before, when creating a new file, we kept things simple by utilizing a text file. This is also true for this section and reading a file. You cannot read an Office file using the method just described. You need to utilize the Office JavaScript files to properly read a Word file or an Excel file in the browser. You can find more information at http://msdn.microsoft.com/en-us/library/office/fp160953%28v=office.15%29.aspx .
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will display the contents of the text file, as shown in Figure 8-17.
Figure 8-17.
Contents of the text file displayed on the page
Updating a File
You can also easily update a file using JSOM. In fact, updating the file is essentially the same code as creating the file, with the addition of a single line:
fileCreateInfo.set_overwrite(true);
This line simply tells SharePoint to overwrite a previous file of the same name. Using this, you could easily read the contents of the text file into a textbox on the page and allow the user to modify the content. When the user wishes to save the file, use the same code as creating the file and include the overwrite command.
Delete a File
In this example, we’ll see how to delete a file.
HTML
Create a new HTML file in Visual Studio and name it JSOMDeleteDocument.html. The markup for this page has a textbox for the user to enter the name of the file that they wish to delete. It consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/Webparts/chapter 8/JSOMDeleteDocument.js"></script>
<div id="DeleteFile">
<div>
<strong>Enter the name of document to delete:</strong>
<br />
<input type="text" id="txtDocumentTitle" />
</div>
<br />
<input type="button" id="btnSubmit" value="Submit" />
</div>
<div id="divResults"></div>
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMDeleteDocument.js; include the following code:
$(function () {
bindButtonClick();
});
function bindButtonClick() {
$("#btnSubmit").on("click", function () {
deleteDocument();
});
}
function deleteDocument() {
var docTitle = $("#txtDocumentTitle").val() + ".txt";
var clientContext = new SP.ClientContext();
var oWebsite = clientContext.get_web();
var fileUrl = _spPageContextInfo.webServerRelativeUrl +
"/Shared Documents/" + docTitle;
this.fileToDelete = oWebsite.getFileByServerRelativeUrl(fileUrl);
this.fileToDelete.deleteObject();
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded() {
$("#divResults").html("Document successfully deleted!");
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
After wiring up the button click event, the first thing that we do is grab the title of the document that the user wishes to delete:
var docTitle = $("#txtDocumentTitle").val() + ".txt";
We’ll keep this example simple and delete the text file that was created earlier, and thus hard-code the .txt extension into the code. Next, we perform the usual ritual of referencing the current client context and web, and then we construct the path to the document:
var fileUrl = _spPageContextInfo.webServerRelativeUrl +
"/Shared Documents/" + docTitle;
For this path, we only need the relative path of the document, and not the full URL. We can obtain the relative path of the current web by using _spPageContextInfo.webServerRelativeUrl. Since we know that this document resides in the Documents folder, we’ll hard-code that and add in the document title that the user submitted. Just like with other delete operations in SharePoint, we do not need to load this request on the client context and can simply call the deleteObject method and execute the query. The success function will output a message to the user informing them that the document has been deleted.
Unlike with the create, read, and update document functions we saw earlier, you can delete any file that you wish with JSOM, assuming that the user has delete permissions. SharePoint is quite agnostic when it comes to deleting documents. You can easily use the same code to delete Office documents without any issues or extra JavaScript libraries.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will display a textbox for the user to enter the document title and display a result message, as shown in Figure 8-18.
Figure 8-18.
Deleting a file via JSOM
Working with Sites
You may be thinking at this point that JSOM is pretty powerful! And in fact it is, and to prove it we’ll create a new site with it! Working with lists and libraries is pretty cool, but being able to create a new site via JavaScript will really demonstrate the power of JSOM.
Create a Site
In this example, we’ll create a new team site. In addition to creating the new site, we’ll also set a number of its properties including Title, Description, and Site Template.
HTML
Create a new HTML file in Visual Studio and name it JSOMCreateSite.html. The markup for this page has a textbox for the user to enter the name of the new site, as well as a textbox for a site description. It consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/Webparts/chapter 8/JSOMCreateSite.js"></script>
<div id="DeleteFile">
<div>
<strong>Enter the name of the site:</strong>
<br />
<input type="text" id="txtSiteTitle" />
</div>
<br />
<div>
<strong>Enter site description:</strong>
<br />
<textarea cols="20" id="txtSiteDescription"></textarea>
</div>
<br />
<input type="button" id="btnSubmit" value="Submit" />
</div>
<div id="divResults"></div>
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMCreateSite.js; include the following code:
$(function () {
bindButtonClick();
});
function bindButtonClick() {
$("#btnSubmit").on("click", function () {
createSite();
});
}
function createSite() {
var siteTitle = $("#txtSiteTitle").val();
var siteDesc = $("#txtSiteDescription").val();
var siteUrl = siteTitle.replace(/\s/g, "");
var clientContext = new SP.ClientContext();
var collWeb = clientContext.get_web().get_webs();
var webCreationInfo = new SP.WebCreationInformation();
webCreationInfo.set_title(siteTitle);
webCreationInfo.set_description(siteDesc);
webCreationInfo.set_language(1033);
webCreationInfo.set_url(siteUrl);
webCreationInfo.set_useSamePermissionsAsParentSite(true);
webCreationInfo.set_webTemplate('STS#0');
var oNewWebsite = collWeb.add(webCreationInfo);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded() {
$("#divResults").html("Site successfully created!");
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
Creating a new site takes a bit more code, but it should all be very familiar by now. First, we grab the Title and Description that the user submitted by using the following lines:
var siteTitle = $("#txtSiteTitle").val();
var siteDesc = $("#txtSiteDescription").val();
var siteUrl = siteTitle.replace(/\s/g, "");
When you create a site, you must provide a URL for the site in addition to the Title. For this example, we’ll simply take the text that the user entered for the Title and remove all the spaces to make the URL. This is done using the replace() method in JavaScript, with the first parameter being what we are searching for, and the second parameter being what it should be replaced with. The /\s/g text denotes a space and must be used for this function to work properly.
Once we have the variables needed for site creation, we reference the current client context and then obtain the collection of web sites in the current web:
var collWeb = clientContext.get_web().get_webs();
The get_web().get_webs() method returns a collection of all the subsites in the current web. It’s this collection that we’ll ultimately add the new site to. Next, we create an SP.WebCreationInformation object:
var webCreationInfo = new SP.WebCreationInformation();
webCreationInfo.set_title(siteTitle);
webCreationInfo.set_description(siteDesc);
webCreationInfo.set_language(1033);
webCreationInfo.set_url(siteUrl);
webCreationInfo.set_useSamePermissionsAsParentSite(true);
webCreationInfo.set_webTemplate('STS#0');
Just like the other CreationInformation objects that we’ve seen before, we create a new WebCreationInformation object and set its various properties. Luckily, just about all the methods needed to configure properties on this object are very self-explanatory; for instance,set_useSamePermissionsAsParentSite() determines if this new site should inherit the permissions of the parent site. There are some tricky parameters that you may not be familiar with, such as 1033 (which means “English” when setting the language for the site) and STS#0 (which means a team site template when setting the site template). All the other properties should look familiar.
Once the properties have been set, we simply add the new site to the collection:
var oNewWebsite = collWeb.add(webCreationInfo);
Creating a new site is also another area where you do not need to load the query on the client context. You can simply execute the query to have the new site created. The success function will simply notify the user that the site has been created.
Note
Again, the code in these examples run under the permission level of the current user. Since a lot of these examples perform higher-level functions, like creating and deleting SharePoint objects, the user will need to have appropriate permissions to perform these functions. It’s worth pointing this out again, as site creation will require the user to have Full Control permissions for the site where the new web is being created.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will display textboxes for the user to enter the new site title and description, and display a result message, as shown in Figure 8-19.
Figure 8-19.
Creating a new site via JSOM
We can then open the Site Contents page where the new site was created, and scroll to the bottom. In the Subsites section, we can see that the new site has been created, as shown in Figure 8-20.
Figure 8-20.
The newly created subsite in the Site Contents page
Delete a Site
In this section, we’ll delete the site we created in the previous example.
HTML
Create a new HTML file in Visual Studio and name it JSOMDeleteSite.html. The markup for this page has a textbox for the user to enter the name of the site they would like to delete. It consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/apress/Webparts/chapter 8/JSOMDeleteSite.js"></script>
<div id="DeleteFile">
<div>
<strong>Enter the name of the site to delete:</strong>
<br />
<input type="text" id="txtSiteTitle" />
</div>
<br />
<input type="button" id="btnSubmit" value="Submit" />
</div>
<div id="divResults"></div>
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMDeleteSite.js; include the following code:
$(function () {
bindButtonClick();
});
function bindButtonClick() {
$("#btnSubmit").on("click", function () {
deleteSite();
});
}
function deleteSite() {
var siteTitle = $("#txtSiteTitle").val();
var siteTitleNoSpaces = siteTitle.replace(/\s/g, "");
var siteUrl = _spPageContextInfo.webAbsoluteUrl + "/" + siteTitleNoSpaces;
var clientContext = new SP.ClientContext(siteUrl);
var oWebsite = clientContext.get_web();
oWebsite.deleteObject();
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded() {
$("#divResults").html("Site successfully deleted!");
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
Just like in the previous example, we grab the title of the site that the user entered, and then we remove all the spaces:
var siteTitle = $("#txtSiteTitle").val();
var siteTitleNoSpaces = siteTitle.replace(/\s/g, "");
var siteUrl = _spPageContextInfo.webAbsoluteUrl + "/" + siteTitleNoSpaces;
Once we have the title and have removed the spaces, we need to construct a full URL to the site. We can get the full URL for the current site by using _spPageContextInfo.webAbsoluteUrl and simply appending a / and the site title without spaces on the end. We need to construct a full URL so that we can request the client context for the site that we wish to delete, and not the current site that the user is on:
var clientContext = new SP.ClientContext(siteUrl);
var oWebsite = clientContext.get_web();
Up until now, we have always used the client context for the current site that the user is viewing the page on. However, you can request the context for another site by passing in a URL as a parameter to the SP.ClientContext() method, as we have done in this example. Once we have the context for the site, we get a reference to the root web in that site by using clientContext.get_web(). Just like with all the other delete operations, we simply call the deleteObject() method to request the delete operation:
oWebsite.deleteObject();
The success function will display a message to the user, informing them the delete has taken place.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will display a textbox for the user to enter the site title, and display a result message, as shown in Figure 8-21.
Figure 8-21.
Deleting a subsite via JSOM
In this example, we’ll delete the site that we just recently created. Navigating back to the Site Contents page will show that the subsite was successfully deleted, as shown in Figure 8-22.
Figure 8-22.
The site has been removed from the root site
Working with Social Data
One of the big new areas of SharePoint is social data. If you’re going to be writing custom solutions for SharePoint you will absolutely encounter the need to access social data at some point. This section will demonstrate how to pull some of this data for use in your solutions.
HTML
Create a new HTML file in Visual Studio and name it JSOMGetSocialData.html. The markup for this page will include a couple of DIVs and a SPAN to output data to. It consists of the following lines:
<script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.js"></script>
<script type="text/javascript" src="/_layouts/15/sp.userprofiles.js"></script>
<script type="text/javascript" src="/apress/Webparts/chapter 8/JSOMGetSocialData.js"></script>
<link rel="stylesheet" type="text/css" href="/apress/Webparts/chapter 8/JSOMGetSocialData.css" />
<div id="WelcomeMessage">
Welcome back <span id="WelcomeMessageUserName"></span>
</div>
<div id="UserFollows" />
This example has more references than any other example so far. You’ll notice that in addition to the references to sp.js and sp.runtime.js, we’ve also included a reference to sp.userprofiles.js. As mentioned earlier in this chapter, JSOM functionality is included throughout many different files that serve specific needs. In this example, since we want to get social data for the user, we have to include a reference to the sp.userprofiles.js file in order to access that functionality.
We’ll also include a custom CSS file titled JSOMGetSocialData.css. This will be used to style the output from the script. All of the other examples could have easily included CSS for styling. You’ll find in your custom development efforts that styling will play a big role in a lot of your web parts; so this example will show you how easy it is to include.
JavaScript
Create a new JavaScript file in Visual Studio and name it JSOMGetSocialData.js; include the following code:
$(function () {
ExecuteOrDelayUntilScriptLoaded(getUserProfileProperties, "sp.userprofiles.js");
});
function getUserProfileProperties() {
var clientContext = new SP.ClientContext();
var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);
this.userProperties = peopleManager.getMyProperties();
clientContext.load(userProperties);
var followingManager = new SP.Social.SocialFollowingManager(clientContext);
this.following = followingManager.getFollowed(15);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded() {
$("#WelcomeMessageUserName").text(userProperties.get_displayName());
var followedItems = "Items you are following:<br />";
$.each(following, function( index, value ) {
followedItems += "<a href='" + value.get_uri() + "'>" + value.get_name() + "</a><br />";
});
$("#UserFollows").append(followedItems);
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
In the jQuery Document.ready function, we include the ExecuteOrDelayUntilScriptLoaded built-in function. We need to use this because our JavaScript code relies on the functionality found in sp.userprofiles.js and would cause errors if it ran prior to that file being loaded:
ExecuteOrDelayUntilScriptLoaded(getUserProfileProperties, "sp.userprofiles.js");
Once the getUserProfileProperties function is fired, we obtain a reference to the current client context, and then create a new PeopleManager object with the following code:
var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);
this.userProperties = peopleManager.getMyProperties();
clientContext.load(userProperties);
We can create a new PeopleManager object by using the SP.UserProfiles.PeopleManager() method, passing in the client context as its parameter. The PeopleManager object provides methods for accessing data about users. In this case, we can obtain all the properties for the current user by using the peopleManager.getMyProperties() method, and loading the userProperties variable on the client context.
Next, we’ll get all the items the user is following by using the SocialFollowingManager() object:
var followingManager = new SP.Social.SocialFollowingManager(clientContext);
this.following = followingManager.getFollowed(15);
We can create a new SocialFollowingManager object using the SP.Social.SocialFollowingManager() method, passing in the client context as its parameter. We can then obtain all the “actors” the user is following by using the getFollowed() method. An “actor” is really just anything that the user follows, which can be users, documents, sites, or tags. When you call the getFollowed() method, you need to pass in a number, which corresponds to the actors that you want returned. In this example, we use 15, which indicates all the actors. You can see the full list of values athttp://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.social.socialactortypes(v=office.15).aspx .
The success method in this example is the most complex so far, as we need to show more data than in other examples. First, we’ll get the user name of the current user to display on the page:
$("#WelcomeMessageUserName").text(userProperties.get_displayName());
The userProperties object has many methods to retrieve data; to get the username, we can call the get_displayName() method. Next, we’ll loop through all the followed items to build a list to show the user:
var followedItems = "Items you are following:<br />";
$.each(following, function( index, value ) {
followedItems += "<a href='" + value.get_uri() + "'>" + value.get_name() + "</a><br />";
});
First, we create a new variable to hold all the followed items. Next, we loop through each item using a jQuery each loop. For each item, we call the get_uri() and get_name() methods to construct a link so that the user can jump directly to the item from the page. Finally, we append all the HTML to the page with the following line:
$("#UserFollows").append(followedItems);
CSS
Create a new CSS file in Visual Studio and name it JSOMGetSocialData.css; include the following code:
#WelcomeMessage {
margin-bottom: 20px;
}
#WelcomeMessageUserName {
font-weight: bold;
}
#UserFollows {
border:dashed 1px #C0C0C0;
width:240px;
padding: 6px;
}
This CSS is very basic and only intended to provide a simple demonstration of styling. We’ll apply a bottom margin on the welcome message to the user, and put the user name in bold. The followed items will be wrapped in a dashed border for emphasis.
Results
Set the Content Link property of the Content Editor Web Part to the HTML file and save the page. The page will display a “Welcome back” message to the user, along with their name in bold. Directly underneath is a list of all the items that they are following, displayed as hyperlinks, as shown in Figure 8-23.
Figure 8-23.
Social data being retrieved via JSOM
Summary
In this chapter, we took a deep dive into the JavaScript Object Model (JSOM) and looked at how it can be used to create custom web parts using the Etherson method. We looked at a wide variety of examples: querying for list data, creating new lists and sites, and querying for social data about users. Even though this was a long chapter in comparison to others in this book, it only scratched the surface on what is possible with JSOM in SharePoint. However, after working through all the examples presented here, you should have a very firm grasp on working with JSOM and on how HTML, JavaScript, and CSS all work together in a custom web part. You should now be comfortable enough to begin crafting your own custom solutions using JSOM. In the next chapter, we’ll look at a lot of the same examples and learn how to perform tasks using the REST API.
© Brandon Atkinson 2015
Brandon AtkinsonCustom SharePoint Solutions with HTML and JavaScript10.1007/978-1-4842-0544-0_9