<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<h1>See comments and open the console</h1>
</body>
</html>
// Stub object
var spService = {
ConvertSelectPropertiesToViewFields(){
return 'fake';
},
GetListItems(){
return Promise.resolve({
getEnumerator(){
var index = 0;
var createJobValue = name => ({
get_lookupValue(){
return name;
}
});
var createFakeItem = (id) => ({
get_item(propertyName){
if(propertyName == 'PwC_JobCodesMulti') return [createJobValue('alpha'), createJobValue('beta'), createJobValue('gama')];
if(propertyName == 'ID') return id;
return 'value for '+propertyName;
}
});
var fakeItems = [
createFakeItem(1),
createFakeItem(2),
createFakeItem(3)
];
return {
moveNext(){
index++;
return index < fakeItems.length;
},
get_current(){
return fakeItems[index];
}
}
}
});
}
};
function GetRelatedBillingDocumentsFromList(selectProperties, currentBillCyclePath, clientCode, jobCodes, engagementCode, enhanceFunctions) {
var webUrl = 'some URL';
var viewFields = 'im not using it in this mock example';
var camlQuery = 'im not using it in this mock example';
var billCyclesListId = '{c23bbae4-34f7-494c-8f67-acece3ba60da}';
return spService
.GetListItems(billCyclesListId, camlQuery, selectProperties)
.then(getEnumerator)
.then(enumeratorToArray)
.then(processListItems);
function getEnumerator(result){
return result.getEnumerator();
}
/*
Helper function to avoid checking if listItem is defined later, and get rid of enumerator
*/
function enumeratorToArray(enumerator){
var temp = [];
if(!enumerator) return temp;
while (enumerator.moveNext()){
temp.push(enumerator.get_current());
}
return temp;
}
/*
At this point we always have an empty or filled array!
*/
function listItemToValue(listItem){
return selectProperties
.map(extractListItemProperty)
.map(stringifyJobTitle)
.reduce(fillObject, {});
function extractListItemProperty(property) {
return {
property,
item: listItem.get_item(property)
}
}
function extractLookupValue(jobValue) {
return jobValue.get_lookupValue();
}
function stringifyJobTitle(value) {
var jobTitle = value.item;
return {
property: value.property,
jobTitle: Array.isArray(jobTitle) ? jobTitle.map(extractLookupValue).join(';') : jobTitle
};
};
function fillObject(objectToFill, value) {
objectToFill[value.property] = value.jobTitle;
return objectToFill;
};
}
function addContentType(listItem){
var promise = getContentTypeOfCurrentItem(listItem.ID.toString());
promise.then(function(cname){
listItem['Document Type'] = cname; //we add the doc type to each listItem, not only the last one
});
return promise;
}
function processListItems(listItems) {
var listItemsWithValues = listItems.map(listItemToValue);
var promises = listItemsWithValues.map(addContentType);
Promise.all(promises).then(youCanUseTheData);
function youCanUseTheData(){
/*
At this point, each listItem holds the 'Document Type' info
*/
listItemsWithValues.forEach(function (listItem) {
console.log(listItem);
});
}
}
}
function getContentTypeOfCurrentItem(id) {
return Promise.resolve('fake id for '+id);
}
/*
TESTING
*/
GetRelatedBillingDocumentsFromList(['ID', 'PwC_JobCodesMulti']);
/* Styles go here */
// cname is always undefined, because getContentTypeOfCurrentItem returns nothing
var cname = getContentTypeOfCurrentItem(listItemValues['ID'].toString());
listItemsWithValues['Document Type'] = cname;
function GetRelatedBillingDocumentsFromList(selectProperties, currentBillCyclePath, clientCode, jobCodes, engagementCode, enhanceFunctions) {
$log.info('Retrieving related billing documents for bill cycle with name [' + currentBillCyclePath + ']');
var deferred = $q.defer();
var webUrl = _spPageContextInfo.webAbsoluteUrl;
var viewFields = spService.ConvertSelectPropertiesToViewFields(selectProperties);
// query must return the documents for the same client but in other bill cycles not the current one
var camlQuery = '<View Scope="RecursiveAll">' + viewFields +
'<Query>' +
'<Where>' +
'<And>' +
'<Eq>' +
'<FieldRef Name="ClientCode" />' +
'<Value Type="Text">' + clientCode + '</Value>' +
'</Eq>' +
'<Neq>' +
'<FieldRef Name="ContentType" />' +
'<Value Type="Computed">Bill Cycle</Value>' +
'</Neq>' +
'</And>' +
'</Where>' +
'</Query>' +
'</View>';
var billCyclesListId = '{c23bbae4-34f7-494c-8f67-acece3ba60da}';
spService.GetListItems(billCyclesListId, camlQuery, selectProperties)
.then(function (listItems) {
var listItemsWithValues = []; // creating an empty array to get filled later is a map
if (listItems) {
var enumerator = listItems.getEnumerator();
var promises = [];
while (enumerator.moveNext()) {
var listItem = enumerator.get_current();
var listItemValues = []; // this is an object, not an array, you're using it as a dictionary
selectProperties
.forEach(function (propertyName) {
var value = listItem.get_item(propertyName);
if (propertyName === 'PwC_JobCodesMulti') {
jobvalue = '';
value.forEach(function (jobvalues) {
jobvalue += jobvalues.get_lookupValue() + ';';
});
listItemValues[propertyName] = jobvalue;
} else {
listItemValues[propertyName] = value;
}
//listItemValues[propertyName] = value;
});
listItemsWithValues.push(listItemValues);
}
// you're using only the last ocurrence here, i think is not the intention
var cname = getContentTypeOfCurrentItem(listItemValues['ID'].toString());
listItemsWithValues['Document Type'] = cname;
}
listItemsWithValues.forEach(function (listItem) {
var fileDirRef = listItem['FileRef'];
var id = listItem['ID'];
var title = listItem['Title'];
var serverUrl = _spPageContextInfo.webAbsoluteUrl.replace(_spPageContextInfo.webServerRelativeUrl, '');
var dispFormUrl = serverUrl + '/sites/billing/_layouts/15/DocSetHome.aspx?id=' + fileDirRef;
//listItem["FileRef"] = dispFormUrl;
//listItem["Bill Cycle"] = dispFormUrl;
var parentLink = listItem['FileRef'];
arrayofstrings = parentLink.split('/');
var billCycleFolderName = arrayofstrings[arrayofstrings.length - 2];
arrayofstrings.pop();
var hyperLink = '<a href="' + arrayofstrings.join('/') + '">' + billCycleFolderName + '</a>';
listItem['Bill Cycle'] = hyperLink;
});
var enhancedListItemValues = spService.SpSearchQuery.EnhanceSearchResults(listItemsWithValues, enhanceFunctions);
deferred.resolve(listItemsWithValues);
})
.catch(function (message) {
deferred.reject();
});
return deferred.promise;
}
function getContentTypeOfCurrentItem(id) {
var clientContext = new SP.ClientContext.get_current();
var oList = clientContext.get_web().get_lists().getByTitle('Bill Cycles');
listItem = oList.getItemById(id);
clientContext.load(listItem);
listContentTypes = oList.get_contentTypes();
clientContext.load(listContentTypes);
clientContext.executeQueryAsync(
// whats the reference to this at this point? i think its undefined or window, because you're calling getContentTypeOfCurrentItem() directly
Function.createDelegate(this, getContentTypeOfCurrentItemSucceeded),
function (error, errorInfo) {
$log.warn('Retrieving list item result failed');
deferred.reject(errorInfo); // deferred is not available in this scope!
}
);
}
function getContentTypeOfCurrentItemSucceeded(sender, args) {
var ctid = listItem.get_item('ContentTypeId').toString(); // listItem is not available at this point
var ct_enumerator = listContentTypes.getEnumerator();
while (ct_enumerator.moveNext()) {
var ct = ct_enumerator.get_current();
if (ct.get_id().toString() == ctid) {
var contentTypeName = ct.get_name();
return contentTypeName; // what's the point of this return? being an OK callback, who handles this value?
}
}
}