Referencing another Workbook in Office Scripts - excel

I have a Workbook that requires it to interact with another workbook. I have the below code which will run fine and get the value of the cell. But I need there to be a function to reference another Workbook.
function main(workbook: ExcelScript.Workbook) {
// Get Worksheet
let Sheet1 = workbook.getWorksheet('Worksheet 1');
// Get the value of cell A1.
let range = SourceData1.getRange("A1");
// Print the value of A1.
console.log(range.getValue());
}
I've tried referencing like so...
let SourceData1 = workbook.getWorksheet('https://mydomain.sharepoint.com/personal/Documents/[sourceData.xlsx]in');
But I take it the workbook part just references whatever is open? How do I refer an external workbook from a different sheet?

You should be able to use most of the response I wrote here. There are just a few small differences:
You do not need to stringify or parse anything. You can just work with the value of the cell as a string directly.
You would get the value of the cell in the first script using the range's GetValue method. You would then return that value as a string in the first script like so:
//first script
function main(workbook: ExcelScript.Workbook): string
{
let sh: ExcelScript.Worksheet = workbook.getActiveWorksheet();
let rang: ExcelScript.Range = sh.getRange("E1");
return rang.getValue() as string
}
In the second script, you wouldn't need to resize any ranges. Just set the range where the input value should be assigned, and assign the functions' parameter value to that (in my link I called the parameter tableValues. So since this is a cell value, I'd consider renaming it to something like cell value). So if you had a cellValue parameter you could just update the line of code like so:
//second script
function main(workbook: ExcelScript.Workbook, cellValue: string)
{
let sh: ExcelScript.Worksheet = workbook.getActiveWorksheet()
let rang: ExcelScript.Range = sh.getRange("D1")
rang.setValue(cellValue)
}

Related

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 };

Office Excel JS - Find and replace

I just wonder whether we can find and replace using Office Excel JS? I have read through their doc but it does not mention about this functionality.
The Range object has a find method to search for a specified string within the range. It returns the range of the first cell with matching text.
await Excel.run(async (context) => {
let sheet = context.workbook.worksheets.getItem("Sample");
let table = sheet.tables.getItem("ExpensesTable");
let searchRange = table.getRange();
let foundRange = searchRange.find("Food", {
completeMatch: true, // Match the whole cell value.
matchCase: false, // Don't match case.
searchDirection: Excel.SearchDirection.forward // Start search at the beginning of the range.
});
foundRange.load("address");
await context.sync();
console.log(foundRange.address);
});
See Find a string within a range using the Excel JavaScript API for more information.
This function replaceAll would do it

Office Script, update table from another, worked now failing

I used what I found Here and it worked great for a few months. My Workbook would always have the latest table update. Starting today it fails every time. Referencing Script 2 during the Flow-
Worksheet getRange: The request failed with status code of 504, error code UnknownError"
//resizes the range
let rang: ExcelScript.Range = SelectedSheet.getRange("A2").getResizedRange(valuesRowCount, valuesColumnCount)
Script 1 =
function main(workbook: ExcelScript.Workbook)
{
let selectedSheet = workbook.getActiveWorksheet();
let usedRange = selectedSheet.getUsedRange();
// Delete range B:D
selectedSheet.getRange("B:D").delete(ExcelScript.DeleteShiftDirection.left);
// Delete range G:I
selectedSheet.getRange("G:I").delete(ExcelScript.DeleteShiftDirection.left);
// Delete range L:L
selectedSheet.getRange("L:L").delete(ExcelScript.DeleteShiftDirection.left);
// Delete range M:M
selectedSheet.getRange("M:M").delete(ExcelScript.DeleteShiftDirection.left);
// Delete range N:S
selectedSheet.getRange("N:S").delete(ExcelScript.DeleteShiftDirection.left);
// Delete range P:X
selectedSheet.getRange("P:X").delete(ExcelScript.DeleteShiftDirection.left);
// Delete range R:AW
selectedSheet.getRange("R:AW").delete(ExcelScript.DeleteShiftDirection.left);
let newTable = selectedSheet.addTable(usedRange, true);
//get table
let tbl: ExcelScript.Table = selectedSheet.getTable("Table1");
//get table's column count
let tblColumnCount: number = tbl.getColumns().length;
//set number of columns to keep
let columnsToKeep: number = 22;
//set the number of rows to remove
let rowsToRemove: number = 0;
//resize the table range
let tblRange: ExcelScript.Range =
tbl.getRangeBetweenHeaderAndTotal().getResizedRange(rowsToRemove,
columnsToKeep - tblColumnCount);
//get the table values
let tblRangeValues: string[][] = tblRange.getValues() as string[][];
//create a JSON string
let result: string = JSON.stringify(tblRangeValues);
//return JSON string
return result;
Script 2 =
function main(workbook: ExcelScript.Workbook, tableValues: string) {
let selectedSheet = workbook.getActiveWorksheet();
let SelectedSheet: ExcelScript.Worksheet = workbook.getWorksheet("Database")
let usedRange = selectedSheet.getUsedRange();
//parses the JSON string to create array
let tableValuesArray: string[][] = JSON.parse(tableValues);
//gets row count from the array
let valuesRowCount: number = tableValuesArray.length - 1
//gets column count from the array
let valuesColumnCount: number = tableValuesArray[0].length - 1
//resizes the range
let rang: ExcelScript.Range = SelectedSheet.getRange("A2").getResizedRange(valuesRowCount, valuesColumnCount)
//sets the value of the resized range to the array
rang.setValues(tableValuesArray)
// Fit the width of all the columns in the Table.
SelectedSheet.getUsedRange().getFormat().autofitColumns();
selectedSheet.getUsedRange().getFormat().setHorizontalAlignment(ExcelScript.HorizontalAlignment.left);
}
Any idea what I am doing wrong?
Are you running Script 1 as part of a Flow too? If so, you should change this line in Script 1:
let selectedSheet = workbook.getActiveWorksheet();
When you run a script as part of a Flow, you need to specify the worksheet by ID or name. So, for example, you would change the line to something like:
let selectedSheet = workbook.getWorksheet("Sheet1")
where Sheet1 is the sheet you want to add the table to.
You have two different sheet variables in Script 2 as well. One is 'selectedSheet' and the other is "SelectedSheet'. You reference both later in the script. Do you mean to have both? And again, for scripts running as part of a Flow, always specify the sheet by ID or name that you are trying to reference. Let me know if that fixes things!
Have you tried rerunning your flow? It's possible there could have been some temporary issue with PowerAutomate. So perhaps the service was down.
The only potential issue I see is this
let newTable = selectedSheet.addTable(usedRange, true);
//get table
let tbl: ExcelScript.Table = selectedSheet.getTable("Table1");
The newTable's name is not guaranteed to be Table1. So if it wasn't, your flow might not work correctly. You could get around that by setting tbl to the newTable. So you could either write code like this:
let newTable = selectedSheet.addTable(usedRange, true);
//get table
let tbl: ExcelScript.Table = newTable;
Or just update tbl to code like this:
let tbl: ExcelScript.Table = selectedSheet.addTable(usedRange, true);

How do you convert a dynamic range into a table using Excel Scripts?

I am new to using excel scripts with power automate. Trying to convert some data to a table. The thing is the number of rows will differ each time.
I've done this in excel desktop, but not sure how to do it using an excel script.
The problem is finding the used range in excel(Office Scripts). Once you have it, i assume you know how to convert it to table.
function main(workbook: ExcelScript.Workbook)
{
// Get the current, active worksheet.
let currentWorksheet = workbook.getActiveWorksheet();
// Get the range containing all the cells with data or formatting.
let usedRange = currentWorksheet.getUsedRange();
// Log the range's address to the console.
console.log(usedRange.getAddress());
}
Link for your reference
From:
https://learn.microsoft.com/en-us/office/dev/scripts/resources/samples/excel-samples
function main(workbook: ExcelScript.Workbook) {
// Get the current worksheet.
let selectedSheet = workbook.getActiveWorksheet();
// Create a table with the used cells.
let usedRange = selectedSheet.getUsedRange();
let newTable = selectedSheet.addTable(usedRange, true);
// Sort the table using the first column.
newTable.getSort().apply([{ key: 0, ascending: true }]);
}

Why is my "defined name" (range) value not being set with this Spreadsheet Light code?

I've got this code to apply a "header" (big, top-of-the-sheet "title") to a sheet:
// Initialize
private static SLDocument sl;
. . .
sl = new SLDocument();
// Create a Style
SLStyle styleHeading = sl.CreateStyle();
styleHeading.SetFont(FontSchemeValues.Major, 36);
styleHeading.Font.Italic = true;
styleHeading.Font.FontName = "Candara";
// Create a Defined Name (Range) and give it a value and style
sl.SetDefinedName("UnitName", "Sheet1!$A$1:$A$13");
sl.SetCellValue("UnitName", "Pennsylvania Platypi Presumptuously Parasailing");
sl.SetCellStyle("UnitName", styleHeading);
// Save the sheet
string appDataFolder = HttpContext.Current.Server.MapPath("~/App_Data/");
string spreadsheetLightFilename = "PlatypiTest.xlsx";
string fullspreadsheetLightPath = Path.Combine(appDataFolder, spreadsheetLightFilename);
sl.SaveAs(fullspreadsheetLightPath);
Note: I verified that "Sheet1" was right with this code:
var nameList = sl.GetSheetNames();
string s = nameList[0]; // "s" is "Sheet1"
The file is created and saved, but it is devoid of content; when I open it, cell A1 is highlighted, but is content-free.
Am I missing a vital step, or going about this completely wrong?
What are you doing is logically fine.
This line
sl.SetDefinedName("UnitName", "Sheet1!$A$1:$A$13");
indeed creates a named range. You can see it if you open the resulting file in Excel and look at the cell selector:
or the Name Manager:
The problem is though that Spreadsheet Light has a very basic support for Defined names - basically all you can do is to create a name and use it inside the formulas. All methods that manipulate content expect single cell reference. Btw, all these methods do not throw exception if you don't pass a valid cell reference, but return bool indicating success/failure.
For instance, if you change your code to
bool success1 = sl.SetCellValue("UnitName", "Pennsylvania Platypi Presumptuously Parasailing");
bool success2 = sl.SetCellStyle("UnitName", styleHeading);
you will see that both success variables are false.
Shortly, if you want to bring some content to the Excel file, you should do it cell by cell. It even does not support regular (unnamed) ranges.
Theoretically, at least, you could do it this way:
// from http://stackoverflow.com/questions/36481802/what-is-the-analogue-to-excel-interops-worksheet-usedrange-rows-in-spreadsheet
var stats = sl.GetWorksheetStatistics();
var rowcount = stats.NumberOfRows;
SLStyle entireSheetRangeStyle = sl.CreateStyle();
entireSheetRangeStyle.// (set style vals)
. . .
sl.SetRowStyle(1, rowcount, entireSheetRangeStyle);

Resources