Reputation: 8252
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?
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)
Upvotes: 1
Views: 1991
Reputation: 201573
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.
Data Entry
in the source Spreadsheet ("DataValidationTest") using the spreadsheet.get method.Data Entry
in the source Spreadsheet ("DataValidationTest") to the destination Spreadsheet ("Public Destination Sheet").Data Entry
was copied, rename the sheet name from Copy of Data Entry
to Data Entry
.Data Entry
using the spreadsheet.batchUpdate method.
Data Validation
in the source Spreadsheet ("DataValidationTest") to the destination Spreadsheet ("Public Destination Sheet").Copy of Data Validation
to Data Validation
.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);
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.Upvotes: 2