Set 'Fit All Columns on One Page' via Excel JavaScript API - excel

I'm looking to set the "Fit All Columns on Page" print option via the Excel JavaScript API. It's very similar to this question which uses VBA -->
How to set 'Fit all columns on one page' in print tab

The Office 365 Online Automate Scripts helped get me on the right path.
Docs:
https://learn.microsoft.com/en-us/javascript/api/excel/excel.pagelayoutzoomoptions?view=excel-js-preview
https://learn.microsoft.com/en-us/javascript/api/excel/excel.pagelayout?view=excel-js-preview#excel-excel-pagelayout-zoom-member
Code:
await Excel.run(async (context) => {
var ws = context.workbook.worksheets.getActiveWorksheet();
var PageLayoutZoomOptions_Obj = {
'horizontalFitToPages': 1,
'verticalFitToPages': 0,
}
ws.pageLayout.zoom = PageLayoutZoomOptions_Obj
await context.sync();
});
Note: I had issues using/including scale so I just left it out.

Related

How to get Values from Yahoo Finance XHR's Complex Object in Google Apps Script

I'm trying to pull historical quarterly revenue data from Yahoo Finance. Its default "Annual" webpage is updated by selecting "Quarterly" option button, but its URL is still same. It appears that "Quarterly" option only updates the screen behind. So I was not able to pull quarterly data from the URL, but annual data only. Tracking of its XHR request, I figured out its source header, by the following codes below. Now I face another challenge on how to extract quarterlyTotalRevenue from its complex object, because of my lack of understanding about object handling. What I finally want to get is an array, something like this.
How can I do that? Thank you for any help!
function test() {
var ticker = 'JPM';
var url = 'https://query1.finance.yahoo.com/ws/fundamentals-timeseries/v1/finance/timeseries/'
+ ticker + '?lang=en-US&region=US&symbol=' + ticker + '&padTimeSeries=true&type=' + '%2cquarterlyTotalRevenue' +
'%2c&merge=false&period1=493590046&period2=1672016399&corsDomain=finance.yahoo.com';
var obj = UrlFetchApp.fetch(url, { muteHttpExceptions: true }).getContentText();
var obj = JSON.parse(obj); //Convert strings to object
console.log(obj);
}
When your script is modified, how about the following modification?
Modified script:
var obj = ### // Please set your value.
var valeus = [["asOfDate", "raw"], ...obj.timeseries.result[0].quarterlyTotalRevenue.map(({ asOfDate, reportedValue: { raw } }) => [asOfDate, raw])];
var res = valeus[0].map((_, c) => valeus.map(r => r[c]));
// return res; // If you want to use this as a custom function, please use this.
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, res.length, 2).setValues(res);
In this modification, the values are put to the active sheet. If you want to use this script as a custom function, please return the values like return res;.
Reference:
map()

Exporting Gcal with Colours

Is there any way to export colours from Goggle Calander and post them into Goggle Sheets - I've seen posts from 2019 from various sites saying that this functionality was impossible, but I use colours to break up my calendar and I would love to bring colours over to help with my stats.
You can follow this guide:
Create a new Google Sheet
Create a new Bound Script via Extensions > Apps Script
Activate Advanced Service for accesing Calendar API Colors
Copy this code in:
const sS = SpreadsheetApp.getActiveSheet()
function bringCalendarToSheet() {
// Getting the colors for the Calendar and Events
const colors = Calendar.Colors.get()
const colorsCalendar = colors.calendar
const colorsEvents = colors.event
// Parsing and setting the data for the Calendar Colors
const A1 = sS.getRange('A1').setValue('Calendar Colors')
const colorsCalendarLength = Object.keys(colorsCalendar).length
const rCC = sS.getRange(2, 1, 1, colorsCalendarLength).setBackgrounds([Object.keys(colorsCalendar).map(k => {
return colorsCalendar[k].background
})])
// Parsing and setting the data for the Event Colors
const A3 = sS.getRange('A3').setValue('Event Colors')
const colorsEventsLength = Object.keys(colorsEvents).length
const rEC = sS.getRange(4, 1, 1, colorsEventsLength).setBackgrounds(
[Object.keys(colorsEvents).map(k => {
return colorsEvents[k].background
})]
)
}
This will show all Calendar available colors:
Result:

Office.js | Excell add in | get selected cell address on click

I am working on a Excel Web Add-In using Office.js. I need to get selected cell's Address with below scenario:
Open the Excel, Don't load add-in, click on any Cell in excel worksheet area. eg:A4
Load the add-in.
Again click on the same cell number eg:A4 that was highlighted on worksheet area as before loading add-in we selected.
Its not triggering the below code:
Office.context.document.addHandlerAsync(Office.EventType.DocumentSelectionChanged,
function (eventArgs) {
Excel.run(function (ctx) {
var range = ctx.workbook.getSelectedRange();
range.load(['address', 'values']);
return ctx.sync().then(function () {
showNotification("", range.values[0][0] + " Address:" + range.address);
});
});
});
NOTE: If I select cell Id other than previously selected cell id eg.A5 its working. Even again if I try to select from cell id A5 to previously selected cell id A4 its working.
Only if we try to select same cell its not triggering the event.
Spend lots of time can some one please help or its limitation in microsoft excel?
I think this is by design, as you are listening to SelectionChanged event, if the current selection is A4, and you click A4, it would not trigger the event as you didn't change the selection.
I am not sure your scenario, if you want to show the current selection, you could add the code before register the event. here is a sample code
async function run() {
await Excel.run(async (context) => {
var range = context.workbook.getSelectedRange();
range.load();
await context.sync();
console.log(range);
Office.context.document.addHandlerAsync(Office.EventType.DocumentSelectionChanged, showSelection);
});
}
async function showSelection(){
Excel.run(async (context) => {
var range = context.workbook.getSelectedRange();
range.load();
await context.sync();
console.log(range);
});
}

How to copy a Google sheet and get data validation to stay intact?

I have a Google spreadsheet template with two sheets, Data Entry and Data Validation. The Data Validation sheet has a number of columns with valid values for matching columns on the Data Entry sheet. Everything works as expected. I need to copy these two sheets to a Sheet Under Test (SUT). I am using the sheets API to copy both sheets. I copy the Data Validation sheet first and then the Data Entry sheet. Here's the code and this appears to work.
const request = {
spreadsheetId :fromSpreadsheetId,
sheetId : fromSheetId,
resource:{
destinationSpreadsheetId: toSpreadsheetId,
},
}
const result = await _sheetService.spreadsheets.sheets.copyTo(request)
On my SUT, both sheets appear and the Data entry sheet has all the expected dropdowns and they all have the proper values. Seems perfect. The problem is when you select an item from any drop down in any column it selects and enters the proper value and then adds a red triangle and the message that an invalid value has been entered. If the column has the rejection setting then the value is removed and the error dialog appears.
The image shows two cells where I have already selected Video Course from the drop down.
If I go in and reselect column where I want validation, use Data→DataValidation… and just hit the Save button that column starts working, so it would appear everything came across correctly but the sheet doesn't think so. Is there any programmatic way to force the above process that I did manually? Is there something else I need to do in the sheets.copyTo method to make this work properly?
EDIT
This project is written in Node.js with a combination of TypeScript and JavaScript. The lower level code for talking to the Sheets API and copying the sheet between spreadsheets can be found in this github file. The method is copySheetFromTo and it's at the bottom of the file.
A sample source sheet with public view permissions
A sample destination sheet with public edit permissions
The integration test that used the above two files to copy the sheets is at the bottom of the file and has 'DEBUGGING TEST' at the beginning of the name (starts at line 209)
You want to copy the sheet including Data Validation.
When the copied sheet is used, an error occurs at the drop down menu of Data Validation.
You want to remove this error.
If my understanding is correct, how about this answer? In this answer, in order to remove the error, I overwrite the Data Validation of the copied sheet as a workaround. Please think of this as just one of several workarounds.
The flow for your situation is as follows.
Flow:
Retrieve all data validations from the sheet of Data Entry in the source Spreadsheet ("DataValidationTest") using the spreadsheet.get method.
Copy the sheets of Data Entry in the source Spreadsheet ("DataValidationTest") to the destination Spreadsheet ("Public Destination Sheet").
After the sheets of Data Entry was copied, rename the sheet name from Copy of Data Entry to Data Entry.
Then, overwrite the retrieved data validations to the sheet of Data Entry using the spreadsheet.batchUpdate method.
In this case, the structure of data validations retrieved by the spreadsheet.get method is almost the same with the structure for the spreadsheet.batchUpdate method. This workaround used this.
Copy the sheets of Data Validation in the source Spreadsheet ("DataValidationTest") to the destination Spreadsheet ("Public Destination Sheet").
Rename the sheet name of Copy of Data Validation to Data Validation.
Sample script:
When you test this script, please set the variables. And I think that sheet of sheet.spreadsheets.get(), sheet.spreadsheets.batchUpdate() and sheet.spreadsheets.sheets.copyTo() is the same with sheetOps of your script.
const srcSpreadsheet = "###"; // Please set this.
const tempDestSheetId = "###"; // Please set this.
const srcDataEntrySheetId = 0; // Please set this.
const srcDataValidationSheetId = 123456789; // Please set this.
let dataValidation = await sheet.spreadsheets.get({
spreadsheetId: srcSpreadsheet,
ranges: ["Data Entry"],
fields: "sheets/data/rowData/values/dataValidation"
});
let data = dataValidation.data.sheets[0].data;
let rows = [];
for (let i = 0; i < data.length; i++) {
if (data[i].rowData) {
rows = data[i].rowData;
break;
}
}
sheet.spreadsheets.sheets.copyTo(
{
spreadsheetId: srcSpreadsheet,
sheetId: srcDataEntrySheetId,
resource: { destinationSpreadsheetId: tempDestSheetId }
},
(err, res) => {
sheet.spreadsheets.batchUpdate(
{
spreadsheetId: tempDestSheetId,
resource: {
requests: [
{
updateSheetProperties: {
fields: "title,sheetId",
properties: { sheetId: res.data.sheetId, title: "Data Entry" }
}
},
{
updateCells: {
rows: rows,
range: { sheetId: res.data.sheetId },
fields: "dataValidation"
}
}
]
}
},
(er, re) => {
if (err) {
console.error(er);
return;
}
console.log(re.data);
}
);
}
);
let result1 = await sheet.spreadsheets.sheets.copyTo({
spreadsheetId: srcSpreadsheet,
sheetId: srcDataValidationSheetId,
resource: { destinationSpreadsheetId: tempDestSheetId }
});
let result2 = await sheet.spreadsheets.batchUpdate({
spreadsheetId: tempDestSheetId,
resource: {
requests: [
{
updateSheetProperties: {
fields: "title,sheetId",
properties: {
sheetId: result1.data.sheetId,
title: "Data Validation"
}
}
}
]
}
});
console.log(result2.data);
Note:
This script supposes that Sheets API has already been able to be used.
This is the simple modified script for showing the flow of workaround. So please modify this for your situation.
As an important point, in order to overwrite the data validations to the copied sheet of Data Entry, it is required to execute it after the copy of the sheet of Data Entry was completely finished. So I modified the script like above.
References:
Method: spreadsheets.batchUpdate
Method: spreadsheets.get
Method: spreadsheets.sheets.copyTo

How to unlock only specific cells from write protected worksheet using excel javascript API

I am using office 365 and Excel online (Build 16.0.9403.1875).
and I am creating Microsoft Excel online Add-ins, using Excel javascript API.
I have a requirement like write protection for entire sheet except few cells (Range).
So, I referred Format protection API, but while debugging, the ‘locked’ property is of no effect in action.
I referred, stack over flow too with this link
And others too
As, I have already tried with the suggestion given by above forum links.
I just expecting reply by working snippet of code.
My code samples are below
Excel.run(function (ctx) {
//Worksheet
var sheet = ctx.workbook.worksheets.getItem("Sheet1");
//Entire Range
var entireRange = sheet.getRange();
entireRange.format.protection.locked = false;
//Specific Range
var range = sheet.getRange("A1:B5");
return ctx.sync()
.then(() => {
//Set specific range "locked" status to true.
range.format.protection.locked = true;
})
.then(ctx.sync)
.then(() => {
//Protect Entire sheet
sheet.protection.protect({
allowInsertRows: false,
allowDeleteRows: false
});
});
}).catch(errorHandler);
Thanks.

Resources