Automatically move the screen to view the selection with an Excel add-in - ms-office

I want to make a function to select a range in a workbook and visualise that range on the screen. My test shows that select() does select a range, whereas it does not always adapt automatically the screen to show the selection.
For example, I try to select and show Z10:Z10 under Excel for Windows by the following code. But after the selection, the screen does not move:
Office.initialize = function(reason) {
$(document).ready(function() {
app.initialize();
$('#testSelect').click(function() { select("Z10:Z10", "Sheet1") });
});
};
function select (rangeAddress, sheetName) {
Excel.run(function (ctx) {
var range = ctx.workbook.worksheets.getItem(sheetName).getRange(rangeAddress);
range.select();
return ctx.sync();
});
}
Could anyone help?

This appears to be a bug (or regression) in the APIs. The team is looking into it right now. In terms of a workaround, what Michael Saunders suggested above is probably your best short-term bet.
Update: This is indeed a bug (or regression) in the Excel desktop client. We have fixed it today, so for Office 365 / Click-to-Run users, it should be available with the next update (i.e., within a couple months).
~ Michael Zlatkovsky, Developer on Office Extensibility Team, MSFT

One option here in the callback after your code completes is to bind to the range and then navigate to it:
Office.context.document.bindings.addFromSelectionAsync(Office.BindingType.Matrix, {id: "myBinding"}, function(asyncResult){
Office.context.goToByIdAsync("myBinding", Office.GoToType.Binding, function(asyncResult){});
});
-Michael Saunders, PM for Office add-ins

Related

Protect Worksheet in Office Scripts with Options

How can I protect a worksheet but allow the user to format the columns in Office Scripts? I have tried a few things but haven't had any success.
function main(workbook: ExcelScript.Workbook) {
let sheet = workbook.getWorksheet("By Item");
sheet.getProtection().protect(ExcelScript.WorksheetProtectionOptions.allowFormatColumns);
}
Please see the attached link
https://learn.microsoft.com/en-us/javascript/api/office-scripts/excelscript/excelscript.worksheetprotection?view=office-scripts#protect-options--password-
The protect() method takes an object as argument for the 1st argument. See below.
I noticed that cell background/fill doesn't work even with this setting. All other formatting works such as font color, border, etc. That may be a bug that we'll follow-up on.
function main(workbook: ExcelScript.Workbook) {
let sheet = workbook.getWorksheet("By Item");
sheet.getProtection().unprotect();
sheet.getProtection().protect({
allowFormatCells: true
});
}

How to handle event on data change in excel sheet to refresh all pivot tables?

I have a VBA code applied to Worksheet and its change. So whenever there is new entry or deletion (any change) in the sheet, it refresh all the pivot tables attached to it -
Private Sub Worksheet_Change(ByVal Target As Range)
ThisWorkbook.RefreshAll
End Sub
( I am not very familiar with the VBA or office script code, so sorry for basic question.)
But this does not work on excel online. Hence i need a code to use in excel online code editor (or typescript). So Far, I am able to write this code -
async function main(workbook: ExcelScript.Workbook) {
await Excel.run(async (context) => {
console.log("Adding Sheet OnChange Handler");
let mysheet = context.workbook.worksheets.getItem("Attendance");
mysheet.onChanged.add(ref);
await context.sync();
console.log("Added a worksheet-level data-changed event handler.");
}
)};
function ref(workbook: ExcelScript.Workbook) {
let selectedsheet = workbook.getActiveWorksheet();
selectedsheet.refreshAllPivotTables();
console.log("Pivot Refreshed.");
};
I am getting an error Cannot find name 'Excel' and it should work whenever there is any change in the worksheet which is not the case. Please help me with this.
Thanks.
I think you are missing the () at the end of the refreshAllPivotTables method.
Please try this -
function main(workbook: ExcelScript.Workbook) {
workbook.refreshAllPivotTables(); // Refresh all pivot tables
}
As replied by #Daniel G. Wilson , it is not possible in script right now. So I used the Power Automate approach.
I wrote the script in my code editor and saved it-
function main(workbook: ExcelScript.Workbook) {
let selectedsheet = workbook.getWorksheet("Pivot");
selectedsheet.refreshAllPivotTables();
console.log("Pivot Refreshed");
};
Then I created a Scheduled flow in Power Automate. Steps are -
Create new Scheduled flow.
Give some name.
Set the starting time and the interval to run it automatically.
Select new step.
Select Excel Online Business.
Select Run a Script.
Choose file location and Script name.
Save and test the flow.
It works fine. Thanks.

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-

Write array formulas

To copy single formulas from an area to another, we could use directly rangeTarget.formulas = rangeSource.formulas once rangeSource.formulas is loaded. However, this method does not seem to apply to array formulas.
For example, A1:A8 contains an array formula {=B1:B8+10}, and the following code attempts to copy this array formula to C1:C8:
function test () {
Excel.run(function (ctx) {
var r0 = ctx.workbook.worksheets.getItem("Sheet1").getRange("A1:A8");
r0.load(["formulas"]);
return ctx.sync().then(function () {
var r1 = ctx.workbook.worksheets.getItem("Sheet1").getRange("C1:C8");
r1.formulas = r0.formulas;
});
});
}
Here is the result (Excel Online and Excel for Windows):
So does anyone know what's the correct way to copy an array formula?
Additionally, I don't know how to enter an array formula manually in Excel Online, the shortcut Ctrl+Alt+Enter does not seem to work (on Mac keyboard).
Array Formulas are not currently supported by the Office.js Excel APIs. However, please feel free to suggest / vote for it on https://officespdev.uservoice.com/
~ Michael Zlatkovsky, Developer on Office Extensibility Team, MSFT

Missing method in JavaScript API for Excel: copy a sheet

Since there is no way to cancel the changes made by an add-in, we need to provide users with backup options.
The current version of JavaScript API for Excel doesn't have a method for copying a sheet with its data and formatting.
Does anyone know of any workarounds or plans for adding such method?
There are indeed currently no way easy way of duplicating a worksheet and so feel free to request it on the Office Extensibility Platform's UserVoice. While such an API may be coming in the future, you could in the meantime add a new worksheet using worksheetCollection.add(), grab a worksheet's used range using the worksheet.getUsedRange() method and copy its values to another sheet.
Your code would then look something like this :
function duplicateSheet(worksheetName) {
Excel.run(function(ctx) {
var worksheet = ctx.workbook.worksheets.getItem(worksheetName);
var range = worksheet.getUsedRange();
range.load("values", "address");
var newWorksheet = ctx.workbook.worksheets.add(worksheetName + " - Backup");
return ctx.sync().then(function() {
var newAddress = range.address.substring(range.address.indexof("!") + 1);
newWorksheet.getRange(newAddress).values = range.values;
}).then(ctx.sync);
});
}
Let me know how that works out for you.
Gabriel Royer - Developer on the Office Extensibility Team, MSFT

Resources