I am looking for a best way to uniquely identify/recognize a selected range within Office.js Excel workbook. So far I am using bindings to set a name for a range i.e. A1:A1. However, it is not clear how to check when user selects the above range if it is a part of the above binding in the workbook.
To set the binding i use the below code:
var myBindings = Office.context.document.bindings;
var myAddress = "Sheet1!A1:A1";
myBindings.addFromNamedItemAsync(myAddress, Office.BindingType.Matrix, { id: "myBind" }, function (asyncResult) {
asyncResult.value.getDataAsync(function (asyncResult2) {
console.log(asyncResult2.value);
});
});
You could use getIntersectionOrNullObject to detect whether your selection is in namedRanges or not. it can return address of the selectedRange in getIntersectionOrNullObject or it will return null object
Here is the sample code
Excel.run(function (ctx) {
const selectedRange = ctx.workbook.getSelectedRange();
var binding = ctx.workbook.bindings.getItemAt(0);
var range = binding.getRange();
var sheetName = "Sheet1";
var rangeAddress = "A1:F8"; // replace to binding range address
// var rangeAddress = range.address;
var range =
ctx.workbook.worksheets.getItem(sheetName).getRange(rangeAddress).getIntersectionOrNullObject(selectedRange);
range.load('address');
console.log("test");
return ctx.sync().then(function () {
console.log("test2");
console.log(range.address);
});
}).catch(function (error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
Related
I am trying to add cells to the existing table using insert API provided by office js. Microsoft official doc gave sample code to insert in sheet which works fine.
Excel.run(function (context) {
var sheet = context.workbook.worksheets.getItem("Sample");
var range = sheet.getRange("B4:E4");
range.insert(Excel.InsertShiftDirection.down);
return context.sync();
}).catch(errorHandlerFunction);
But i was trying do same with table on the sheet. But it is not working.
table = ctx.workbook.tables.getItem(tableName);
let range = table.getRange();
range.insert(Excel.InsertShiftDirection.down);
Is there a way to achieve this?
You could use Excel.TableRow, the sample code:
Excel.run(function (ctx) {
var tables = ctx.workbook.tables;
var values = [["Sample", "Values", "For", "New", "Row"]];
var row = tables.getItem("Table1").rows.add(null, values);
row.load('index');
return ctx.sync().then(function() {
console.log(row.index);
});
}).catch(function(error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
The document can be found at https://learn.microsoft.com/en-us/javascript/api/excel/excel.tablerowcollection?view=excel-js-preview#add-index--values-
I have written the following code to implement custom conditional formatting using Office JS -
function customFormatting() {
// Run a batch operation against the Excel object model
Excel.run(function (ctx) {
// Create a proxy object for the active worksheet
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
//Queue a command to write the sample data to the specified range
//in the worksheet and bold the header row
var range = sheet.getRange("A2:E9");
var conditionalFormat = range.conditionalFormats.add(Excel.ConditionalFormatType.custom);
conditionalFormat.custom.format.fill.color = "red";
conditionalFormat.custom.rule = {formula:">1001 && <5000"};
//Run the queued commands, and return a promise to indicate task completion
return ctx.sync();
})
.then(function () {
app.showNotification("Success");
console.log("Success!");
})
.catch(function (error) {
// Always be sure to catch any accumulated errors that bubble up from the Excel.run execution
app.showNotification("Error: " + error);
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
}
I am getting the following error while running the code -
Error: TypeError: Attempted to assign to readonly property.
(Revising my answer to describe 2 possible solutions, since I'm not clear on exactly which scenario matches what you're trying to achieve.)
Solution 1: Highlight cell when cell value meets criteria
In this first scenario, let's assume you have this table in the active worksheet, and your objective is to highlight the cell in column E of any row where the value in column E is between 1001 and 5000:
The following code uses conditional formatting to set fill color to yellow in column E when the cell value is between 1001 and 5000.
Excel.run(function (ctx) {
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
var range = sheet.getRange("E2:E9");
var conditionalFormat = range.conditionalFormats.add(Excel.ConditionalFormatType.cellValue);
conditionalFormat.cellValue.format.fill.color = "yellow";
conditionalFormat.cellValue.rule = { formula1: "=1001", formula2: "=5000", operator: "Between" };
return ctx.sync()
.then(function () {
//app.showNotification("Success");
console.log("Success!");
})
})
.catch(function (error) {
//app.showNotification("Error: " + error);
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
After this code runs, the table looks like this:
Solution 2: Highlight entire row when a specific cell value in the row meets criteria
In this next scenario, let's assume you have this table in the active worksheet, and your objective is to highlight the entire row of data (columns A-E) whenever the value in column E of a row is between 1001 and 5000:
The following code uses conditional formatting to set fill color to yellow for the entire row of data (columns A-E), whenever the value in column E of a row is between 1001 and 5000.
Excel.run(function (ctx) {
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
var range = sheet.getRange("A2:E9");
var conditionalFormat = range.conditionalFormats.add(Excel.ConditionalFormatType.custom);
conditionalFormat.custom.format.fill.color = "yellow";
conditionalFormat.custom.rule.formula = '=IF((AND($E2>1001, $E2<5000)),TRUE)';
return ctx.sync()
.then(function () {
//app.showNotification("Success");
console.log("Success!");
})
})
.catch(function (error) {
//app.showNotification("Error: " + error);
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
After this code runs, the table looks like this:
conditionalFormat.custom.rule is read only. This means that you can't create an object and assign it to conditionalFormat.custom.rule as your code is trying to do. Instead you have to assign values to each property of the rule. For example:
conditionalFormat.custom.rule.formula = '=IF(B8>INDIRECT("RC[-1]",0),TRUE)';
Note that the formula value has to be a valid Excel formula, not a JavaScript expression as you are using.
i'm trying to insert a table inside the content control. Here is my code:
function insertTable() {
Word.run(function (context) {
var range = context.document.getSelection();
var cc = range.insertContentControl();
cc.title = "My Table";
var values = [["Apple", "red", "round"], ["Banana", "yellow", "long"], ["Pear", "green", "oblong"]];
context.load(cc);
return context.sync().then(function () {
var table = cc.insertTable(3, 3, 'Start', values);
})
// Synchronize the document state by executing the queued commands,
// and return a promise to indicate task completion.
.then(context.sync);
})
.catch(function (error) {
console.log('Error: ' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
}
But i got this error.
Error: {"name":"OfficeExtension.Error","code":"InvalidArgument","message":"InvalidArgument","traceMessages":[],"innerError":null,"debugInfo":{"code":"InvalidArgument","message":"InvalidArgument","errorLocation":""},"stack":"InvalidArgument: InvalidArgument\n at Anonymous function (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:211625)\n at yi (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:249536)\n at st (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:249623)\n at d (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:249443)\n at c (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:248029)"}
I'm using the beta word api:
<script src="https://appsforoffice.microsoft.com/lib/beta/hosted/office.js" type="text/javascript"></script>
Because on api version 1.1 there is not the method insertTable. Any idea why it doesn't work? I've seen on the documentation that this method is available on api version 1.3, are they released?
Thanks
I was stuck with the same problem. It turns out you cannot insert a table in the middle of a paragraph (or in a paragraph that contains something else). When you first add a paragraph, and insert the table in this paragraph you get the desired effect. Please see the code below.
All credits belong to Cindy Meister
function placeTable() {
Word.run(function (context) {
var values = [["Apple"]];
var selectionRange = context.document.getSelection();
var paragraph = selectionRange.insertParagraph("", "Before");
return context.sync()
.then(function () {
var table = paragraph.insertTable(1, 1, "Before", values);
var contentControl = table.insertContentControl();
})
.then(context.sync)
.catch(function (error) {
console.log(error);
});
});
I came here because I got the same error.
However, in my case it was because I provided the insertTable method a column value of less than what the values parameter had.
i.e. my values had three columns and I specified 2 in insertTable.
Hope this helps someone in the future.
so I have a table of 10 items, each item has about 5 keys (name,experience,level, etc). Now, I want to scan that table, get each item as an object and add it to an array and then JSON stringify that array and return it.
I just need help with the scanning code and getting all items and putting it into an array.
Here's my code I have currently.
var dynamodb = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, context, callback)
{
var returnArray = {
"cards": {}
}
getCards();
function getCards() {//Not sure how to write this function
var params = {
TableName : "toBeApprovedTable",
Key: {//not sure what to put here, since I want all items, and not searching through keys.
},
};
dynamodb.scan(params,function(err,data)
{
if(err)
{
console.log("error in scanning");
}
else
{
console.log("scanning success!");
//Not sure what to do here.
}
});
}
};
I figured it out after scrapping through Google + AWS docs.
Here is how to scan a table for all elements in the table. My return is a map, which contains an array of elements. Each element is a map of my object.
exports.handler = function(event, context, callback)
{
var returnArray = {
"cardsToBeApproved":[]
};
getCards();
function getCards() {//Not sure how to write this function
var params = {
TableName : "toBeApprovedTable"
};
dynamodb.scan(params,onScan);
}
function onScan(err,data)
{
if(err)
{
console.log("unable to scan table");
}
else
{
console.log("scan succeeded");
data.Items.forEach(function(card)
{
console.log("my card name is " + card.name);
var cardStringified = JSON.stringify(card);
returnArray.cards.push(card);
});
callback(null,JSON.stringify(returnArray));
}
}
};
How can I get the position of two worksheets using the Excel Javascript API?
Here is how it works just for one sheet:
Excel.run(function (ctx) {
var wSheetName = 'Sheet1';
var worksheet = ctx.workbook.worksheets.getItem(wSheetName);
worksheet.load('position')
return ctx.sync().then(function () {
console.log(worksheet.position);
});
});
=> it logs 0 to the console
But it doesn't logs anything if I try to get the position for two worksheets:
Excel.run(function (ctx) {
var wSheetName = 'Sheet1';
var wSheetName2 = 'Evars';
var worksheet = ctx.workbook.worksheets.getItem(wSheetName);
var worksheet2 = ctx.workbook.worksheets.getItem(wSheetName2);
worksheet.load('position')
worksheet2.load('position')
return ctx.sync().then(function () {
console.log(worksheet.position);
console.log(worksheet2.position);
});
});
I just tried your code, and it works fine. I wonder if you simply didn't have a sheet by one of those names, and so it was throwing an exception -- which was appearing to you as silent, since you didn't have a catch handler.
The code below, essentially the same as yours but with a catch statement, works correctly:
Excel.run(function(ctx) {
var wSheetName = 'Sheet1';
var wSheetName2 = 'Sheet2';
var worksheet = ctx.workbook.worksheets.getItem(wSheetName);
var worksheet2 = ctx.workbook.worksheets.getItem(wSheetName2);
worksheet.load('name, position')
worksheet2.load('name, position')
return ctx.sync().then(function () {
console.log(worksheet.name + ": " + worksheet.position);
console.log(worksheet2.name + ": " + worksheet2.position);
});
}).catch(function(error) {
OfficeHelpers.UI.notify(error);
OfficeHelpers.Utilities.log(error);
})
You can try this snippet live in literally five clicks in the new Script Lab (https://aka.ms/getscriptlab). Simply install the Script Lab add-in (free), then choose "Import" in the navigation menu, and use the following GIST URL: https://gist.github.com/Zlatkovsky/c61594f1c86970e8dba91fe94b7ca4b6. See more info about importing snippets to Script Lab.
Found the solution here ... maybe this will help someone
Excel.run(function (ctx) {
var worksheets = ctx.workbook.worksheets;
worksheets.load('items');
return ctx.sync().then(function () {
for (var i = 0; i < worksheets.items.length; i++) {
var sheet_name = worksheets.items[i].name;
var sheet_position = worksheets.items[i].position;
}
});