I'm using YouTube Data API v3 and Google Apps Script for retrieve all my subscriptions.
The problem I'm facing is that - using the following code, the response brings duplicated channels:
do {
const mySubsResponse = YouTube.Subscriptions.list('snippet', {
mine: true,
//channelId: "<MY_CHANNEL_ID>",
maxResults: 50,
fields: "pageInfo(totalResults),nextPageToken,items(snippet(title,resourceId(channelId)))"
});
if (!mySubsResponse || mySubsResponse == undefined) {
Logger.log('No subscriptions found.');
SpreadsheetApp.getUi().alert("No subscriptions found.");
break;
}
// Loop all my subscriptions found in the response:
for (let j = 0; j < mySubsResponse.items.length; j++) {
const mySubItem = mySubsResponse.items[j];
sheet.getRange("H" + incrSub).setValue(mySubItem.snippet.title);
sheet.getRange("I" + incrSub).setValue(mySubItem.snippet.resourceId.channelId);
incrSub++;
}
nextPageToken = mySubsResponse.nextPageToken;
} while (nextPageToken);
I believe this is due each item in the response is actually the video uploaded by the channel I'm subscribed to - I don't think it's a problem with the page token.
In the code above, I've commented the channelId parameter and I've testted with both: mine:true and channelId:<MY_CHANNEL_ID> and, the totalResults shows me I have 479 subscriptions, but, when I'm looping the results,
For example, I'm subscribed to the channel called "Channel_1"; this
channel had uploaded three videos today. The response of the code
above brings me "Channel_1" three times, when it should be only 1 -
because I'm subscribed to "Channel_1" once.
What I want to get is a list of all channels I'm subscribed to.
I've checked the subscriptions:list documentation, but, it's not clear how I can get my subscriptions only.
If the subscriptions:list endopint is not the correct one for this task, which endpoint enables me to bring the desired results?1
1a list of all channels I'm subscribed to.
After checking more closely (and, I admit, after a little break I have), I finally found the problem and the solution:
The problem is: I wasn't using the nextPageToken in every loop, so, basically, I was requesting the same page without actually making any pagination.
In this section:
const mySubsResponse = YouTube.Subscriptions.list('snippet', {
mine: true,
//channelId: "<MY_CHANNEL_ID>",
maxResults: 50,
fields: "pageInfo(totalResults),nextPageToken,items(snippet(title,resourceId(channelId)))"
});
Can be seen that the pageToken: nextPageToken is not defined.
Then, the solution is:
Modify the code for sending the nextPageToken obtained.
This is the modified code:
// Call my subscriptions:
/** Token pagination. */
var nextPageToken = "";
/** Row position where to start writing the results. */
var incrSub = 6;
/**
* Get all my subscriptions.
*/
do {
const mySubsResponse = YouTube.Subscriptions.list('snippet', {
channelId: "<MY_CHANNEL_ID>", // also works with "mine: true".
maxResults: 50,
// Here, the first time the call is made, the "nextPageToken" value
// is empty. In every iteration (if "nextPageToken" is retrieved),
// the "nextPageToken" is used - in order to get the next page.
pageToken: nextPageToken,
fields: "nextPageToken,items(snippet(title,resourceId(channelId)))"
});
if (!mySubsResponse || mySubsResponse == undefined) {
Logger.log('No subscriptions found.');
SpreadsheetApp.getUi().alert("No subscriptions found.");
break;
}
// Write the subscriptions returned in the response:
for (let j = 0; j < mySubsResponse.items.length; j++) {
const mySubItem = mySubsResponse.items[j];
sheet.getRange("H" + incrSub).setValue(mySubItem.snippet.title);
sheet.getRange("I" + incrSub).setValue(mySubItem.snippet.resourceId.channelId);
incrSub++;
}
// Check the token:
try {
if (mySubsResponse.nextPageToken != null || mySubsResponse.nextPageToken != undefined) {
nextPageToken = mySubsResponse.nextPageToken;
} else {
nextPageToken = undefined;
break;
}
} catch (ex_page) {
// An error occurred. Check closely the code.
}
} while (nextPageToken != undefined);
With this modified code, all of my subscriptions are returned successfully.
I've created my first Google Workspace Addon which I have deployed to the associated domain successfully although still working on it due to this error.
Without errors, functionally it's (was) working well, however, I now keep getting "Exceeded maximum execution time" errors.
This error is frustratingly intermittent, but it recently started occuring around 90%+ of the time despite not occurring previously for weeks. Reverting to previous versions of my code hasn't fixed the issue.
Most if not all existing answers regarding this error assume the script is genuinely exceeding the time limit for scripts (either 6 minutes or 30 minutes).
To be clear - this is not what's happening here. The script doesn't run for anywhere close to the maximum time allowed (as far as I'm aware). It actually runs for around 45 seconds before giving the error.
It may somehow be running in the background and causing a legitimate Timeout error but I need to figure out if this is the case and the cause of the error and then fix it.
I've contacted Google but their relevant support who are knowledgeable about this and who could help are unfortunately very difficult to get hold of.
In Cloud Logging for this error, I'm seeing (obfuscated id's):
{
"insertId": "28z8v2anf1xq6",
"jsonPayload": {
"context": {
"reportLocation": {
"filePath": "[unknown file]",
"functionName": "[unknown function]"
}
},
"message": "Exceeded maximum execution time",
"serviceContext": {
"service": "AKfycbx-SO5mXBNoe2leEH4wrj02t9fZZwkq5BQlJPuBaNM"
}
},
"resource": {
"type": "app_script_function",
"labels": {
"function_name": "fileMakerPro",
"invocation_type": "unknown",
"project_id": "order-management-713317"
}
},
"timestamp": "2022-03-10T10:09:58.827Z",
"severity": "ERROR",
"labels": {
"script.googleapis.com/process_id": "fIxbX5X5IjrIqLLK-XQgJiJV0U9vQMEAEA1GOxTqw-XzqsaVlKTNK2UcymM7feuXp-qZLshvBUg61TS6u28l_v6szoAq8QBBOvGudISVj0yceQXPKpIHO6HJ2G-uxuqy4xcnv-NzDfBTMbJH7VmK_AjZd6a5KVA-LnhtOE_28mCn_zTpI5AC3-BhX_lcCC1p-3QsMX6blhMZSYgVTTo1T_Z9SovufUWinpJieIbio-L8wzQPkjLYM2l9s5RHGuKMcT3LbvUO7fFS4DV1z_xfaR_nU1LqeayAk1aouGSXc",
"script.googleapis.com/user_key": "wPo7ZL4DSIqpPrZfeqo7E7yAArA430YCNnzbVYhyuVlR6nKybMkISeaDZoigRDx0gAJXIjF49EoL",
"script.googleapis.com/deployment_id": "wkq5BQlJPcbx-SO5mEHAKfywrj02t9fZZ4uBXBNoe2leaNM",
"script.googleapis.com/project_key": "Xf9t90MIwJJbMnu2Z9hQ48TM6DPTcW9w3"
},
"logName": "projects/order-management-317713/logs/script.googleapis.com%2Fconsole_logs",
"receiveTimestamp": "2022-03-10T10:09:59.313440894Z"
}
Which is obscure and isn't helpful at all with the "unknowns".
The function it references, for reference:
async function fileMakerPro(e) {
console.time("fileMakerPro");
//Order Management Named Ranges
let OM_NR = await getNamedRangesAsObject_(ss);
let orderNumber, orderFolder, orderFolderName;
let loadingDate, loadingDateFormatted, dueDate, dueDateFormatted;
let sheetGoodsTable = OM_NR.goodsTable.ranges.filter(function (x) { /* here, x is an array, not an object */
return !(x.every(element => element === (undefined || null || '')))
});
//Get order number if exists or show warning and return
if (orderNumber = OM_NR.OrderNo.range.toString()) {
} else {
ui.alert(`⚠️ ORDER NUMBER \(${OM_NR.OrderNo.rangeA1.toString()}\) appears missing, please correct and try again.`);
return;
}
//Get loading date if exists or show warning and return
if (loadingDate = OM_NR.transportLoadingDate.range) {
loadingDateFormatted = `${loadingDate.getDate()}-${loadingDate.getMonth() + 1}-${loadingDate.getFullYear()}`;
monthName = monthNames[loadingDate.getMonth()];
//Set Due Date 30 days after Loading Date
dueDate = new Date(loadingDate.getFullYear(), loadingDate.getMonth(), loadingDate.getDate() + 30);
dueDateFormatted = `${dueDate.getDate()}-${dueDate.getMonth() + 1}-${dueDate.getFullYear()}`;
} else {
ui.alert(`⚠️ LOADING DATE \(${OM_NR.transportLoadingDate.rangeA1.toString()}\) appears to be missing, please correct and try again.`);
return;
}
let rootFolder = DriveApp.getFileById(sheetId).getParents().next();
let tempFolder = DriveApp.getFolderById("1f4Ll-KODzmvBIuunaCS_7anMCX-w86S6");
let monthFolders = rootFolder.getFolders();
let tickBoxes = e.formInputs.generateDocsCheckboxes;
let packingListTemplateId = '1cZUB4U59Z56456gdgdghhka2QQ9sUNIlQSHYy1M';
let tickCMR = false, tickInvoice = false;
//Find existing order folder
let orderSearch = await searchFolders(monthFolders, monthName, orderNumber);
//Set Order Folder Name if both values present
orderFolderName = `${loadingDate.getDate()}-${loadingDate.getMonth() + 1}-${loadingDate.getFullYear()} \(${orderNumber}\)`;
if (tickBoxes !== undefined) {
if (tickBoxes.indexOf('tickBoxCMRnote') > -1) {
tickCMR = true;
}
if (tickBoxes.indexOf('tickBoxInvoice') > -1) {
tickInvoice = true;
}
} else {
let confirm = ui.alert(`⚠️ No documents selected. Update Order ${orderNumber} Snapshot and Packing List only?`, Browser.Buttons.YES_NO);
if (confirm === ui.Button.YES) {
fileMakerPro();
} else {
ss.toast(`⚠️ Update cancelled.`);
return;
}
}
if (!orderSearch.foundMonthFolder) {
ss.toast(`⚙️ Creating Month Folder...`);
monthFolder = rootFolder.createFolder(monthName);
} else {
monthFolder = orderSearch.foundMonthFolder;
}
if (!orderSearch.foundOrderFolder) {
ss.toast(`⚙️ Creating Order Folder...`);
orderFolder = monthFolder.createFolder(orderFolderName);
} else {
if (!orderSearch.foundOrderFolder.getName().includes(loadingDateFormatted)) {
ui.alert(`⚠️ Duplicate Order Number ${orderNumber} found: ${orderSearch.foundMonthFolder.getName()} / ${orderSearch.foundOrderFolder.getName()}.\n\n Please change Order Number or remove duplicate Order Folder.`);
return;
}
orderFolder = orderSearch.foundOrderFolder;
}
if (tickInvoice && tickCMR) {
assembleCMR(orderFolder, orderNumber, tempFolder, loadingDateFormatted, sheetGoodsTable, OM_NR);
assembleInvoice(orderFolder, orderNumber, tempFolder, loadingDateFormatted, dueDateFormatted, sheetGoodsTable, OM_NR);
ss.toast(`✅ Documents Saved`);
} else {
if (tickCMR) {
assembleCMR(orderFolder, orderNumber, tempFolder, loadingDateFormatted, sheetGoodsTable, OM_NR);
ss.toast(`✅ CMR Document Saved`);
}
if (tickInvoice) {
assembleInvoice(orderFolder, orderNumber, tempFolder, loadingDateFormatted, dueDateFormatted, sheetGoodsTable, OM_NR);
ss.toast(`✅ Invoice Document Saved`);
}
}
let existingOrderSnapshot = orderFolder.getFilesByName(`${orderNumber} - ORDER SNAPSHOT - DO NOT EDIT`);
let existingPackingList = orderFolder.getFilesByName(`${orderNumber} - PACKING LIST`);
let packingListId = await createPackingList(existingPackingList, orderFolder, orderNumber, packingListTemplateId, sheetId, OM_NR);
createOrderSnapshot(existingOrderSnapshot, orderFolder, orderNumber, sheetId, packingListId);
syncOrderNumbers(orderSearch.orderNumbers);
console.timeEnd("fileMakerPro");
return;
}
I suspect maybe the following function could be causing the Timeout since the loop may be malfunctioning but not sure how to check or fix:
async function writePackingList(OM_NR, packingList, packingListId){
let PL_NR = await getNamedRangesAsObject_(packingList);
for (let nr in PL_NR) {
Logger.log(nr);
if (nr == "loadingAddress") {
packingList.getRangeByName(`${nr}`).setValue(OM_NR[`${nr}`].range);
} else if (nr) {
packingList.getRangeByName(`${nr}`).setValue(OM_NR[`${nr}`].range);
} else {
break;
}
}
ss.getRangeByName("transportTotalNetWeight").setFormula(`=IMPORTRANGE("${packingListId}", "PL!I15")`)
ss.getRangeByName("transportTotalGrossWeight").setFormula(`=IMPORTRANGE("${packingListId}", "PL!H15")`)
}
Any help would be appreciated as I've hit a brick wall with this. I need to figure out how to debug this error, understand why it's happening and fix it so it doesn't happen when fully deployed.
Thanks
EDIT to include additional functions:
//Make copy of Invoice template doc, get body, replace all placeholders, return
async function assembleInvoice(orderFolder, orderNumber, tempFolder, loadingDateFormatted, dueDateFormatted, sheetGoodsTable, OM_NR) {
console.time("assembleInvoice");
ss.toast(`⚙️ Assembling Invoice Document...`);
let prefix = orderNumber + " - ";
let fileName = "INVOICE";
let templateTempCopy;
//Blue Invoice Template
let invoiceTemplate1 = DriveApp.getFileById("C2j_q3nUP4UTUR1KiCt07r1lATPKSjzEm-EeY109T8B4");
//Red Invoice Template
let invoiceTemplate2 = DriveApp.getFileById("1uczJT-F-JzKzaBwh_CdhJNcFkgDHfGjypJYom4vqGIo");
//Choose Invoice template based on Movement Type
let staraMovementType = OM_NR.staraMovementType.range;
if (staraMovementType.toString().includes('GB SHIPPING TO')) {
templateTempCopy = invoiceTemplate1.makeCopy(tempFolder);
} else {
templateTempCopy = invoiceTemplate1.makeCopy(tempFolder);
}
//Open working copy
let workingCopy = DocumentApp.openById(templateTempCopy.getId());
//Get body from working copy
let documentBody = workingCopy.getBody();
//Populate table
let allTables = documentBody.getTables();
let invoiceGoodsTable = allTables[3];
let itemRowTemplate = invoiceGoodsTable.getRow(invoiceGoodsTable.getNumRows() - 2);
let totalsRowTemplate = invoiceGoodsTable.getRow(invoiceGoodsTable.getNumRows() - 1);
for (let n in sheetGoodsTable) {
let tableRow = invoiceGoodsTable.appendTableRow(itemRowTemplate.copy());
tableRow.getCell(0).replaceText("{itemNo}", sheetGoodsTable[n][1]);
tableRow.getCell(1).replaceText("{itemDesc}", sheetGoodsTable[n][0]);
tableRow.getCell(2).replaceText("{commodityCode}", sheetGoodsTable[n][2]);
tableRow.getCell(3).replaceText("{cartons}", sheetGoodsTable[n][4]);
tableRow.getCell(4).replaceText("{qtyKgs}", sheetGoodsTable[n][5]);
tableRow.getCell(5).replaceText("{price}", sheetGoodsTable[n][3]);
tableRow.getCell(6).replaceText("{total}", sheetGoodsTable[n][5] * sheetGoodsTable[n][3]);
}
let totalsRow = invoiceGoodsTable.appendTableRow(totalsRowTemplate.copy());
totalsRow.getCell(3).replaceText("{cartons}", OM_NR.transportCasesCartons.range);
totalsRow.getCell(4).replaceText("{qtyKgs}", OM_NR.transportTotalNetWeight.range);
totalsRow.getCell(6).replaceText("{total}", OM_NR.transportInvoiceTotal.range);
itemRowTemplate.removeFromParent();
totalsRowTemplate.removeFromParent();
let importerAddress = `${OM_NR.importerConsigneeIntoEU.range}, ${OM_NR.importerAddress.range}`;
documentBody.replaceText("{currency}", OM_NR.staraInvoiceCurrency.range);
documentBody.replaceText("{shipToAddress}", importerAddress);
documentBody.replaceText("{billToAddress}", importerAddress);
documentBody.replaceText("{exporterCustomsInvoiceNo}", OM_NR.exporterCustomsInvoiceNo.range);
documentBody.replaceText("{exporterVAT}", OM_NR.exporterVAT.range);
documentBody.replaceText("{exporterEORI}", OM_NR.exporterEORI.range);
documentBody.replaceText("{staraOrderNo}", OM_NR.staraOrderNo.range);
documentBody.replaceText("{staraCustomerOrderNo}", OM_NR.staraCustomerOrderNo.range);
documentBody.replaceText("{transportLoadingDate}", loadingDateFormatted);
documentBody.replaceText("{dueDate}", dueDateFormatted);
documentBody.replaceText("{paymentTerms}", "30 DAYS");
documentBody.replaceText("{staraInvoiceNo}", OM_NR.staraInvoiceNo.range);
documentBody.replaceText("{incoTerms}", `${OM_NR.orderIncoterm.range} ${OM_NR.orderCountryOfDestination.range}`);
documentBody.replaceText("{transportTotalGrossWeight}", OM_NR.transportTotalGrossWeight.range);
documentBody.replaceText("{transportTotalNetWeight}", OM_NR.transportTotalNetWeight.range);
documentBody.replaceText("{transportTruckRef}", OM_NR.transportTruckRef.range);
documentBody.replaceText("{transportSeal1}", OM_NR.transportSeal1.range);
documentBody.replaceText("{transportSeal2}", OM_NR.transportSeal2.range);
documentBody.replaceText("{transportInvoiceTotal}", OM_NR.transportInvoiceTotal.range);
documentBody.replaceText("{staraInvoiceCurrency}", OM_NR.staraInvoiceCurrency.range);
workingCopy.saveAndClose();
//Gets a 'blob' of the completed document
let completedDoc = templateTempCopy.getAs('application/pdf');
//Check for existing PDF and move to trash (not fully delete)
let foundFile = orderFolder.getFilesByName(prefix + fileName);
if (foundFile.hasNext()) {
foundFile.next().setTrashed(true);
}
try {
//Create PDF
ss.toast(`📝 Saving ${fileName} PDF...`);
orderFolder.createFile(completedDoc).setName(prefix + fileName);
deleteTempFiles(templateTempCopy.getId());
} catch (err) {
showError(err);
} finally {
ss.toast(`✅ Invoice Document Saved`);
console.timeEnd("assembleInvoice");
}
return;
}
async function createPackingList(existingPackingList, orderFolder, orderNumber, packingListTemplateId, sheetId, OM_NR) {
console.time("createPackingList");
let packingListId;
//Get current sheet container objects and data
if (existingPackingList.hasNext()) {
packingListId = existingPackingList.next().getId();
} else {
ss.toast(`📃 Creating Packing List...`);
let newPackingList = DriveApp.getFileById(packingListTemplateId);
let newPackingListCopy = newPackingList.makeCopy(`${orderNumber} - PACKING LIST`, orderFolder)
packingListId = newPackingListCopy.getId();
}
let packingList = SpreadsheetApp.openById(packingListId);
addImportrangePermission(packingListId, sheetId);
writePackingList(OM_NR, packingList, packingListId);
ss.toast(`✅ Packing List Created/Updated`);
console.timeEnd("createPackingList");
return packingListId;
}
async function createOrderSnapshot(existingOrderSnapshot, orderFolder, orderNumber, sheetId, packingListId) {
console.time("createOrderSnapshot");
let snapshotExists = existingOrderSnapshot.hasNext();
//If snapshot exists, delete.
if (snapshotExists) {
existingOrderSnapshot.next().setTrashed(true);
ss.toast(`📷 Updating Order Snapshot...`);
} else {
ss.toast(`📷 Creating Order Snapshot...`);
}
//Make copy of sheet in order folder
let currentSheet = DriveApp.getFileById(sheetId);
let sheetCopy = currentSheet.makeCopy(`${orderNumber} - ORDER SNAPSHOT - DO NOT EDIT`, orderFolder);
let sheetCopyId = sheetCopy.getId();
let targetSpreadsheet = SpreadsheetApp.openById(sheetCopyId);
//let targetSpreadsheet = SpreadsheetApp.openById(DriveApp.getFileById(sheetId).makeCopy(`${orderNumber} - ORDER SNAPSHOT - DO NOT EDIT`, orderFolder).getId());
addImportrangePermission(targetSpreadsheet.getRangeByName("CONTROL").getValue(), sheetCopyId);
addImportrangePermission(packingListId, sheetCopyId);
targetSpreadsheet.getRangeByName("transportTotalNetWeight").setFormula(`=IMPORTRANGE("${packingListId}", "PL!I15")`)
targetSpreadsheet.getRangeByName("transportTotalGrossWeight").setFormula(`=IMPORTRANGE("${packingListId}", "PL!H15")`)
targetSpreadsheet.getRangeByName("topRow").clearDataValidations()
targetSpreadsheet.getRangeByName("sheetBody").clearDataValidations()
//DELETE UNNEEDED TABS FROM COPY
targetSpreadsheet.deleteSheet(targetSpreadsheet.getSheetByName("PC"));
targetSpreadsheet.deleteSheet(targetSpreadsheet.getSheetByName("C1"));
targetSpreadsheet.deleteSheet(targetSpreadsheet.getSheetByName("C2"));
targetSpreadsheet.deleteSheet(targetSpreadsheet.getSheetByName("SFC"));
if (snapshotExists) {
ss.toast(`✅ Order Snapshot Updated`);
} else {
ss.toast(`✅ Order Snapshot Created`);
}
console.timeEnd("createOrderSnapshot");
return;
}
async function addImportrangePermission(sourceSheetId, authSheetId) {
console.time("addImportrangePermission");
if (sourceSheetId) {
// donor or source spreadsheet id
// adding permission by fetching this url
let url = `https://docs.google.com/spreadsheets/d/${authSheetId}/externaldata/addimportrangepermissions?donorDocId=${sourceSheetId}`;
let token = ScriptApp.getOAuthToken();
let params = {
method: 'post',
headers: {
Authorization: 'Bearer ' + token,
},
muteHttpExceptions: true
};
UrlFetchApp.fetch(url, params);
}
console.timeEnd("addImportrangePermission");
return;
}
Issue:
In Workspace add-ons, callback functions executed when an Action triggers are limited to 30 seconds of execution time:
The Apps Script Card service limits callback functions to a maximum of 30 seconds of execution time. If the execution takes longer than that, your add-on UI may not update its card display properly in response to the Action.
Note:
Since you didn't provide the code related to the functions which are taking most time (e.g. assembleCMR, assembleInvoice, createPackingList) I cannot make any suggestion on that, but in any case you should try to improve the efficiency of those functions, or split it all into several Actions.
Reference:
Callback functions
This is the controller file of my app. It adds the data perfectly, but when it reaches the then key word google chrome hangs but key parameter is also added to the data base. I can't figure out where the problem is.
.controller('recordsCtrl', ['$scope','$firebaseArray',function($scope,$firebaseArray) {
$scope.records = $firebaseArray(rootRef);
//show form
$scope.showAddForm = function(){
$scope.addFormShow = true;
}
// hide form
$scope.hide = function(){
$scope.addFormShow = false;
}
// submit contact
$scope.addFormSubmit = function() {
console.log("adding form...")
// Assign values
if ($scope.lname) { var lname = $scope.lname; } else { var lname = null; }
if ($scope.mname) { var mname = $scope.mname; } else { var mname = null; }
if ($scope.fname) { var fname = $scope.fname; } else { var fname = null; }
if ($scope.email) { var email = $scope.email; } else { var email = null; } if ($scope.conId) { var conId = $scope.conId; } else { var conId = null;}
// Build Object
$scope.records.$add({
fname: fname,
lname: lname,
mname: mname,
email: email,
company: company,
conId: conId
}).then(function(rootRef) {
***//this is not printed in the console but the key is assigned to the database***
console.log("Assign root key");
var id = rootRef.key();
console.log("Added Record with ID: " + id);
// clear Form
clearFields();
// Hide Form
$scope.addFormShow = false;
// send message to use
$scope.msg = "Record Added";
});
}
}]);
My team ran into this issue when we updated to Firebase 3.7.x. I believe this is a known bug.
Try downgrading to Firebase 3.6.x.
Google Directory provide API to get all organizational units from domain.
I'm able to get OU inside "/" but I want to get all child OU.
There is function with some arguments:
AdminDirectory.Orgunits.list(String costumerId, Object optionalArg)
This function accept "type" argument as mentioned in official documentation, but when I put argument "orgUnitPath" it will respond with "Bad request"
Here is my full code
var page = AdminDirectory.Orgunits.list('my_costumer',{
orgUnithPath: '/Kiosks',
type: 'all'});
var units = page.organizationUnits;
if (units) {
for (var i = 0; i < units.length; i++) {
var unit = units[i];
Logger.log(unit);
}
} else {
Logger.log('No units found.');
}
Thank you very much
You mistyped 'my_customer' and orgUnitPath. Also, organizationalUnits is going to be an array of objects that you will want to get specific properties of such as orgUnit.name, not log directly.
function listSubOUs() {
var page = AdminDirectory.Orgunits.list('my_customer', {
orgUnitPath: '/',
type: 'all'
});
var orgUnits = page.organizationUnits;
if (orgUnits) {
for (var i = 0; i < orgUnits.length; i++) {
var orgUnit = orgUnits[i];
Logger.log('%s (%s)', orgUnit.name, orgUnit.orgUnitPath, orgUnit.description);
}
} else {
Logger.log('No OUs found.');
}
}
I have the following function:
function pickContacts() {
var output = "";
// Create the picker
var picker = new Windows.ApplicationModel.Contacts.ContactPicker();
picker.commitButtonText = "Select";
var emailsPromise = new WinJS.Promise(function () {
// Open the picker for the user to select contacts
picker.pickMultipleContactsAsync().then(function (contacts) {
if (contacts.length > 0) {
// Get selected e-mails
contacts.forEach(function (contact) {
contact.emails.every(function (email) { output += email.value + ";"; });
});
return output;
} else {
return "";
}
});
});
return emailsPromise;
};
This gets me a list of e-mail addresses from selected contacts. So next I want to use that; here's my code:
document.getElementById("findEmail").addEventListener("click", function () {
var emailAdd = document.getElementById("email");
pickContacts().done(function (emails) {
emailDets.value = emails;
});
});
But I'm not getting the return value from pickContacts (which I've determined is actually returned). I'm guessing that there's something wrong with the way I'm handling the returned promise, but I can't seem to debug it (trying to step into it just exits the function).
What am I doing wrong?
You don't need to create a new promise--just return the promise from pickMultipleContactsAsync.then. The promises spec says that the return value from .then is another promise that's fulfilled when your completed handler finishes, and the fulfillment value is the return value of the completed handler. So you can just do this:
return picker.pickMultipleContactsAsync().then(function (contacts) {
if (contacts.length > 0) {
// Get selected e-mails
contacts.forEach(function (contact) {
contact.emails.every(function (email) { output += email.value + ";"; });
});
return output;
} else {
return "";
}
});
The other way works, but just creates yet another promise that isn't needed, and makes your code a little more complex.
You'll have to pass the completed callback as a parameter of your promise function and then call it with the results you want to pass. Esseintially:
var emailsPromise = new WinJS.Promise(function () {
// Open the picker for the user to select contacts
picker.pickMultipleContactsAsync().then(function (contacts) {
if (contacts.length > 0) {
// Get selected e-mails
contacts.forEach(function (contact) {
contact.emails.every(function (email) { output += email.value + ";"; });
});
return output;
} else {
return "";
}
});
});
becomes:
var emailsPromise = new WinJS.Promise(function (complete, error, progress) {
// Open the picker for the user to select contacts
picker.pickMultipleContactsAsync().then(function (contacts) {
if (contacts.length > 0) {
// Get selected e-mails
contacts.forEach(function (contact) {
contact.emails.every(function (email) { output += email.value + ";"; });
});
complete(output);
} else {
complete("");
}
});
});