Google Apps Script: How to update range on several slicers at once? - google-apps-script

Problem: Cannot update the ranges for two or more slicers with Google Script
Info: The sheet contains two slicers
Code:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Tracking');
var slicers = sheet.getSlicers();
var slicerRange = sheet.getRange('A3:A160'); //current slicer range A3:A165
slicers[0,1].setRange(slicerRange);
}
Error: Two slicers can either have zero or all common rows.
What is wrong? The code works if I only work with one slicer in the sheet and code.
Thanks so much in advance for any help!

I dont think you can edit their range.
But you could probably remove and create them again with your new range:
function test(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Tracking');
var slicers = sheet.getSlicers();
var newRange = sheet.getRange('A3:A160'); // your new range
var slicersCount = 0;
for (i=0;i<slicers.length;i++){
slicers[i].remove();
slicersCount ++;
}
for (i=0;i<slicersCount;i++){
sheet.insertSlicer(newRange, 5, 3); // choose anchorRowPos and anchorColPos you want
}
}
And then you can modify the rest of their settings as you wish.
Hope this helps.

Thanks a lot for your help! It eventually helped me to make it work.
This is the code I ended up with, which is without counter on the insertSlicer() since I need to give individual settings:
function test() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Tracking');
var slicers = sheet.getSlicers();
var rowValue = sheet.getLastRow();
var newRange = sheet.getRange('A3:X'+rowValue); //new range
for (i=0; i<slicers.length; i++){
slicers[i].remove();
}
//Slicers to column A and D
destinationSheet.insertSlicer(newRange, 2, 1); // choose anchorRowPos and anchorColPos
destinationSheet.insertSlicer(newRange, 2, 4);
//Get new slicers
var slicers = destinationSheet.getSlicers();
var filterCriteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(['']).build();
slicers[0].setColumnFilterCriteria(1, filterCriteria);
slicers[0].setTitle('Title1');
var filterCriteria2 = SpreadsheetApp.newFilterCriteria().setHiddenValues(['1']).build();
slicers[1].setColumnFilterCriteria(24, filterCriteria2);
slicers[1].setTitle('Title2');
}

Related

Google Script for updating Slicer ranges

I have a problem in updating the ranges in multiple slicers at once, which is not possible.
I tried using the script below that i found in another thread for automatically deleting and recreating the slicers with the desired range.
but i get the following error. "destinationSheet" not defined.
Would appreciate in you can help me with a solution here.
Thank you.
function test() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Tracking');
var slicers = sheet.getSlicers();
var rowValue = sheet.getLastRow();
var newRange = sheet.getRange('A3:X'+rowValue); //new range
for (i=0; i<slicers.length; i++){
slicers[i].remove();
}
//Slicers to column A and D
destinationSheet.insertSlicer(newRange, 2, 1); // choose anchorRowPos and anchorColPos
destinationSheet.insertSlicer(newRange, 2, 4);
//Get new slicers
var slicers = destinationSheet.getSlicers();
var filterCriteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(['']).build();
slicers[0].setColumnFilterCriteria(1, filterCriteria);
slicers[0].setTitle('Title1');
var filterCriteria2 = SpreadsheetApp.newFilterCriteria().setHiddenValues(['1']).build();
slicers[1].setColumnFilterCriteria(24, filterCriteria2);
slicers[1].setTitle('Title2');
}
Thanks to Tanaike's suggestion to change the "destinationSheet" part of the code to 'sheet', the code writen as below worked.
function test() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Tracking');
var slicers = sheet.getSlicers();
var rowValue = sheet.getLastRow();
var newRange = sheet.getRange('A3:X'); //new range
for (i=0; i<slicers.length; i++){
slicers[i].remove();
}
//Slicers to column A and D
sheet.insertSlicer(newRange, 2, 1); // choose anchorRowPos and anchorColPos
sheet.insertSlicer(newRange, 2, 4);
//Get new slicers
var slicers = sheet.getSlicers();
var filterCriteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(['']).build();
slicers[0].setColumnFilterCriteria(1, filterCriteria);
slicers[0].setTitle('Title1');
var filterCriteria2 = SpreadsheetApp.newFilterCriteria().setHiddenValues(['1']).build();
slicers[1].setColumnFilterCriteria(24, filterCriteria2);
slicers[1].setTitle('Title2');
}

Run function on 1 sheet only instead of .forEach

I believe this will be a super easy question for you. I downloaded a YT script to automatically update YT views on Google Sheets which you can find here (https://developers.google.com/gsuite/solutions/youtube-tracker).
I have a spreadsheet with 12 tabs and the code has a function to go through every tab in the spreadsheet.
function markVideos() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
// Runs through process for each tab in Spreadsheet.
sheets.forEach(function(dataSheet) {
var tabName = dataSheet.getName();
var range = dataSheet.getDataRange();
var numRows = range.getNumRows();
var rows = range.getValues();
var headerRow = rows[0];
I want to change it to apply to a specific tab only, let's say "Sheet12", instead of running it for every tab.
function markVideos() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet12");
// Runs through process for each tab in Spreadsheet.
function NameOfTheFunction(dataSheet) {
var tabName = dataSheet.getName();
var range = dataSheet.getDataRange();
var numRows = range.getNumRows();
var rows = range.getValues();
var headerRow = rows[0];
I tried this but had no luck because it doesn't seem to be applying the function to the specific sheet. I believe this is super easy fix but I have no idea about programming.
Remove the forEach statement and use getSheetByName instead of getSheets:
function markVideos() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tabName = 'Sheet12';
var dataSheet = ss.getSheetByName(tabName)
var range = dataSheet.getDataRange();
var numRows = range.getNumRows();
var rows = range.getValues();
var headerRow = rows[0];
}
Array ForEach() Method calls a function once for each element in an array. That is why a function must be defined that will take an array element function(dataSheet)
Since you only need to access 1 sheet based on its sheet name.
You don't need to define a function to access the properties of that sheet.
Sample:
Sample Code:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName("Sheet1");
var tabName = sheets.getName();
var range = sheets.getDataRange();
var numRows = range.getNumRows();
var rows = range.getValues();
var headerRow = rows[0];
Logger.log(tabName);
Logger.log(numRows);
Logger.log(rows);
Logger.log(headerRow);
}
Logger Log Output:
References:
Class Sheet Methods
SpreadsheetApp Methods

google sheets script conditionally move row to another spreadsheet

I am new to this and I am having some trouble trying to figure this out. I have a spreadsheet that collects data from a google form. I am trying to find a way to move that data based on a column answer to a different google sheet. (Not a sheet in the same document but a different document all together). It seems like there is some information about moving to a different tab in the same document, but not a different document.
I will first say that I tried just an IMPORTRANGE function, but that only mirrors the data, and does not let you update or change cells.
Here is what I have been able to piece together so far, but I may be way off.
I have a trigger that would run every hour.
function myFunction() {
var ss = SpreadsheetApp.openById('1U0I9SkbGkHgm-vRkwf2Ppc_yxlqrVlg2t8yKRy3sYuI');
var sheetOrg = ss.getSheetByName("Form Responses 1");
var value1ToWatch = "ANDERSON";
var value2ToWatch = "BARNES";
var sheetNameToMoveTheRowTo = "Sheet1"; //sheet has same name for each target openByID(" *url key* ")
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ts1 =SpreadsheetApp.openById("1PxV1PQrMdu_2aSru4dpan8cUgHYdlYPUp5anyzjMAms");
sheet1in = ts1.getSheetByName("Sheet1");
var ts2 = SpreadsheetApp.openById("1BYyQZNiXc2QqsyqWs7uazjl5B6mfFYM1xj3u8gWyYOQ");
sheet1in = ts2.getSheetByName("Sheet1");
arr = [],
values = sheetOrg.getDataRange().getValues(),
i = values.length;
while (--i) {
if (value1ToWatch.indexOf(values[i][1]) > -1) {
arr.unshift(values[i])
sheetOrg.deleteRow(i + 1)
sheet1in.getRange(sheet1in.getLastRow()+1, 1, arr.length,
arr[0].length).setValues(arr);
};
if (value2ToWatch.indexOf(values[i][1]) > -1) {
arr.unshift(values[i])
sheetOrg.deleteRow(i + 1)
sheet2in.getRange(sheet2in.getLastRow()+1, 1, arr.length,
arr[0].length).setValues(arr);
};
}
}
The sheet google forms dumps the information into is "Form Responses 1".
Column B is the cells I want to get the values from. (There are a total of 9 different values that it can be like "ANDERSON", "BARNES", "SMITH", etc).
For sheetNameToMoveTheRowTo is "Sheet1" - that may be confusing and I may need to change that, but for example
ts1 =SpreadsheetApp.openById("1PxV1PQrMdu_2aSru4dpan8cUgHYdlYPUp5anyzjMAms") the sheet name that I want the information moved to is "Sheet1".
ts2 = SpreadsheetApp.openById("1BYyQZNiXc2QqsyqWs7uazjl5B6mfFYM1xj3u8gWyYOQ") the sheet name is also "Sheet1" but in a different document.
I think if I were able to get the "ANDERSON" one to work, then I can just add additional variables for each possible response, and just copy and paste additional "IF" statements, just changing the valueToWatch and targetSheet values. <= if that is not correct please let me know
I have tried to both debug, and run the script above but nothing happens. There are no errors reported on the debug, but it is not moving any information over.
Any idea what I am doing wrong?
// UPDATE I got this to work. I have updated the code listed with what worked for me.
I think that copyTo() method will not work like you mentioned, it operates on same SpreadSheet. I'm sending you example with looping on source sheet data and then setting the target sheet values with it.
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var allrange = ss.getActiveRange();
var range = sheet.getRange("A1:A10");
var values = range.getValues();
var allvals = [];
for(var i = 0; i < values.length; i++) {
allvals.push( values[i] ) ;
}
var dataLength = allvals.length;
// alert data
var ui = SpreadsheetApp.getUi();
// ui.alert( JSON.stringify(allvals) )
// copy to new Google SpreadSheet
var newSheet = SpreadsheetApp.openById('1F79XkNPWm2cCWlB2JP3K4tAYRESKUgtHK4Pn2vbJEiI').getSheets()[0];
var tmp = "A1:A" + dataLength ;
var newRange = newSheet.getRange( tmp );
newRange.setValues( allvals );
}
Here's a simple example of moving data from one spreadsheet to another.
function movingDataToSS(){
var ss=SpreadsheetApp.getActive();
var dss=SpreadsheetApp.openById('ssId');
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var dsh=dss.getSheetByName('Sheet1');
var drg=dsh.getRange(1,1,rg.getHeight(),rg.getWidth()).setValues(vA);
}
If you interested in placing some conditions on your output by only getting output from odd rows and even columns.
function movingDataOddRowsAndEvenCols(){
var ss=SpreadsheetApp.getActive();
var dss=SpreadsheetApp.openById('ssId');
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var h=rg.getHeight();
var w=rg.getWidth();
var dsh=dss.getSheetByName('Sheet1');
for(var i=0;i<h;i++){
var out=[];
if(i%2==0){
for(var j=0;j<w;j++){
if(j%2==1){
out.push(vA[i][j]);
}
}
dsh.appendRow(out);
}
}
}

Copy value and format from a sheet to a new google Spreadsheet document?

I need to copy a sheet on google SpreadSheet to another SpreadSheet document.
I´ve done my research, and I found two methods that do this, however both have problems that I don´t know how to fix.
The first method copies the sheet with format, but it keeps the referenced cells, so I get a reference error in the new document (#ref). I need a function that copies the format and the values (not references).
function copySheet() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[0];
var destination = SpreadsheetApp.openById("15ucPbZrIYXZAOCYVdpK6OA0oyQT1NcsmuiJmDRfdpHQ");
sheet.copyTo(destination);
}
This second method copies the values without references, however it copies only values, without format.
function copySheetValues()
{
var source = SpreadsheetApp.getActiveSheet();
var sourcename = source.getSheetName();
var sourceDataRange = source.getDataRange();
var sourceSheetValues = sourceDataRange.getValues();
var sourceRows = sourceDataRange.getNumRows();
var sourceColumns = sourceDataRange.getNumColumns();
var destination = SpreadsheetApp.openById('15ucPbZrIYXZAOCYVdpK6OA0oyQT1NcsmuiJmDRfdpHQ');
destination.insertSheet(sourcename, 0);
destination.getDataRange().offset(0, 0, sourceRows, sourceColumns).setValues(sourceSheetValues);
}
How do I write a function that keeps the format and copies the values?
Since you seem to know how to get and set values using the whole data range, just use the other methods to get and set all the other parameters.
The script editor autocomplete is a great help in this case to try not to forget one !
I hope the list is complete, it is a bit of a pain to write though !.
code below, if one of them is not useful to you just delete it (in both directions (set and get).
function copySheetValues(){
var source = SpreadsheetApp.getActiveSheet();
var sourcename = source.getSheetName();
var sValues = source.getDataRange().getValues();
var sBG = source.getDataRange().getBackgrounds();
var sFC = source.getDataRange().getFontColors();
var sFF = source.getDataRange().getFontFamilies();
var sFL = source.getDataRange().getFontLines();
var sFFa = source.getDataRange().getFontFamilies();
var sFSz = source.getDataRange().getFontSizes();
var sFSt = source.getDataRange().getFontStyles();
var sFW = source.getDataRange().getFontWeights();
var sHA = source.getDataRange().getHorizontalAlignments();
var sVA = source.getDataRange().getVerticalAlignments();
var sNF = source.getDataRange().getNumberFormats();
var sWR = source.getDataRange().getWraps();
var destination = SpreadsheetApp.openById('15ucPbZrIYXZAOCYVdpK6OA0oyQT1NcsmuiJmDRfdpHQ');
var destinationSheet = destination.insertSheet(sourcename, 0);
destinationSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues)
.setBackgrounds(sBG)
.setFontColors(sFC)
.setFontFamilies(sFF)
.setFontLines(sFL)
.setFontFamilies(sFFa)
.setFontSizes(sFSz)
.setFontStyles(sFSt)
.setFontWeights(sFW)
.setHorizontalAlignments(sHA)
.setVerticalAlignments(sVA)
.setNumberFormats(sNF)
.setWraps(sWR);
}
Edit :
Bryan's answer and your comment made me think of another solution, much more simple and that handles merged cells as well. Here is the code :
function copySheetValuesV2(){
var source = SpreadsheetApp.getActiveSheet();
var sourceName = source.getSheetName();
var sValues = source.getDataRange().getValues();
var destination = SpreadsheetApp.openById('15ucPbZrIYXZAOCYVdpK6OA0oyQT1NcsmuiJmDRfdpHQ');
source.copyTo(destination)
var destinationSheet = destination.getSheetByName('Copy of '+sourceName)
destinationSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues);// overwrite all formulas that the copyTo preserved
}
In both script be sure that the destination sheet name does not already exist. I didn't handle that case although it is quite easy to do with a try/catch structure.
Another route to try that I think Serge was alluding to here.
function myFunction() {
var source = SpreadsheetApp.openById('SOURCE_ID');
var sourceSheet = source.getSheetByName('Sheet1');
var sourceRange = sourceSheet.getDataRange();
var sourceValues = sourceRange.getValues();
var tempSheet = source.getSheetByName('temp');
var tempRange = tempSheet.getRange('A1');
var destination = SpreadsheetApp.openById('DEST_ID');
sourceRange.copyTo(tempRange); // paste all formats?, broken references
tempRange.offset(0, 0, sourceValues.length, sourceValues[0].length)
.setValues(sourceValues); // paste all values (over broken refs)
tempSheet.copyTo(destination); // now copy temp sheet to another ss
}
This is a variation upon Sergei's answer.
This script will copy all visible sheets and export them in to a new spreadsheet with " Final" appended to the document title.
function copySheetValuesV4(){
var sourceSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheets = sourceSpreadsheet.getSheets();
var destination = SpreadsheetApp.create(sourceSpreadsheet.getName()+' Final');
for (var i = 0; i < sourceSheets.length; i++){
var sourceSheet = sourceSheets[i];
if (!sourceSheet.isSheetHidden()) {
var sourceSheetName = sourceSheet.getSheetName();
var sValues = sourceSheet.getDataRange().getValues();
sourceSheet.copyTo(destination)
var destinationSheet = destination.getSheetByName('Copy of '+sourceSheetName).setName(sourceSheetName);
destinationSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues);// overwrite all formulas that the copyTo preserved */
}
destination.getSheetByName("sheet1").hideSheet() // Remove the default "sheet1" */
}
}

Copy Columns from a sheet to add at lastcolumn in "archive" sheet with GAS

Sorry for my english. ^^
Erm, i´ve found a script to copy from a sheet to an other Sheet.
My problem is: its copy with rows.
I want to copy columns and add 2 columns to lastcolumn on script running.
It becames a problem, because columns has no a1notification. A=1, B=2, etc.
copyTo wants A1notification.
Heres my script:
function Archiv() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var target = SpreadsheetApp.openById("sheetid");
var source_sheet = ss.getSheetByName("sheetname");
var target_sheet = target.getSheetByName("sheetnametarget");
var source_range = source_sheet.getRange("D4:E89");
var last_col = target_sheet.getLastColumn();
target_sheet.insertColumnAfter(last_col);
var target_range = target_sheet.getRange(">>>>(lastcol+1)<<<<4:>>>>>(lastcol+2)<<<<89");
source_range.copyTo(target_range, {contentsOnly:true});
}
The script have to run every Monday to archive the content of 2 Columns.
I hope you can understand my wish.
I have tested many things, but nothing helps. :(
Many thanks in advance.
Sebastian
You can use another range selection mode that will makes things very simple, see this doc, using integers for row and column numbers.
Your code could become like this :
function Archiv() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var target = SpreadsheetApp.openById("sheetid");
var source_sheet = ss.getSheetByName("sheetname");
var target_sheet = target.getSheetByName("sheetnametarget");
var source_range = source_sheet.getRange("D4:E89");
var last_col = target_sheet.getLastColumn();
while(target_sheet.getMaxColumns()<=last_col+2){// add columns only if necessary
target_sheet.insertColumnAfter(last_col)}
var source_values = source_range.getValues();
var target_range = target_sheet.getRange(4,last_col+1,source_values.length,2);// row Nr4, starting on last column+1, 2 columns width and 89-4 rows heigth
target_range.setValues(source_values);
}
I used getValues() and setValues() instead of copyTo() that returned an error : target and source must be in the same spreadsheet