Sharepoint: How to easily get related child items using JSOM - sharepoint

Suppose I have 2 Lists: Teams and Employees. Each team has a number of employees:
Teams
ID
Name
Employees
ID
Name
TeamID (foreign key of Teams)
Is it possible to write a query in SharePoint JSOM such that I could do something along the following lines (after the query executes/loads):
var employeesListItems = teamListItem.get_item("Employees")
Does SharePoint Object Model support this in any way?
Clarification: my intent is to reuse the ClientObject as much as I can. I understand that I could query for all employees and all teams, create an array of custom objects for each, and then iterate over employees and push them to onto the "Employees" field of the related Team object. I would like to avoid doing so.

Even though SharePoint CAML supports List Joins and Projections, in that case I would suggest you a different approach.
The following example demonstrates how to retrieve parent/child items using a single request:
function getItemWithDetails(parentListTitle,childListTitle,lookupFieldName,lookupFieldValue,success,error)
{
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var lists = web.get_lists();
var parentList = lists.getByTitle(parentListTitle);
var parentItem = parentList.getItemById(lookupFieldValue);
var childList = lists.getByTitle(childListTitle);
var childItems = childList.getItems(createLookupQuery(lookupFieldName,lookupFieldValue));
ctx.load(parentItem);
ctx.load(childItems);
ctx.executeQueryAsync(
function() {
success(parentItem,childItems);
},
error
);
}
function createLookupQuery(lookFieldName,lookupFieldValue)
{
var queryText =
"<View>" +
"<Query>" +
"<Where>" +
"<Eq>" +
"<FieldRef Name='{0}' LookupId='TRUE'/>" +
"<Value Type='Lookup'>{1}</Value>" +
"</Eq>" +
"</Where>" +
"</Query>" +
"</View>";
var qry = new SP.CamlQuery();
qry.set_viewXml(String.format(queryText,lookFieldName,lookupFieldValue));
return qry;
}
Usage
var parentListTitle = 'Teams';
var childListTitle = 'Employees'
var lookupFieldValue = 1;
var lookupFieldName = 'Team';
getItemWithDetails(parentListTitle,childListTitle,lookupFieldName,lookupFieldValue,
function(teamItem,employeeItems){
//print parent item
console.log(teamItem.get_item('Title'));
//print child items
for(var i = 0; i < employeeItems.get_count(); i++){
var employeeItem = employeeItems.getItemAtIndex(i);
console.log(employeeItem.get_item('Title'));
}
},
function(sender,args){
console.log(args.get_message());
});
Another option is to utilize List Joins and Projections. The following example demonstrates how to retrieve employee list items with projected team items
function getListItems(listTitle,joinListTitle,joinFieldName,projectedFields,success,error)
{
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getByTitle(listTitle);
var items = list.getItems(createJoinQuery(joinListTitle,joinFieldName,projectedFields));
ctx.load(items);
ctx.executeQueryAsync(
function() {
success(items);
},
error
);
}
function createJoinQuery(joinListTitle,joinFieldName,projectedFields)
{
var queryText =
"<View>" +
"<Query/>" +
"<ProjectedFields>";
for(var idx in projectedFields) {
queryText += String.format("<Field Name='{0}_{1}' Type='Lookup' List='{0}' ShowField='{1}' />",joinListTitle,projectedFields[idx]);
}
queryText +=
"</ProjectedFields>" +
"<Joins>" +
"<Join Type='INNER' ListAlias='{0}'>" +
"<Eq>" +
"<FieldRef Name='{1}' RefType='Id'/>" +
"<FieldRef List='{0}' Name='ID'/>" +
"</Eq>" +
"</Join>" +
"</Joins>" +
"</View>";
var qry = new SP.CamlQuery();
qry.set_viewXml(String.format(queryText,joinListTitle,joinFieldName));
return qry;
}
Usage
var listTitle = 'Employees';
var joinListTitle = 'Teams'
var joinFieldName = 'Team';
var projectedFields = ['ID','Title'];
getListItems(listTitle,joinListTitle,joinFieldName,projectedFields,
function(employeeItems){
//print items
for(var i = 0; i < employeeItems.get_count(); i++){
var employeeItem = employeeItems.getItemAtIndex(i);
var employeeName = employeeItem.get_item('Title');
var teamName = employeeItem.get_item('Teams_Title').get_lookupValue();
console.log(employeeName + ',' + teamName);
}
},
function(sender,args){
console.log(args.get_message());
});

Probably you can not achieve what you want, because of lookup configuration. But you could do the following:
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var lists = web.get_lists();
var teams = lists.getByTitle("Teams");
var employees = lists.getByTitle("Employees");
//just get the first item
var employee = employees.getItemById(1);
ctx.load(employee)
ctx.executeQueryAsync(function() {
var team = employee.get_item("TeamID");
// both the id and the value of the lookup field
var lookupId = team.get_lookupId();
var lookupValue = team.get_lookupValue();
// let's grab all the fields
var fullTeam = teams.getItemById(lookupId)
ctx.load(fullTeam)
ctx.executeQueryAsync({
var name = fullTeam.get_item("Name");
alert("We can get the Name field of the lookup field: " + name);
});
});
I guess, it a bit reverse of what you really intent to achieve but still this way you will exploit CSOM.

Related

Xpages - Adding a Key to NotesViewNavigator

I'm returning values from two different columns but will like to narrow down the results by using a key.
And below is my code which returns all. Efforts to use keys returns in mistypes.
var v:NotesView = database.getView("myView");
var key = getComponent("key").getValue();
var nav:NotesViewNavigator = v.createViewNavFromCategory(key);
//solved by replacing-v.createViewNav();
var entry:NotesViewEntry = nav.getFirst();
var list = new java.util.Vector();
while (entry != null) {
var tabs:string = "";
for (var i=0; i<entry.getIndentLevel(); i++) tabs = tabs + "\t";
requestScope.status += "\n" + tabs + entry.getColumnValues().elementAt(entry.getIndentLevel()).toString();
list.addElement(entry.getColumnValues().elementAt(entry.getIndentLevel()).toString());
var tmpentry:NotesViewEntry = nav.getNextCategory();
entry.recycle();
entry = tmpentry;
}
print(requestScope.status);
return list;
Will be pleased with your help.

Extracting information from "Created By" field

Is there any way I could extract the department or email information from the "Created By" field in a custom list?
You should be more specific how you want to extract the information, if it's javascript or c# or via UI.
Here is a simple example, maybe you can do something with it. Let me know if you have any questions.
var ctx = new SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getByTitle('Kalender');
//this query can be done in other ways, I'm getting all items
var query = SP.CamlQuery.createAllItemsQuery();
var items = list.getItems(query);
ctx.load(items);
ctx.executeQueryAsync(function () {
var itemsEnum = items.getEnumerator();
while (itemsEnum.moveNext()) {
var item = itemsEnum.get_current();
var author = item.get_item('Author');
console.log("Email: " + author.get_email());
console.log("Name: " + author.get_lookupValue());
console.log("ID: " + author.get_lookupId());
}
}, function(sender, args) {
console.log(args.get_message());
});

Update ProjectedField with JOIN in Sharepoint using Javascript client object model

Suppose I have 2 Lists: Teams and Employees. Each team has a number of employees:
Teams
ID
Name
Employees
ID
Name
TeamID (foreign key of Teams)
If I created a Join query of Employees LEFT JOIN Teams, could I then set_item and update the Name field in Teams?
var ctx = SP.ClientContext.get_current();
var list = clientContext.get_web().get_lists().getByTitle('Employees');
var queryText =
"<View>" +
"<Query></Query>" +
"<ProjectedFields>" +
"<Field Name='TeamName' Type='Lookup' List='Team' ShowField='Name' />" +
"</ProjectedFields>" +
"<Joins>" +
"<Join Type='INNER' ListAlias='Team'>" +
"<Eq>" +
"<FieldRef Name='TeamID' RefType='Id'/>" +
"<FieldRef List='Team' Name='ID'/>" +
"</Eq>" +
"</Join>" +
"</Joins>" +
"<ViewFields>" +
"<FieldRef Name='TeamName'/>" +
"</ViewFields>" +
"</View>";
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml(queryText);
var listItemsCollection = list.getItems(camlQuery);
ctx.executeQueryAsync(onSuccess, onError);
And then, update the TeamName field:
var first = listItemsCollection.get_data()[0];
first.set_item("TeamName", "something");
first.update();
ctx.executeQueryAsync(onSuccess, onError);
Is this supported? (I currently have not way of trying this)
If not, what could be the alternative?
No, only those fields that contains list item could be updated. But you could consider the following approach for updating projected fields.
Since projected fields are returned as lookup values, you could retrieve projected list item and update it's properties as demonstrated below:
var listTitle = 'Employees';
var joinListTitle = 'Teams'
var joinFieldName = 'TeamID';
var projectedFields = ['Name'];
getListItems(listTitle,joinListTitle,joinFieldName,projectedFields,
function(items){
var item = items.get_data()[0]; //get first item
var itemId = item.get_item('TeamsName').get_lookupId(); //get projected list item id
var propertiesToUpdate = {'Name': 'New Team Name'};
updateListItem(joinListTitle,itemId,propertiesToUpdate,function(item){
console.log('List Item has been updated');
},
logError);
},
logError);
where
function createJoinQuery(joinListTitle,joinFieldName,projectedFields,joinType)
{
var queryText =
"<View>" +
"<Query/>" +
"<ProjectedFields>";
for(var idx in projectedFields) {
queryText += String.format("<Field Name='{0}{1}' Type='Lookup' List='{0}' ShowField='{1}' />",joinListTitle,projectedFields[idx]);
}
queryText +=
"</ProjectedFields>" +
"<Joins>" +
"<Join Type='{2}' ListAlias='{0}'>" +
"<Eq>" +
"<FieldRef Name='{1}' RefType='Id'/>" +
"<FieldRef List='{0}' Name='ID'/>" +
"</Eq>" +
"</Join>" +
"</Joins>" +
"</View>";
var qry = new SP.CamlQuery();
qry.set_viewXml(String.format(queryText,joinListTitle,joinFieldName,joinType));
return qry;
}
function getListItems(listTitle,joinListTitle,joinFieldName,projectedFields,success,error)
{
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getByTitle(listTitle);
var items = list.getItems(createJoinQuery(joinListTitle,joinFieldName,projectedFields,'INNER'));
ctx.load(items);
ctx.executeQueryAsync(
function() {
success(items);
},
error
);
}
function updateListItem(listTitle,itemId, propertiesToUpdate,success,error)
{
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getByTitle(listTitle);
var listItem = list.getItemById(itemId);
for(var name in propertiesToUpdate) {
listItem.set_item(name,propertiesToUpdate[name]);
}
listItem.update();
ctx.executeQueryAsync(function() {
success(listItem);
},error);
}

CAML query contains does not work

I've got this code, which takes a part of the title to perform a query and filter part of the content of a list:
<script type="text/javascript">
var items_lista;
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', Initialize);
function Initialize() {
var PDP_Link_Filter = $("title").text().split("-")[1].split(".")[0];
PDP_Link_Filter = "Link_" + PDP_Link_Filter + "_";
var contexto = SP.ClientContext.get_current();
var web = contexto.get_web();
var listas = web.get_lists();
var parametros = listas.getByTitle('Parametrizacion_WF');
var query = new SP.CamlQuery();
query.set_viewXml("<Query><Where><Contains><FieldRef Name='Title'/>" +
"<Value Type='Text'>" + PDP_Link_Filter + "</Value></Contains></Where></Query>");
console.log(query);
items_lista = parametros.getItems(query);
contexto.load(items_lista);
contexto.executeQueryAsync(Function.createDelegate(this, this.onRequestSucceeded), Function.createDelegate(this, this.onRequestFailed));
} //Initialize
function onRequestSucceeded()
{
console.log(items_lista);
for(i = 0; i < items_lista.get_count(); i++)
{
console.log(items_lista.get_item(i).get_item('Title'));
}
}
function onRequestFailed() { console.log('Error'); }
</script>
The query filter that it generates (obtained through console.log()):
<Query><Where><Contains><FieldRef Name='Title'/><Value Type='Text'>P000</Value></Contains></Where></Query>
But when the for loop runs it shows all the content of the list not just the rows that match the filter.
What am I doing wrong?
This is most probably related with malformed value for SP.CamlQuery.viewXml property. Since this property expects XML schema that defines the list view, the root element has to be View element, for example:
var ctx = SP.ClientContext.get_current();
var list = ctx.get_web().get_lists().getByTitle(listTitle);
var items = list.getItems('<View Scope="RecursiveAll"><Query></Query></View>');
In your case enclose the query with View element:
<View>
<Query>...</Query>
</View>

prevent double meeting sharepoint calendar csom

I am trying to make it if the date and time are already booked in the calender dont book, i am using this code and nothing get displayed? Any Sugestions?
var context = SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists();
var targetList;
function createItem() {
targetList = list.getByTitle("AppbokningarList");
var listItemCreation = new SP.ListItemCreationInformation();
var newItem = targetList.addItem(listItemCreation);
var listItemTitle = document.getElementById('Textrubrik').value;
alert(listItemTitle);
var listItemCustom = document.getElementById('datepicker').value;
alert(listItemCustom);
var listItemFromTime = document.getElementById('timepicker').value;
alert(listItemFromTime);
var listItemtoDate = document.getElementById('datepickerto').value;
alert(listItemtoDate);
var listItemToTime = document.getElementById('timepickerTo').value;
alert(listItemToTime);
var listItemBeskrivning = document.getElementById('Textbeskrivning').value;
alert(listItemBeskrivning);
newItem.set_item('Title', listItemTitle);
var result = listItemCustom + " " + listItemFromTime;
newItem.set_item('EventDate', result);
var result2 = listItemtoDate + " " + listItemToTime;
newItem.set_item('EndDate', result2);
newItem.set_item('Description', listItemBeskrivning);
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<Where><Geq><FieldRef Name='EventDate' /><Value Type='DateTime'>" + result + "</Value></Geq><Leq><FieldRef Name='EndDate' /><Value Type='DateTime'>" + result2 + "</Value></Leq><FieldRef Name='RecurrenceID' /></Where>");
this.collListItem = targetList.getItems(camlQuery);
context.load(collListItem);
var property = new SP.EventProperties();
if (collListItem > 0) {
property.cancel = true;
}
newItem.update();
context.load(newItem);
context.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded),Function.createDelegate(this, this.onQueryFailed));
}
function onQuerySucceeded(sender, args) {
var succeded = "Mötet är nu bokat!";
alert(succeded);
}
function onQueryFailed(sender, args) {
var failed = "Redan bokat!";
alert(failed);
}
Look at all your set_items. Most likely your date fields need an actual date object to be stored successfully to SP.
var currDate = new Date();
listItem.set_item('DateColumn',currDate);
listItem.update();
Cool stuff here to: http://alexeybbb.blogspot.com/2012/09/sharepoint15-js-update-datetime-field.html

Resources