Quantcast
Channel: Hot Weekly Questions - Web Applications Stack Exchange
Viewing all articles
Browse latest Browse all 9782

Validate values before writing

$
0
0

In my Sheets projects I often have to write values at the end of the sheet programmatically. I use data validations, some of which don't accept invalid values. My problem is that if a write operation fails, I end up with an incomplete input. I want my operations to either succeed 100% or not at all.

Suppose I have a single-column sheet that only accepts A, B or C values:

enter image description here

First I thought I could validate the input values before writing:

const sheet = ss.getActiveSheet(); // Single-column sheetconst dataRange = sheet.getDataRange(); // Single-column range that only accepts A, B or C values.const writeValues = [["A"], ["B"], ["C"], ["D"]]; // Invalid mock input. D is not valid.const writeRange = sheet.getRange(dataRange.getNumRows() + 1, 1, writeValues.length, writeValues[0].length);writeRange.getDataValidations().forEach((row, i) => row.forEach((validation, j) => {  if (validation && !validation.getAllowInvalid()) {    // Interrupt if writeValues[i][j] is not valid.  }}));writeRange.setValues(writeValues); // Will fail because D is not a valid input value.

However this doesn't work, because for some reason writeRange doesn't have any validations. It seems like they get applied only after the range initialization, but before writing.

Then I thought I could just sacrifice some effectiveness with a try/catch block that deletes the newly created rows afterwards if the write operation fails.

const sheet = ss.getActiveSheet(); // Single-column sheetconst dataRange = sheet.getDataRange(); // Single-column range that only accepts "A", "B" or "C" values.const writeValues = [["A"], ["B"], ["C"], ["D"]]; // Invalid mock input. "D" is not valid.const writeRange = sheet.getRange(dataRange.getNumRows() + 1, 1, writeValues.length, writeValues[0].length);try {  writeRange.setValues(writeValues);} catch(error) {  sheet.deleteRows(writeRange.getRow(), writeValues.length); // Should remove the incompletely written range.  throw error;}

But it turns out that setValues throws an error that is not catchable! This issue has been submitted 7 years ago and still persists.

Any ideas for a workaround?

EDIT: I can use the first solution if I simply insert the required rows before initializing the range:

const sheet = ss.getActiveSheet();const dataRange = sheet.getDataRange();const firstRow = dataRange.getNumRows() + 1;sheet.insertRowsAfter(dataRange.getNumRows(), writeValues.length);const writeRange = sheet.getRange(firstRow, 1, writeValues.length, writeValues[0].length);writeRange.getDataValidations().forEach((row, i) => row.forEach((rule, j) => {  if (rule && !rule.getAllowInvalid()) {    const args = rule.getCriteriaValues();    if (args[0] && values[i][j] && !args[0].includes(values[i][j])) {      sheet.deleteRows(firstRow, writeValues.length);      throw new Error(`"${writeValues[i][j]}"" is invalid.`);    }  }}));writeRange.setValues(writeValues);

Viewing all articles
Browse latest Browse all 9782

Trending Articles