Working with Discussions List via SharePoint Client Object Model

Overview

In this post  will be demonstrated how to perform a common CRUD operations when working with Discussions List via  Client Object Model (JavaScript CSOM) in SharePoint 2010/2013.

Create a Discussion

So, let’s get started with creating a Discussion item. SP.Utilities.Utility.createNewDiscussion method is used for creating a discussion item:

function createDiscussion(listTitle,properties,OnItemAdded,OnItemError)
{
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle(listTitle);
context.load(list);
var discussionItem = SP.Utilities.Utility.createNewDiscussion(context, list, properties.Subject);
for(var propName in properties) {
if(propName == 'Subject') continue;
discussionItem.set_item(propName, properties[propName])
}
discussionItem.update();
context.load(discussionItem);
context.executeQueryAsync(
function() {
OnItemAdded(discussionItem);
},
OnItemError
);
}

view raw
createDiscussion.js
hosted with ❤ by GitHub

Load all Discussions

Since Discussion Content Type derives from Folder Content Type  we could utilize SP.CamlQuery.createAllFoldersQuery method to construct a query to retrieve all the discussions:

function getDiscussions(listTitle,OnItemsLoaded,OnError)
{
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle(listTitle);
context.load(list);
var qry = SP.CamlQuery.createAllFoldersQuery();
var discussionItems = list.getItems(qry);
context.load(discussionItems);
context.executeQueryAsync(
function() {
OnItemsLoaded(discussionItems);
},
OnError
);
}

view raw
getDiscussions.js
hosted with ❤ by GitHub

Create a Message

The SP.Utilities.Utility.createNewDiscussionReply method is used to create a Message item (add reply to a discussion item):

function createMessage(discussionItem,properties,OnItemAdded,OnItemError)
{
var context = new SP.ClientContext.get_current();
var messageItem = SP.Utilities.Utility.createNewDiscussionReply(context, discussionItem);
for(var propName in properties) {
messageItem.set_item(propName, properties[propName])
}
messageItem.update();
context.executeQueryAsync(
function() {
OnItemAdded(messageItem);
},
OnItemError
);
}
function createMessages(discussionItem,messagesProperties,OnItemsAdded,OnItemsError)
{
var context = new SP.ClientContext.get_current();
var messageItems = [];
$.each(messagesProperties, function (i, properties) {
messageItems.push(SP.Utilities.Utility.createNewDiscussionReply(context, discussionItem));
for(var propName in properties) {
messageItems[i].set_item(propName, properties[propName])
}
messageItems[i].update();
});
context.executeQueryAsync(
function() {
OnItemsAdded(messageItems);
},
OnItemsError
);
}

view raw
createMessage.js
hosted with ❤ by GitHub

Load all Messages

Since message items  are contained within discussion container (Folder) , to identify messages by discussion we will use SPBuiltInFieldId.ParentFolderId field in CAML query:

function getMessages(listTitle,disscussionId,OnItemsLoaded,OnError)
{
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle(listTitle);
context.load(list);
var qry = createAllMessagesByDisscussionIDQuery(disscussionId);
var messageItems = list.getItems(qry);
context.load(messageItems);
context.executeQueryAsync(
function() {
OnItemsLoaded(messageItems);
},
OnError
);
}
function createAllMessagesByDisscussionIDQuery(disscussionId) {
var qry = new SP.CamlQuery;
var viewXml = "<View Scope='Recursive'> \
<Query> \
<Where> \
<Eq> \
<FieldRef Name='ParentFolderId' /> \
<Value Type='Integer'>" + disscussionId + "</Value> \
</Eq> \
</Where> \
</Query> \
</View>";
qry.set_viewXml(viewXml);
return qry;
};

view raw
getMessages.js
hosted with ❤ by GitHub

Import Discussion List

And finally in order to see how to work with Discussions List in action,  let’s discuss one more example.  Suppose we need to import Discussions List content from an external source, let’s say from Stack Exchange. To access Stack Exchange content (Questions and Answers in our case) we will utilize Stack Exchange API:

function DiscussionBoardImporter()
{
this.sourceQuery = '/2.1/questions?order=desc&sort=votes&site=sharepoint&filter=!-.AG)sL*gPlV';
this.targetDiscussionsListName = 'Discussions List';
}
DiscussionBoardImporter.prototype = (function() {
var importData = function(data,discussionsListName)
{
$.each(data, function (i, question) {
var discussionProperties = {'Body': question.body,'Subject':question.title,'VoteNumber': question.score};
createDiscussion(discussionsListName,discussionProperties,
function(discussionItem){
console.log('Discussion ' + discussionItem.get_item('Title') + ' has been created successfully');
var messagesProperties = [];
$.each(question.answers, function (j, answer) {
messagesProperties.push({'Title': answer.title,'Body': answer.body});
});
createMessages(discussionItem,messagesProperties,
function(){
console.log('Messages have been created successfully');
},
function(sender,args){
console.log('Error occured while creating messages:' + args.get_message());
}
);
},
function(sender,args){
console.log('Error occured while creating disscussion:' + args.get_message());
});
});
};
var loadData = function(query,targetListName, loaded)
{
$.ajax({
url: 'http://api.stackexchange.com&#39; + query,
dataType: 'json',
success: function(data) {
loaded(data.items,targetListName);
}
});
};
return {
constructor:DiscussionBoardImporter,
import: function()
{
loadData(this.sourceQuery,this.targetDiscussionsListName,importData);
}
};
})();
var importer = new DiscussionBoardImporter();
importer.import();

How to populate a SharePoint List via CSOM

Overview

Populating a SharePoint List with data is  required for different purposes quite often. In this article I am going to demonstrate how to populate Contacts list with a fake data using CSOM.

Provision column to a List via SharePoint CSOM

We will utilize Contacts List for demonstration purposes. But before we  proceed, let’s add a Geolocation field to a list.

Since the Geolocation column is not available by default in SharePoint lists, it’s common practice to provision this field to a list programmatically. The code below demonstrates  how to add the Geolocation field  by using the SharePoint client object model:

function ProvisionField(fieldSchema, listTitle,OnSuccess,OnError)
{
var context = SP.ClientContext.get_current();
var list = context.get_web().get_lists().getByTitle(listTitle);
var fields = list.get_fields();
var fieldToAdd = fields.addFieldAsXml(fieldSchema, true, SP.AddFieldOptions.AddToDefaultContentType);
fieldToAdd.update();
context.load(fieldToAdd);
context.executeQueryAsync(OnSuccess(fieldToAdd),OnError);
}
function AddGeolocationFieldToContactsList()
{
ProvisionField("<Field Type='Geolocation' DisplayName='Location'/>","Contacts",
function(field){
console.log('Geolocation field has been added');
},
function(sender,args){
console.log('Error occured while adding Geolocation field:' + args.get_message());
})
}

Generate list data

For populating Contacts list we will utilize Faker.js JavaScript library that is intended for generating massive amounts of fake data, below is provided the complete code:

function AddListItem(listTitle,itemProps,OnItemAdded,OnItemError)
{
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle(listTitle);
var itemCreateInfo = new SP.ListItemCreationInformation();
var listItem = list.addItem(itemCreateInfo);
for(var propName in itemProps) {
listItem.set_item(propName, itemProps[propName])
}
listItem.update();
context.load(listItem);
context.executeQueryAsync(
function() {
OnItemAdded(listItem);
},
OnItemError
);
}
function GenerateContacts()
{
var contactsCount = 108;
for(var i = 0; i < contactsCount; i++){
var contactEntry = CreateContactEntry();
AddListItem('Contacts',contactEntry,
function(contactItem){
console.log('Contact ' + contactItem.get_item('Title') + ' has been created successfully');
},
function(sender,args){
console.log('Error occured while creating contact:' + args.get_message());
});
}
}
function CreateContactEntry()
{
var contactCard = Faker.Helpers.createCard();
return {'Title': contactCard.username,
'FullName': contactCard.name,
'Email': contactCard.email,
'Company': contactCard.company.name,
'WorkPhone': contactCard.phone,
'WorkAddress': contactCard.address.streetA,
'WorkCity': contactCard.address.city,
'WorkZip': contactCard.address.zipcode,
'WorkCountry': contactCard.address.ukCountry,
'WebPage': 'http://&#39; + contactCard.website,
'Location': 'Point(' + contactCard.address.geo.lng + ' ' + contactCard.address.geo.lat + ')'};
}
var scriptbase = _spPageContextInfo.siteAbsoluteUrl + '/_layouts/15/';
$.getScript(scriptbase + 'SP.js',
function () {
$.getScript(_spPageContextInfo.siteAbsoluteUrl + '/SiteAssets/Faker.js', GenerateContacts);
}
);

view raw
GenerateListData.js
hosted with ❤ by GitHub

Results

After running the script the Contacts list will be populated with a fake data as demonstrated below.

Contacts default view

Contacts

Contacts map view

ContactsMap

References