Working with the ECMAScript Client Object Model (JSOM) in SharePoint 2010–Part 3 (Nikhil Sachdeva)
Retrieving Data from Lists and Libraries
The SharePoint team did a great job in ensuring that there is significant similarity in the server and client object models with regards to their syntax and behavior. If you have developed in SharePoint by using the server object model, you likely noticed that most operations in the client object model are similar to the operations you perform when using the server object model.
The following discussion demonstrates some common list operations that can be performed using JSOM. You may want to display the monthly sales of an employee and track them against the annual target sales. The sales target is defined based on their role in the organization. You want to provide a Sales Target View where management can view the current Sales achieved by an employee and compare it against its Sales Target. You select an employee from a list that displays the sales achieved by the employee. Finally, you want to show whether the employee is an "Achieved", "Lagging Behind" or "Super Performer" by comparing the total of the sales achieved with the configured Sales Target for the employee role.
For this purpose, a simple Web Part and some custom lists has been created that allows the users to select an employee and then display their sales information. First, create a custom list called Employee which stores general information about the employee (no AD sync for now). The following diagram shows how the employee list looks.
The sales target is based on a role and stored in another list named SalesTarget.
To track the monthly sales for each employee, another list named Sales is created which stores details about each Sale associated with the employee.
The UI looks similar to the following.
Retrieving All Items in a List
To begin, you want to display all the employees in the Employee list so that management can choose which employee data to view. For this purpose, you add a button named GetEmployees and bind the Click event of this button to call a Javascript method. The method leverages JSOM to populate a radio list with all employees in the organization. The following is a sample of the get_employees() method.
function get_Employees(control) {
try {
this.baseControl = control;
this.controlToLoad = control + "_chkEmployeeList";
var context = new SP.ClientContext.get_current();
// Load the web object
this.web = context.get_web();
//Get the list
var list = this.web.get_lists().getByTitle('Employee');
// Get all the items in the list
employees = list.getItems('');
// Load the web in the context and retrieve only selected columns to improve performance
context.load(this.employees, 'Include(ID,EmployeeName,Role)');
//Make a query call to execute the above statements
context.executeQueryAsync(Function.createDelegate(this, this.get_Employees_onSuccess), Function.createDelegate(this, this.get_Employees_onFailure));
}
catch (e)
{
alert("An error occurred while fetching data. Please contact your system administrator.");
}
}
To analyze what is happening in the get_Employees method, consider the following:
First you retrieve the current context by calling SP.ClientContext.get_Current(); remember that because the JSOM is running under the current site context, you do not need to specify any Url to connect to.
When you have the context, a call is made to get the current web this.web = context.get_web().
The get_lists() method of the current web object returns all of the lists in the current web and the getByTitle () filters it down to the Employee list.
Now, you simply call the getItems() method on the list. Notice that, in this case, you pass an empty string to specify that all items are returned. You must pass an empty string here; if you simply pass nothing as a parameter, you will generate an exception.
The context type provides a load method which is responsible for loading objects and collections from the server . The SP.Context type provides two variants of load which serve different purposes:
Load: This is also called as an In-Place load. This load variant should be used when you want to load objects and collection and maintain their state through multiple requests. Essentially, whatever object that you pass into the load method is populated and can be used as-is in subsequent requests.
LoadQuery: The LoadQuery variant returns a new instance or collection every time it is called. This is beneficial when you want to return an enumerator to the object which you want to maintain yourself.
Both the variant can take a parameter that defines which columns to return. For loading a singular object, you simple pass the names of the columns separated by commas as followings:
context.load(<object>,'<Field1>','<Field2>','<Field3>');
In case the object is a collection, you can still specify the columns to include in the load operation by using the following format 'Include(<Column1>, <Column2>,<Column3>, …) ' format.
context.load(<objectCollection>,'Include(<Field1>,<Field2>,<Field3>');
Note that if you want to access the child properties of an object, you must load the object (by calling the ExecuteQueryAsync method) before you can access it; otherwise, you will generate an exception such as the following:
The property or field has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
The client object model provides you with the flexibility of executing statements in batches. This is a major performance boost because you do not have to go back and forth to the server to access each object. Considering the previous example, you are making calls on the context, web, and list objects but do not have instances of these objects available as of yet. Only when you make a call to the ExecuteQueryAsync method is a request generated and then sent to the server for processing.
JSOM only supports the asynchronous version of ExecuteQuery and so you need to provide two callback methods whenever you make a call to ExecuteQueryAsync; these methods specify the success and failure callback methods to call on the client when the request has been processed.
When the query has been executed, a call is made to the success or failure callback method depending on the response returned. You can then access properties and method for the loaded object. For example, the following code snippet uses the getEnumerator () method to retrieve the returned employee collection and then access the FieldValues of each item by using the get_item ('<FieldName>') methods.
function get_Employees_onSuccess() {
// Get the collection
var employeeCollection = this.employees.getEnumerator();
// get the control
var chkBoxList = document.getElementById(this.controlToLoad);
// get the checkbox group
while (employeeCollection.moveNext()) {
var employee = employeeCollection.get_current();
addRowForEmployeeList(this.controlToLoad, employee.get_item('ID'), employee.get_item('EmployeeName'), employee.get_item('Role'));
}
}
function get_Employees_onFailure() {
alert("An error occurred while fetching data. Please contact your system administrator.");
}
Retrieving Specific Items by Id
JSOM supports properties and methods similar to the server object model to retrieve specific items. The following code snippet retrieves an object based on it ListItem ID.
function get_EmployeeById(employeeId) {
try {
var context = new SP.ClientContext.get_current();
this.web = context.get_web();
var list = this.web.get_lists().getByTitle('Employee');
this.employee = list.getItemById(employeeId);
context.load(this.employee, 'EmployeeName', 'Role');
context.executeQueryAsync(Function.createDelegate(this, this.get_Employee_onSuccess), Function.createDelegate(this, this.get_Employee_onFailure));
}
catch (e) {
alert("An error occurred while fetching data. Please contact your system administrator.");
}
}
Retrieving Specific Items by Using CAML
You can also use the SharePoint CAML query language to filter data when loading objects. The client object model provides a SP.CamlQuery type that is used to pass a CAML query when the object is loaded. Simply assign your CAML query string to the set_viewXml method of CamlQuery and pass it to the object that supports it (for example, getItems(CamlQuery).
In the following code, you use a CAML query to retrieve the sales data for an employee:
function get_EmployeeSales(employeeName) {
try {
this.controlToLoad = this.baseControl + "_" + "tblEmployeeSales";
var context = new SP.ClientContext.get_current();
// Load the web object
this.web = context.get_web();
//Get the list
var list = this.web.get_lists().getByTitle('Sales');
// Get all items based on query
var query = '<View Scope=\'RecursiveAll\'>' +
'<Query>' +
'<Where>' +
'<Eq>' +
'<FieldRef Name=\'EmployeeName\' />' +
'<Value Type=\'LookUp\'>' + employeeName + '</Value>' +
'</Eq>' +
'</Where>' +
'</Query>' +
'</View>';
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml(query);
this.salesDetails = list.getItems(camlQuery);
// Load the web in the context and retrieve only selected columns to improve performance
context.load(this.salesDetails, 'Include(ID,EmployeeName,SalesAchieved,SaleDate,Customer,Title)');
//Make a query call to execute the above statements
context.executeQueryAsync(Function.createDelegate(this, this.get_EmployeeSales_onSuccess), Function.createDelegate(this, this.get_EmployeeSales_onFailure));
}
catch (e) {
alert("error occurred" + e.toString());
}
}
Property Getters and Setters in JSOM
If you look closely at the type signatures, you will notice that the JSOM properties are different in their naming conventions as compared to CSOM or the server object model. Basically, JSOM provides a getter and setter model for most properties of SharePoint objects. Any value that needs to be accessed can be obtained by using the get_<PropertyName> methods for the corresponding object; similarly any property assignments can be performed by using the set_<PropertyName> methods for the objects. You can find information about the various methods available in the SP namespace.
In this post, you saw the various ways to retrieve items from a SharePoint list. In the next post, you work on some data manipulation operations that you can perform on a list.
Technorati Tags: Nikhil Sachdeva,ECMAScript Client Object Model,JSOM
Comments
Anonymous
July 16, 2012
employees.getEnumerator() throwing an exception " The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested" Please help!!!Anonymous
August 29, 2012
Link to part 4 blogs.msdn.com/.../working-with-the-ecmascript-client-object-model-jsom-in-sharepoint-2010-part-4-nikhil-sachdeva.aspxAnonymous
October 01, 2012
Nice, but I wish you would have included all your code (e.g. addRowForEmployeeList and get_EmployeeSales_onSuccess).Anonymous
November 01, 2012
I agree with Reggie. The only thing an asyncronyous call can do is display an alert to the user in the form of a popup. Form fields cannot be populated and global variables cannot be used. This really has no purpose.Anonymous
February 07, 2013
what is the point of only being able to throw alert boxes instead of return values?Anonymous
May 27, 2013
is there any best practices for using ECMA script?