get row from range in current worksheet? - excel

I can not get tables name in active worksheet. I have a drop-down that will be populated with worksheets in workbook. I have another drop-down that should get all columns names(header) in selected worksheets. Somehow range.address has "sheet1!2:2" .
Here is code that I used:
function getRow(worksheetName) {
Excel.run(function (ctx) {
// Queue a command to write the sample data to the worksheet
// at moment i have only one worksheet named "Sheet1"
var range = ctx.workbook.worksheets.getItem(worksheetName).getRange().getRow(1);
range.load('address');
// Run the queued-up commands, and return a promise to indicate task
//completion
return ctx.sync().then(function () {
console.log(range.address); // prints Sheet1!2:2
})
})
.catch(errorHandler);
}
Here is a link to spreadsheet that I used for testing.
Any clue what i am doing wrong here?

I'd suggest that you replace getRange() with getUsedRange() instead, as shown here:
function getRow(worksheetName) {
Excel.run(function (ctx) {
var range = ctx.workbook.worksheets.getItem(worksheetName).getUsedRange().getRow(1);
range.load('address');
return ctx.sync().then(function () {
console.log(range.address);
})
})
.catch(errorHandler);
}

Rick Kirkham's comment above is correct. In the file that you've linked to, there is no table object -- although the worksheet does contain several rows/columns of data, that data is not explicitly contained inside a table.
Are you able to manually manipulate this file? If yes, then you can create a table object for the data by doing the following:
Select the data you want to be in the table.
With that data selected, choose the Table button (on the Insert tab).
Verify inputs in the Create Table prompt and choose OK.
If you are not able to manually manipulate this file, then you can create the table (from the range of data in your worksheet) by using the Office JavaScript API, as described here: https://dev.office.com/docs/add-ins/excel/excel-add-ins-tables#convert-a-range-to-a-table.

Related

Excel custom functions show BUSY! but async function is not called

I have an Excel Add-in having custom functions and taskpane. My client created a workbook having multiple sheets using my custom functions approximately 3500+ function calls in current workbook. When a user opens this workbook, I need to recalculate sheet so that only my functions are recalculated. To achieve this task, I have performed following steps.
Loop on sheets in workbook.
Search each sheet for my formula using worksheet.findAllOrNullObject() function.
if search result is not NullObject, then call ranges.calculate(). Which should trigger function calls.
var sheets = context.workbook.worksheets;
sheets.load("items/name");
await context.sync();
for (var i = 0; i < sheets.items.length; i++) {
var sheet = sheets.items[i];
const foundRanges = sheet.findAllOrNullObject(FORMULA_DATA[formula], {
completeMatch: false,
matchCase: false
});
await context.sync();
if (!foundRanges.isNullObject)
foundRanges.calculate();
await context.sync();
}
}
Problem I am facing that when I call recalculate function, all cells referring to these functions show BUSY! which means that my function have not resolved promise yet, but no function is actually called. I added break points at start of each function during debugging but no code stops there (I a change a single cell then breakpoint is hit).
I enabled run-time logging and it has entries for each call begin but no end call entry.
Also one of the cell reference is passed to all functions and if I change its value, then all function calls are made properly and it shows result as desired and logfile contains entries for begin and end for all calls.
After thoroughly investigating the issue, I have come to conclusion that this client was using other Add-in which had same function names and it was saved in workbook. When I recalculated the sheet range areas, it was trying to call functions from those old Add-in which was uninstalled earlier. Therefore all cells were showing BUSY! and since code was not there in excel these promises were never resolved. Once I removed all taskpanes from workbook and re-opened it this problem does not appeared again.
To save Taskpanes info
Office.addin.setStartupBehavior(Office.StartupBehavior.load);
To Remove Taskpanes information, use File => Info => Check for Issues => Inspect Document => Inspect.
After it displays results , Task pane Add-ins => Remove All.

Excel Office Script not clearing cells. Getting unreachable code detected (7027) error

I have this script which works all except for the clearing of the B4:B120 area "// Clear the "Margin Updates" column." section which is greyed out for some reason):
function main(workbook: ExcelScript.Workbook): ReportImages {
// Recalculate the workbook to ensure all tables and charts are updated.
workbook.getApplication().calculate(ExcelScript.CalculationType.full);
// Get the data from the "Target Margins - FHM" table. (name of Excel tab, not name of table)
let sheet1 = workbook.getWorksheet("Sheet1");
const table = workbook.getWorksheet('Target Margins - FHM').getTables()[0];
const rows = table.getRange().getTexts();
// Get only the Product Type and "Margin Update" columns, then remove the "Total" row.
const selectColumns = rows.map((row) => {
return [row[0], row[1]];
});
// Delete the "ChartSheet" worksheet if it's present, then recreate it.
workbook.getWorksheet('ChartSheet')?.delete();
const chartSheet = workbook.addWorksheet('ChartSheet');
// Add the selected data to the new worksheet.
const targetRange = chartSheet.getRange('A1').getResizedRange(selectColumns.length - 1, selectColumns[0].length - 1);
targetRange.setValues(selectColumns);
// Get images of the chart and table, then return them for a Power Automate flow.
const tableImage = table.getRange().getImage();
return { tableImage };
// Clear the "Margin Updates" column.
const targetSheet = workbook.getActiveWorksheet();
const getRange = targetSheet.getRange("B4:B120");
getRange.clear(ExcelScript.ClearApplyTo.contents);`
}
// The interface for table and chart images.
interface ReportImages {
tableImage: string
}
The code copies the data in sections of the A and B columns (which constitute a table) and sends an email via Power Automate flow. Unfortunately, I need the section of the B column to be clear of values (not formatting or style) after which this flow is not doing.
I'd greatly appreciate help with this problem.
Thank you.
#cybernetic. nomad:
When I try using Range ("B4:B120").Clear I receive
unreachable code detected (7027)
and
and "cannot find name 'Range' (2304)
Office Script Range Clear Error
In JavaScript, the function exits as soon as the return keyword is evaluated. That's why it's saying your code is unreachable. So you have to restructure your code so that the return happens at the end. So you can update your code to look something like this:
// Clear the "Margin Updates" column.
const targetSheet = workbook.getActiveWorksheet();
const getRange = targetSheet.getRange("B4:B120");
getRange.clear(ExcelScript.ClearApplyTo.contents);
return { tableImage };

How to update the source data range for existing chart

I'm trying to write a script that finds data in a sheet dynamically (the dimensions of the table need to be flexible in both axis) and then updates the source data range for an existing chart on another sheet (so that my users don't need to set up the styling themselves).
Below is my script so far. Everything works apart from the final line where Excel Online gives me the error:
"Line 10: Chart setData: You cannot perform the requested operation"
function main(workbook: ExcelScript.Workbook)
{
let selectedSheet = workbook.getWorksheet("Enter data in this sheet");
// Add a new table at used range on selectedSheet
let range = selectedSheet.getUsedRange();
if(selectedSheet.getTables().length == 0)
{
let newTable = workbook.addTable(range, true);
}
workbook.getWorksheet("The Chart").getChart("Chart 1").setData(range);
}
The worksheet names are correct and so is the chart name as far as I can see:
screenshot of excel online showing chart and worksheet names
Answer found; the chart was on a protected sheet which did not allow editing of objects. Updating the protection to allow all users to edit objects has resolved the issue.

Select a discontiguous range

I'm building an office-js add-in for Excel. I need to select two non-adjacent cells (e.g A1 and C3). The following code works to select the multi-cell range starting at A1 and ending at C3.
Excel.run(function (ctx) {
var sheet = ctx.workbook.worksheets.getItem('sheet1');
var range = sheet.getRange('a1:c3');
range.select();
return ctx.sync();
});
However, I'm looking to select only the two cells (A1 and C3). In VBA the syntax is
worksheets("sheet1").range("a1,c3").select
But I cannot find anything analogous in office-js. I've tried as similar syntax with office-js:
Excel.run(function (ctx) {
var sheet = ctx.workbook.worksheets.getItem('sheet1');
var range = sheet.getRange('a1,c3');
range.select();
return ctx.sync();
});
but it fails with: {"code":"InvalidArgument","message":"The argument is invalid or missing or has an incorrect format.","errorLocation":"Worksheet.getRange"}
An API to work with discontinuous ranges is not yet available in Office.js. We are working on it and are finalizing the design right now. In the meantime, you will have to create separate range objects for the two cells and operate on each of them with duplicate commands.
Actually on the latest insiders fast (16.0.9327.2006 ) deployed just a few days ago you can actually try our implementation for Areas (aka discontinuous ranges. )
please make sure to use our preview cdn to test this.(https://appsforoffice.microsoft.com/lib/beta/hosted/office.js)
but basically you can do things like:
function run() {
return Excel.run(function (context) {
var range = context.workbook.getSelectedRange();
range.load("address");
return context.sync()
.then(function () {
console.log("The range address was \"" + range.address + "\".");
});
});
}
and you will see that if you select a non-continuous range you will get something like: "Sheet1!C6:C14,Sheet1!F12:H22".
you can pass a similar string on the getRange method to create an Area and simultaneously format it etc.
Please give it a try and send us your feedback! thanks!
context.workbook.getSelectedRange()
is used for contiguous ranges.
If you want to get the range for a discontiguous range you should use:
context.workbook.getSelectedRanges()

Excel Office Add-In API Worksheet Protection Password

I have a question relating to Excel's worksheet protection...
The context is that I need to have different worksheets available for different user groups to edit but all groups must at least see all sheets e.g. usergroup1 can edit sheets two and three and parts of sheet one, usergroup2 can edit only sheet one.
I am able to set the FormatProtection (range.format.protection.locked = false;) accordingly and WorksheetProtection (worksheet.protection.protect();) to enable this but I don't appear to have the ability to set a password through the API against the Worksheet Protection? This means for example, that either group can simply click the Unprotect Sheet option in the review ribbon and edit the sheets that I don't want them to.
I've tried going through the below documentation but to no avail unfortunately.
http://dev.office.com/reference/add-ins/excel/worksheetprotection
https://github.com/OfficeDev/office-js-docs/blob/master/reference/excel/worksheetprotection.md
As an example, here is a function that I'd like to complete:
function CopyWorksheet() {
var newAddress;
Excel.run(function (ctx) {
var worksheet = ctx.workbook.worksheets.getActiveWorksheet();
var range = worksheet.getUsedRange();
range.load();
// insert new worksheet
var newWorksheetName = "Copied_Sheet";
var newWorksheet = ctx.workbook.worksheets.add(newWorksheetName);
return ctx.sync().then(function () {
// copy the old values to the new worksheet
newAddress = range.address.substring(range.address.indexOf("!") + 1);
newWorksheet.getRange(newAddress).values = range.values;
newWorksheet.getRange(newAddress).formulas = range.formulas;
newWorksheet.getRange(newAddress).text = range.text;
// protect both worksheets
worksheet.protection.protect();
newWorksheet.protection.protect();
// requirement here to set a password so that no one can
// edit the worksheets by selecting 'Unprotect Sheet' in excel
// ...
})
.then(ctx.sync)})
.catch(function(error) {
console.log("Error: " + error);
});
}
Currently, I'm using Excel 2016 (desktop version). Is this possible to implement or have I missed some functionality that exists which can achieve the same result?
Thanks for your help.
Password-protection is not available in our APIs. You can protect the sheet to avoid casual edits, but you can't password-protect. The reason is that password-protection is not available on all endpoints (IIRC, there was an issue with Excel Online).
If you want to file a suggestion bug on UserVoice, you can see if we'd consider doing password-protection as a Desktop-only API. We have so far avoided doing those in Excel, but I do know that Word has done a few "WordApiDesktop" APIs. So depending on how much it's blocking your (and others') scenario, that might be an option. In which case you'd be able to password-protect and unprotect on desktop, but wouldn't be able to take those actions online.
There is an update for this issue: we now support password protection. Check https://learn.microsoft.com/en-us/javascript/api/excel/excel.workbookprotection?view=office-js#protect-password-

Resources