column B gets data updated
column C onwards is used to store consolidated data
im trying to copy a range of data to right next column
and update column C with data from column B
function doUpBCL() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('BLC');
var data_new = ss.getRange('B1').getDisplayValue();
var data_old = ss.getRange('C1').getDisplayValue();
if( data_new !== data_old ) // check if data changed
{
var lr = ss.getLastRow();
var lc = ss.getLastColumn();
var data = ss.getRange(1,3,lr,lc - 3).getValues();
ss.getRange(1,4,lr,lc - 4).setValues(data);
var data_ = ss.getRange(lr,2,1,1).getValues();
ss.getRange(lr,3,1,1).setValues(data_);
}
};
macro (created by Google Sheets) as EXAMPLE to ilustrate what i want is (i need help with above function, not this)
function upblc_macro() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('BLC'), true);
spreadsheet.getRange('D:D').activate();
spreadsheet.getRange('C:Z').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
spreadsheet.getRange('C:C').activate();
spreadsheet.getRange('B:B').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
};
using last row cos im going to use similar funcions to other pages and im trying to funcion where i dont have to adjust everytime
simply add new column, move or append to last column wont work the way i need
help is much appreciated, thanks
with lots of tries and errors, with a few tweaks and minor changes, i managed to make it work as i wanted
function doUpBCL() {
const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('BLC');
const data_new = ss.getRange('B1').getDisplayValue();
const data_old = ss.getRange('C1').getDisplayValue();
if( data_new !== data_old ) // check if data changed
{
var lr = ss.getLastRow();
var lc = ss.getLastColumn();
const data = ss.getRange(1,3,lr,lc-2).getValues();
ss.getRange(1,4,lr,lc-2).setValues(data);
const data_ = ss.getRange(1,2,lr,1).getValues();
ss.getRange(1,3,lr,1).setValues(data_);
}
else
{
}
};
not sure why of some stuff i changed, some other stuff i learned, but still learning
Related
I am a beginner with JavaScript and have been taking courses for a few months. I have a couple of scripts I have written so far that are up and running. I have an issue that I can’t get past which is very important to find a resolution for, so I’m hoping someone can help.
I have google survey’s that are being submitted and an on even form generator script that creates a form and produces a link in google sheets. The problem I’m having is that I need to be able to filter forms that belong to certain person on to a different spreadsheet using a script. I have written the script a few ways to try to achieve this but have been unsuccessful. The script works as intended but it removes the form generator links when it’s copied or moved.
Here is the filter script I had written:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var trn = ss.getSheetByName('Hull - NY');
var originalData = trn.getRange(2, 1, trn.getLastRow() - 1, 12).getValues();
var centerManager = 'Brooks, Robert';
if (trn.getColumn() == 3 && trn.getValue() == 'Brooks, Robert') {
var r = originalData.getRow();
var data = originalData.filter(function (item) {
return item[1] === centerManager;
});
var targetSheet = ss.insertSheet(centerManager);
targetSheet.getRange(2, 1, data.length, data[0].length).setValues(data).getLastRow();
}
}
I appreciate any help that could be provided!
You must read the formulas and then use the formula instead of the cell value, where a formula exist.
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const trn = ss.getSheetByName('Hull - NY');
const sourceRange = trn.getDataRange()
const originalValues = sourceRange.getValues();
const originalFormulas = sourceRange.getFormulas()
const centerManager = 'Brooks, Robert';
const MANAGER_COL = 2
const data = []
originalValues.forEach((row,i)=>{
if(row[MANAGER_COL-1] === centerManager){
originalFormulas[i].forEach((formula,i)=>{
if(formula[i]){
row[i] = formula
}
})
data.push(row)
}
});
const targetSheet = ss.insertSheet(centerManager);
if(data.length>0){
targetSheet.getRange(2, 1, data.length, data[0].length).setValues(data).getLastRow();
}
}
I am trying to write a script that, when a cell in a sheet changes "Негатив отсутствует", will replace the value of a cell in another sheet with the value "Нерелевант". Help please, what did I do wrong?
function ChangeTone(event) {
if (event.source.getActiveRange().getValue()=="Негатив отсутствует" && event.source.getActiveSheet()=="Разметка ТОП100 по суду"){
var sheet = SpreadsheetApp.getActiveSheet();
var currRow = sheet.getActiveCell().getRow();
var value = sheet.getRange(currRow, 1).getDisplayValue();
var pasteSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Тональность");
var data = pasteSheet.getDataRange().getValues();
// if(currRow > 2){
// sheet.deleteRow(currRow);
// }
for(var i = 1; i<data.length;i++){
if(data[i][1] == value){
pasteSheet.getRange((i), 2).clear({contentsOnly: true});
pasteSheet.getRange((i), 2).setValue('Нерелевант');
break;
}
};
// sheet.getActiveCell().setValue("");
}
}
Explanation / Issues:
Issue:
There is a clear issue with your code and in particular here:
event.source.getActiveSheet()=="Разметка ТОП100 по суду"
You are comparing a sheet object with a string and this will always return false. The correct way to do it would be:
event.source.getActiveSheet().getName()=="Разметка ТОП100 по суду"
but here I also tried to optimize your code because it is quite inefficient.
Optimization:
You don't take full advantage of the event object.
SpreadsheetApp.getActiveSpreadsheet() can be replaced by e.source.
You also define the same variables multiple times when you only need to do that once:
For event.source.getActiveSheet() and var sheet = SpreadsheetApp.getActiveSheet(); you can define a single variable to store the active sheet object and call it whenever you need it.
Last but not least. I am not quite sure about your logic regarding the for loop since you haven't mentioned it in your question.
But I see you use a for loop, an if statement and a break line to escape the for loop as soon as there is a match between the source value and the value in the paste sheet.
Instead of using a for loop, you can use findIndex to find the value that matches the criterion data[i][1] == value.
Also the full getDataRange() is not needed if you intend to use only one column, therefore I change that part too.
Solution:
function onEdit(e){
const ss = e.source;
const ar = e.range;
const activeSheet = ss.getActiveSheet();
const pasteSheet = ss.getSheetByName("Тональность");
if (ar.getValue()=="Негатив отсутствует" && activeSheet.getName()=="Разметка ТОП100 по суду"){
const value = activeSheet.getRange(ar.getRow(), 1).getValue();
const data = pasteSheet.getRange('B1:B'+pasteSheet.getLastRow()).getValues().flat();
const indx = data.findIndex((element) => element == value);
if (indx>-1){
const pasteRng = pasteSheet.getRange(indx+1,2);
pasteRng.clearContent();
pasteRng.setValue('Нерелевант');
}
}
}
Let me know if that worked for you, otherwise I would like to modify it so it does.
Thank you very much! The script works =)
I also made a working script before. But this is my first script, so it is much slower and not so ... concise. Also it was fired with a trigger, and yours works as a simple event.
My old version:
function ChangeTone(event) {
if (event.source.getActiveRange().getValue()=="Негатив отсутствует" && event.source.getActiveSheet().getName() == "Разметка ТОП100 СУД"){
var sheet = SpreadsheetApp.getActiveSheet();
var currRow = sheet.getActiveCell().getRow();
sheet.getRange("A"+currRow+":F"+currRow).setBackground('#ff5a5a');
var value = sheet.getRange(currRow, 1).getDisplayValue();
var pasteSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Тональность");
var data = pasteSheet.getDataRange().getValues();
for(var i = 1; i<data.length;i++){
if(data[i][0] == value){
pasteSheet.getRange((i+1), 2).setValue('Нерелевант');
sheet.getRange("C"+currRow+":F"+currRow).deleteCells(SpreadsheetApp.Dimension.ROWS);
}
};
sheet.getRange("A"+currRow+":B"+currRow).setBackground('#ffffff');
}
}
So took your code and added row deletion after replacing cell value. Final version:
function onEdit(e){
const ss = e.source;
const ar = e.range;
const arRow = ar.getRow();
const activeSheet = ss.getActiveSheet();
const pasteSheet = ss.getSheetByName("Тональность");
if (ar.getValue()=="Негатив отсутствует" && activeSheet.getName()=="Разметка ТОП100 СУД"){
const value = activeSheet.getRange(arRow, 1).getValue();
const data = pasteSheet.getRange('A1:A'+pasteSheet.getLastRow()).getValues().flat();
const indx = data.findIndex((element) => element == value);
if (indx>-1){
const pasteRng = pasteSheet.getRange(indx+1,2);
pasteRng.clearContent();
pasteRng.setValue('Нерелевант');
activeSheet.getRange("C"+arRow+":F"+arRow).deleteCells(SpreadsheetApp.Dimension.ROWS);
}
}
}
Thanks again for your help =)
I'm doing a data transfer of several spreadsheets to a single one, what I do is transfer the last data of certain columns to the master spreadsheet and also insert them in the last available row of certain columns, for now, I insert all the data but I would like to to know how I can have it examine the master spreadsheet so that if those data already exist, it does not delete them but update them. The script that I have is the following ...
function Gas10(){
var ss1 = SpreadsheetApp.openById("ID");
var ssh1 = ss1.getSheetByName("Sheet 1");
var lastRow1 = ssh1.getLastRow();
var gtRange1 = ssh1.getRange("C"+(lastRow1)+":K"+(lastRow1)).getValues();
var gtRange2= ssh1.getRange("A" + (lastRow1)).getValue();
var ss2 = SpreadsheetApp.getActiveSpreadsheet();
var ssh2 = ss.getSheetByName("Sheet 2");
var lastRow2 = ssh2.getLastRow() + 1;
var setRange1 = ssh2.getRange(lastRow2, 4, gtRange1.length, gtRange1[0].length).setValues(gtRange1);
var setRange2 = ssh2.getRange(lastRow2, 3).setValue(gtRange2);
}
I need to know how I can do it when I insert a piece of information (I already do that), but update it if it already exists. This is the example that I created so that it can be better understood, in this example I have two sheets of which from sheet 1 I pass data to sheet 2 and what I'm looking for is that sheet 2 updates all the data that are equal to (Name, Num, Proyect). I hope that now I understand better what I'm looking for.
Basically what you have to do is
get the new Line you want to add to the destination spreadsheet
get all the required datas of the destination spreadsheet
Check if the new Line datas have the same datas than in the destination data array
If so change ID value
paste changed datas in the destination spreadsheet
based on this spreadsheet The code should look something like this
function Gas10(){
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var ssh1 = ss1.getSheetByName("Sheet 1");
var ssh2 = ss1.getSheetByName("Sheet 2");
var lastRow1 = ssh1.getLastRow();
var lastCol1 = ssh1.getLastColumn();
var newLine = ssh1.getRange(lastRow1, 2, 1, lastCol1 - 1 ).getValues();
var destDatas = ssh2.getDataRange().getValues();
for (var i = 1; i < destDatas.length; i++)
{
if (newLine[0][0] == destDatas[i][0]
&& newLine[0][1] == destDatas[i][1]
&& newLine[0][2] == destDatas[i][2])
{
destDatas[i][3] = newLine[0][3];
}
}
// add newLine to destDatas
destDatas.splice(destDatas.length, 0, newLine[0]);
var lastColumn = ssh2.getLastColumn();
var lastRow2 = ssh2.getLastRow() + 1;
ssh2.getRange(1, 1, destDatas.length, lastColumn).setValues(destDatas);
ssh1.deleteRow(lastRow1);
}
Here's an example I played around with:
It looks at the slave sheet for any data. When it finds data it puts the row and col and value into an obj which is then added to an array. When it finishes it calls the updMaster which then looks for data in those same cells (assuming that the cells are in the same place if those cells are blank then it adds data and I also changed the background to lightblue to show me where it updated the cells.
You could run the getSlaveData() for different sheets if you wish.
function getSlaveData(){
var ss=SpreadsheetApp.getActive();
var ssh=ss.getSheetByName('Sheet2');
var sA=[];
var srg=ssh.getDataRange();
var svA=srg.getValues();
for(var i=0;i<svA.length;i++){
for(var j=0;j<svA[i].length;j++){
//if(svA[i][j]){
if(!ssh.getRange(i+1,j+1).isBlank()){//optional way to look for values
var sObj={};
sObj['row']=i + 1;
sObj['col']=j + 1;
sObj['value']=svA[i][j];
sA.push(sObj);
}
}
}
updMaster(sA);
}
function updMaster(sA){
var ss=SpreadsheetApp.getActive();
var msh=ss.getSheetByName('Sheet1');
for(var i=0;i<sA.length;i++){
if(msh.getRange(sA[i].row,sA[i].col).isBlank()){
msh.getRange(sA[i].row,sA[i].col).setValue(sA[i].value);
msh.getRange(sA[i].row,sA[i].col).setBackground('lightblue');
}
}
}
I am completely new in writing scripts for google sheets, so I was hoping some of you could help/guide me a little bit.
So Ideally, I want a script to clear (not remove) ALL filters in my sheet. This is, however, complicated for me to do (If some of you have such a script, I would LOVE to see it :) )
Instead, I made this one (Used recorder):
function Clear_Filter() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A5').activate();
spreadsheet.getActiveSheet().getFilter().removeColumnFilterCriteria(1);
spreadsheet.getRange('B5').activate();
spreadsheet.getActiveSheet().getFilter().removeColumnFilterCriteria(2);
spreadsheet.getRange('C5').activate();
spreadsheet.getActiveSheet().getFilter().removeColumnFilterCriteria(3);
spreadsheet.getRange('G5').activate();
spreadsheet.getActiveSheet().getFilter().removeColumnFilterCriteria(7);
spreadsheet.getRange('J5').activate();
spreadsheet.getActiveSheet().getFilter().removeColumnFilterCriteria(10);
spreadsheet.getRange('M5').activate();
spreadsheet.getActiveSheet().getFilter().removeColumnFilterCriteria(13);
};
So my filter is set in Row 5. First I made the above for all columns (I had 20), but the problem is, that the code is very slow :( So now I am using the columns, that I use the most, when filtering, but the code is still slow. Well the worst thing is, that the code is running one column at a time (which we see in the code), and when the code is finish, I end up in the last column.
Can I do something? I dont want my sheet window keep turning right, when I run the code, and then end up in column M.
I will appreciate any help!
Thanks
Here is mine. The function does not remove filters. Instead, it clears them as requested.
function clearFilter(sheet) {
sheet = SpreadsheetApp.getActiveSheet(); //for testing purpose only
var filter = sheet.getFilter();
if (filter !== null) { // tests if there is a filter applied
var range = filter.getRange(); // prevents exception in case the filter is not applied to all columns
var firstColumn = range.getColumn();
var lastColumn = range.getLastColumn();
for (var i = firstColumn; i < lastColumn; i++) {
filter.removeColumnFilterCriteria(i);
}
Logger.log('All filters cleared')
}
else {Logger.log('There is no filter')}
}
Reset filters criterea + sort by first column (as default state).
And add this action to main menu.
/** #OnlyCurrentDoc */
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [
{name: "Reset filters", functionName: "ResetFilters"},
];
ss.addMenu("Custom actions", menuEntries); // add to main menu
}
function ResetFilters() {
var spreadsheet = SpreadsheetApp.getActive();
var lastColumn = spreadsheet.getActiveSheet().getLastColumn();
var filter = spreadsheet.getActiveSheet().getFilter();
var criteria = SpreadsheetApp.newFilterCriteria().build();
for (var i = 1; i <= lastColumn; i++) {
filter.setColumnFilterCriteria(i, criteria);
}
filter.sort(1, true); // remove this line for disable setting of sorting order
};
To clear all
`function turnOffFilter(sheet) {
for (var index = 1; index < sheet.getLastColumn(); index++) {
if (sheet.getFilter().getColumnFilterCriteria(index)) {
sheet.getFilter().removeColumnFilterCriteria(index);
}
}
}`
It seems that the answers (e.g. proposed by Birmin) work fine but the script is painfully slow. I find it much faster to reapply the filter:
function clearFilter(sheet) {
sheet = SpreadsheetApp.getActiveSheet(); //for testing purpose only
var filter = sheet.getFilter();
if (filter !== null) { // tests if there is a filter applied
var range = filter.getRange();
filter.remove();
range.createFilter();
Logger.log('All filters cleared')
}
else {Logger.log('There is no filter')}
}
I, have you tried :
function Clear_Filter() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getFilter().remove();
}
I have a spreadsheet that has a checklist that's to be filled out 60, 30, and 1 day before an event. The sheets are called "60-Day","30-Day", and "Kickoff." I'm trying to get rows that haven't been checked off to be automatically added to the next sheet (so any unchecked rows on "60-day" get appended to "30-day", and from "30-day" to "kickoff"--also, by "checked off" I mean that an "x" is entered into a cell). I've got a pretty good start on the code, but I must be doing something wrong - cause it doesn't seem to do anything (forgive my javascript ignorance, my foray into coding started last week with codecademy and a whole lot of browsing on these forums). I feel like there are some pretty basic things that I'm probably missing and would welcome whatever help I can get. Here's what I've got...
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var r = ss.getActiveCell();
var i = 4;//have this number be your first row of data
if(r.getColumn()===5){ // this indicates the column that, if left blank, will mean the row should be copied to the next sheet
if (ss.getActiveSheet().getName()=="60-Day"){
var source_sheet = ss.getSheetByName("60-Day");
var target_sheet = ss.getSheetByName("30-Day");
var last_row = target_sheet.getLastRow();
while(i<=last_row){
if(source_sheet.getValue("E"+i)!="x"){
var source_range = source_sheet.getRange(i,2,1,6); // indicate the columns you'd like to copy
var target_range = target_sheet.getRange(last_row + 1,2,1,6); // indicate the columns where you'd like to paste
source_range.copyTo(target_range);
i++;
SpreadsheetApp.flush();
}else{
i++;
}
}
};
else if (ss.getActiveSheet().getName()=="30-Day"){
var source_sheet = ss.getSheetByName("30-Day");
var target_sheet = ss.getSheetByName("Kickoff");
var last_row = target_sheet.getLastRow();
while(i<=last_row){
if(ss.getValue("E"+i)!="x"){
var source_range = source_sheet.getRange(i,2,1,6);//indicate the columns you'd like to copy
var target_range = target_sheet.getRange(last_row + 1,2,1,6);//indicate the columns where you'd like to paste
source_range.copyTo(target_range);
i++;
SpreadsheetApp.flush();
}else{
i++;
}
};
}
}
}
So that's that -- here's where I run into more trouble though. If a row has been pushed to the target sheet and gets checked off on the target sheet, I'd like it to disappear from the target sheet AND I'd like the the original row in the source sheet to now show that it has been checked off. Also, if a previously blank row gets checked off on the source sheet, I'd like the copy that had been pushed to the target sheet to disappear. This is where I start to get pretty lost. How would I go about implementing that?
Think you'll want the changes in this...
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var r = ss.getActiveCell();
var i = 4;//have this number be your first row of data
if(r.getColumn()===5){ // this indicates the column that, if left blank, will mean the row should be copied to the next sheet
if (ss.getActiveSheet().getName()=="60-Day"){
var source_sheet = ss.getSheetByName("60-Day");
var target_sheet = ss.getSheetByName("30-Day");
var source_last_row = source_sheet.getLastRow();
var target_last_row = target_sheet.getLastRow() + 1;
while(i<=source_last_row){
if(source_sheet.getRange("E"+i).getValue() !="x"){
var source_range = source_sheet.getRange(i,2,1,6); // indicate the columns you'd like to copy
var target_range = target_sheet.getRange(target_last_row,2,1,6); // indicate the columns where you'd like to paste
source_range.copyTo(target_range);
//var new_last_row = target_last_row - 1;
source_sheet.deleteRow(i); // delete source row after copy
i++;
SpreadsheetApp.flush();
target_sheet.getRange('E'+target_last_row).setValue('x'); // insert 'x' back into target
}else{
i++;
}
}
}
else if (ss.getActiveSheet().getName()=="30-Day"){
var source_sheet = ss.getSheetByName("30-Day");
var target_sheet = ss.getSheetByName("Kickoff");
var source_last_row = source_sheet.getLastRow();
var target_last_row = target_sheet.getLastRow() + 1;
while(i<=source_last_row){
if(source_sheet.getRange("E"+i).getValue() !="x"){
var source_range = source_sheet.getRange(i,2,1,6);//indicate the columns you'd like to copy
var target_range = target_sheet.getRange(target_last_row,2,1,6);//indicate the columns where you'd like to paste
source_range.copyTo(target_range);
//var new_last_row = target_last_row - 1;
source_sheet.deleteRow(i); // delete source row after copy
i++;
SpreadsheetApp.flush();
target_sheet.getRange('E'+target_last_row).setValue('x'); // insert 'x' back into target
}else{
i++;
}
}
}
}
}