Apps Script - How to copy data containing checkboxes? - arrays

I'm updating large quantities of data using a script. I have to use arrays since .getValue and .setValue is very inefficient. My problem is that the data I am handling is containing checkboxes but when I use an array to copy and paste the data, the checkboxes are turned into TRUE and FALSE strings.
Is there any way to keep the checkbox object when using arrays to copy data ? Using .insertCheckboxes on individual cells is also very slow (and I cannot use .getRange().insertCheckboxes since the cells that contain checkboxes are not always adjacent).

If the source data is in a spreadsheet range, use Range.copyTo() with the appropriate CopyPasteType.
If you cannot use Range.copyTo() for some reason, you can copy values and validations with something like this:
function copyFromSheet1ToSheet2() {
const ss = SpreadsheetApp.getActive();
const source = ss.getRange('Sheet1!A1:D10');
const target = ss.getRange('Sheet2!A1');
copyValuesAndValidations(source, target);
}
function copyValuesAndValidations(sourceRange, targetRange) {
targetRange = targetRange.offset(0, 0, sourceRange.getHeight(), sourceRange.getWidth());
targetRange.setValues(sourceRange.getValues());
targetRange.setDataValidations(sourceRange.getDataValidations());
}

Related

How do I read numbers with appscript from a google sheet and want to use the number as formatted on another sheet"

I am doing a dependant dropdown list in google sheets using a script.
The source sheet data is read into an array, The destination sheet pulls the dropdown options from the aray.
The numbers from the source sheet are formatted as degrees; 0°, 45°, 90°, 180°.
When the are displayed in the dropdown on the destination sheet the degree symbol is removed and the 0 option doesn't show as an option at all. so I get 45, 90, 180. If I format the destination cell as percent, the the chosen option doesn't match the validation. and I still can't get the 0°.
How can I pass the formatting with the numbers so everything works correctly?
I was thinking I need to do something with setNumberFormat('##0"°"'), but I don't know how.
This is how I am creating the data from the array:
var ws = SpreadsheetApp.getActiveSpreadsheet() .getSheetByName(mainWsName) ;
var wsOptions = SpreadsheetApp.getActiveSpreadsheet() .getSheetByName(optionsWsName) ;
var options = wsOptions.getRange(3, 2,wsOptions.getLastRow()-2, 5).getValues();
var optionsFormat = wsOptions.getRange(3, 2,wsOptions.getLastRow()-2, 5).getNumberFormat()
This is how the data is being retrieved from the array:
var filteredOptions = options.filter(function(o){ return o[0] === firstLevelColValue && o[1] === val });
var listToApply = filteredOptions.map(function(o){ return o[2] });
var cell = ws.getRange(r, thirdLevelColumn) ;
applyValidationToCell(listToApply,cell);
This is my first time asking a question here, I hope I have given the information necessary to solve my problem. Let me know if there is additional information needed.
Thanks
Use getDisplayValues() instead of getValues()
This will allows you to retrieve the values in exactly the same way as they are displayed in the spreadsheet.

Google Sheets - Allow only one checkbox to be checked when the boxes are placed in specific cells across a wide range

I need a simple script for Google Sheets to allow only one of 6 checkboxes to be checked at a time. The end user will check a checkbox and should see the one they checked before turn unchecked or FALSE when they check the new one. The "problem" for a newbie like is me that the checkboxes will be asymmetrically located. They are in cells D14, D30, J14, J32, P14 and P30. I also need to duplicate this sheet a number of times, so preferably the script should work on any of the duplicates I make the same way. The cells will always be these six cells in every sheet.
I've seen many posts about this subject and tried to use the example scripts to my problem without success, so I want to ask specifically about my spreadsheet.
Here is a link to a draft version of my sheet with the locations of the checkboxes:
https://docs.google.com/spreadsheets/d/1PtxetS-Gyv7LyMD19yF3NuWZ24RvqUjyK42SmQTttiU/edit?usp=sharing
Thank you,
Lassi
You can set up an onEdit() trigger that will:
Check whether the cell edited is a checkbox (by verifying its range).
Check that the new value for the cell is TRUE (the checkbox has been enabled).
In case both of 1 and 2 apply, unset the rest of the defined checkboxes in the same sheet.
Note that the execution of the script may be a bit slow (due to Google Apps Script limitations) and that the script will work independently for each of the Sheets in your workbook.
Code
var CHECKBOX_CELLS = ["D14", "J14", "P14", "D30", "J32", "P30"];
function onEdit(e) {
var range = e.range;
var checkboxIndex = CHECKBOX_CELLS.indexOf(range.getA1Notation());
if (checkboxIndex > -1 && range.getValue() == true) {
var sheet = range.getSheet();
for (var i=0; i<CHECKBOX_CELLS.length; i++) {
if (i==checkboxIndex) continue;
sheet.getRange(CHECKBOX_CELLS[i]).setValue(false);
}
}
}

IndexedDb dynamically populating existing ObjectStores

I have created many, let's say three ObjectStores inside a defined and versioned IndexedDB schema.
I need to populate all of them. To do so, I created an object which stores both name end endpoint (where it gets data to populate).
Also to avoid error when trying to fill objectstores already populated, I use the count() method to ... count key inside the objectstore and if there are 0 key, then populates, else reads.
It works perfect if I execute on a one by one basis, that is instead of using a loop, declare and execute each one of the three objectstores.
However when invoking the function to populate each storage inside a loop, I get the following error message for the last two objectstores to be populated:
Failed to read the 'result' property from 'IDBRequest': The request
has not finished. at IDBRequest.counts.(anonymous function).onsuccess
Here is the code:
// object contains oject stores and endpoints.
const stores = [
{osName:'user-1', osEndPoint:'/api/1,
{osName:'user-2', osEndPoint:'/api/2},
{osName:'user-3', osEndPoint:'/api/3}
];
// open db.
var request = indexedDB.open(DB_NAME, DB_VERSION);
// in order to dynamically create vars, instantiate two arrays.
var tx = [];
var counts = [];
var total = [];
// onsuccess callback.
request.onsuccess = function (e) {
db = this.result;
for(k in stores) {
tx[k] = db.transaction(stores[k].osName).objectStore(stores[k].osName);
counts[k] = tx[i].count();
counts[k].onsuccess = function(e) {
total[k] = e.target.result;
// if the counting result equals 0, then populate by calling a function that does so.
if (total[k] == 0) {
fetchGet2(stores[k].osEndPoint, popTable, stores[k].osName); //
} else {
readData(DB_NAME, DB_VERSION, stores[0].osName);
}
};
} // closes for loop
}; // closes request.onsuccess.
The fetchGet2 function works well inside a loop, for example the loop used to create the objectstores, and also has been tested on a one by one basis.
It looks like an async issue, however I cannot figure how to fix the problem which is to be able to populate existing objectstores dynamically, avoiding to populate filled objectsores and only filling empty ones.
Indeed testing without the count issue, but inside the loop works perfect, or with the count but without loop.
At the moment and when logging counts[k], It only logs data for the last member of the object.
Thanks in advance, I'm coding with vanilla js, and I'm not interested in using any framework at all.
Yes, this looks like an issue with async. For loops iterate synchronously. Try writing a loop that does not advance i until each request completes.

Passing YouTube data into Google sheets column

My goal is to pass in a YouTube channel's id and call that channel's video view metrics for a given window of time, store that data in an array and then pass each video view metric into one column of array.length in descending order.
//...key variables
var channelId = sheet.getActiveCell().getValue();
var offsetCell = sheet.getActiveCell().offset(0,2);
//further down the script...
for(i=0; i < dataResponse.items.length; i++) {
var data = [];
var vidDataLen = dataResponse.items.length;
var offsetRange = sheet.getRange(offsetCell, vidDataLen, 0)
data.push(dataResponse.items[i].statistics.viewCount);
//sheet.appendRow(data)
offsetCell.setValue([data])
}
As you can follow, I initially used appendRow, but I didn't want data to be appended into overwriting rows, I wanted the data to pass into, the column and row of offsetCell, and descending into the succeeding cells.
My efforts with
var offsetRange = sheet.getRange(offsetCell, vidDataLen, 0)
were attempting to create an active range based on the number of items in the data array, since that will vary on each channel.
However, that did not work, because getRange does not accept objects as parameters.
Are there any google-script functions I could use to pass the array data into an offset cell and successive cells in that same column?
NOTE: Running this script with the offsetRange variable commented out results in the YouTube api being successfully called, however, only one value from the 'data' array is passed into offsetCell
NOTE 2: I have scoured StackOverflow for google scripted questions and related subjects, however I have not seen an active or relevant solution for passing multiple stored values from an API call into a specific range of offset cells (in one column).
The solution for this was relatively straight forward
I removed the data array and used the statement sheet.insertRows(offsetCell.getRow()+1,vidDataLen);
to create the range of cells in the column I wanted to pass data into so existing data would not be overwritten
var vidDataLen = dataResponse.items.length;
sheet.insertRows(offsetCell.getRow()+1,vidDataLen);
for(i=0; i < dataResponse.items.length; i++) {
offsetCell.setValue(dataResponse.items[i].statistics.viewCount);
offsetCell = offsetCell.offset(1, 0);
}
Instead of passing data into a loop array, I just passed each value directly into the setValue() method's argument, and then assigned offsetCell to offsetting each new iteration of offsetCell by 1 row and 0 columns.

Get all the Records from GXTGrid

//MyGrid
ListStore< PojoSurveyReportApproved> store = new ListStore< PojoSurveyReportApproved>(loader);
List<ColumnConfig> configs = getSurvey(list);
cm = new ColumnModel(configs);
cp = new ContentPanel();
final Grid< PojoSurveyReportApproved> grid = new Grid< PojoSurveyReportApproved>(store, cm);
grid.setTitle("ddddddd");
grid.setBorders(true);
grid.getAriaSupport().setDescribedBy(toolBar.getId() + "-display");
cp.removeAll();
cp.add(grid);
This is my Grid, which loads dynamically. whenever it changes, all the records from the grid should be retrieved, where i can easily export it to Excel.
Just i want is all the records in the grid eighter as an array or list, is there any listener to handle it or any way i can get all the records.
I have tried out in some ways by adding a listener to a store by it does not gives me result
Did you try-
store.getAll(); ?
This code takes all the records in the grid and returns as a collection. However, you may need to take another arrayList to use the store values depending on your needs.

Resources