Script deleting all formulas in the Google Sheet, how to fix? - javascript

I have sheet A and B, data from sheet A which matching my criteria I am duplicating on sheet B by using formulas. Since some data not matching my criteria I am getting an empty row.
**PROBLEM STATEMENT **
I have a script which I am planning to use to delete empty rows on the sheet. But I have been notice that its deleting all formulas same time and all formatting.
I need to delete the rows only between the non empty ones. For example row 1,2 have data, row 5 have data, so, only row 3-4 need to be removed, this process should be automatic.
CODE
function deleteEmptyRows(){
var sh = SpreadsheetApp.getActiveSheet();
var data = sh.getDataRange().getValues();
var targetData = new Array();
for(n=0;n<data.length;++n){
if(data[n].join().replace(/,/g,'')!=''){ targetData.push(data[n])};
Logger.log(data[n].join().replace(/,/g,''))
}
sh.getDataRange().clear();
sh.getRange(1,1,targetData.length,targetData[0].length).setValues(targetData);
}

I see no sample of your data and have no idea how your sheet looks like, so here is just another guess:
function deleteEmptyRows() {
const sh = SpreadsheetApp.getActiveSheet();
const data = sh.getDataRange().getValues();
const empty_rows = [];
for (let i in data) if (data[i].join('') == '') empty_rows.push(+i+1);
empty_rows.reverse().forEach(x => sh.deleteRow(x));
}
Update
The variant of the function that finds for the last row contains visible data and removes all empty (with no visible data) rows above:
function delete_all_empty_rows_above_the_last_filled_row() {
const sh = SpreadsheetApp.getActiveSheet();
const data_all = sh.getDataRange().getValues();
for (var last_row = data_all.length-1; last_row>0; last_row--) {
if (data_all[last_row].join('') != '') break;
}
const data = sh.getRange(1,1,last_row+1,3).getValues();
const empty_rows = [];
for (let i in data) if (data[i].join('') == '') empty_rows.push(+i+1);
empty_rows.reverse().forEach(x => sh.deleteRow(x));
}
Update 2
To make the function to file every time as there were changes on the sheet "IF Copy" within the column "A" you need to add something like this:
function onEdit(e) {
if (e.range.getSheet().getName() != "IF Copy") return;
if (e.range.columnStart == 1)
delete_all_empty_rows_above_the_last_filled_row();
}
But onEdit() trigger works only when you edit sheet manually. If a sheet changes via some formula or another function the trigger doesn't work.

Related

How to delete the empty cells in a specific column using apps script?

The goal is to delete empty cells in Column N alone, without disturbing the other columns and shift the rest of the cells upwards to obtain a compact column with just non empty cells. There can and will be empty cells after the result of course.
Please suggest a method
function Defaulters() {
var spreadsheet = SpreadsheetApp.getActive();
var as = spreadsheet.getActiveSheet();
//to get the last row of the Column
var lastRow = 100;
var range = as.getRange("N" + lastRow);
if (range.getValue() !== "")
{Logger.log(lastRow);}
{lastRow = range.getNextDataCell(SpreadsheetApp.Direction.UP).getRow();}
Logger.log(lastRow);
//to delete the empty cells and give a compact output of just names and emails in the Column
for (var l=lastRow; l>=3; l--)
{if(as.getRange(l,14).getValue() == "")
Logger.log(true); **//what to put here to delete this cell?**
else
Logger.log(false);**// what to put here to retain this cell?**
}
}
I'd try something like this:
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues(); // get all data
const data_new = data.filter(row => row[13] != ''); // filter the data by column 'N'
sheet.clearContents(); // clean the sheet
sheet.getRange(1,1,data_new.length,data_new[0].length)
.setValues(data_new); // put the new data back on the sheet
}
Or even like this:
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues().filter(row => row[13] != '');
sheet.clearContents().getRange(1,1,data.length,data[0].length).setValues(data);
}
If you need to keep all the table intact and remove empty cells only from column 'N' it can be done this way:
function clean_column_N() {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange('N3:N'+sheet.getLastRow()) // get a range start from row 3
const data = range.getValues().filter(String); // get a data and remove empty elements
range.clearContent().offset(0,0,data.length).setValues(data); // put the data back on the sheeet
}
All data in column 'N' will be moved upward.
Update
Modified last variant to clean any column:
function main() {
clean_column('N');
clean_column('O');
}
function clean_column(col) {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange(col + '3:' + col + sheet.getLastRow());
const data = range.getValues().filter(String);
range.clearContent().offset(0,0,data.length).setValues(data);
}

Google Apps Script Copying a column in one sheet, transposing it, then pasting to another

I have a sheet that is set up in the template of a form, with data prompts like Name, ID#, etc. in column A and the actual data that is inputted in column B. I have created a button labeled 'Submit Form' that is linked to the script. What I want this script to achieve is to copy only the data from a specific range in column B, then paste that data into the next empty row in a new sheet to create a sort of database of the form responses. It will also clear the data from the range in column B on the original sheet.
I already have a way to clear the selected range on the original sheet, as well as a way to copy the selected range to the new sheet while automatically starting from the first empty row. I am having trouble transposing the data, however, since it pastes into a column like the original data, as opposed to pasting into a row.
function submitForm() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("RMA");
var sheet2 = ss.getSheetByName('RMA Database');
var values = sheet2.getRange("A:A").getValues();
var maxIndex = values.reduce(function(maxIndex, row, index) {
return row[0] === "" ? maxIndex : index;
}, 0);
sheet2.setActiveRange(sheet2.getRange(maxIndex + 2, 1))
sheet1.getRange("B5:B25").copyTo(sheet2.getRange(sheet2.getLastRow()+1,1),
{contentsOnly:true});
sheet1.getRange('B5:B25').clearContent();
}
Try this:
I don't see the point of this line var values = sheet2.getRange("A:A").getValues(); so I just omitted it
function runOne() {
var ss = SpreadsheetApp.getActive();
var sheet1 = ss.getSheetByName("RMA");
var sheet2 = ss.getSheetByName('RMA Database');
var vA=sheet1.getRange("B5:B25").getValues().map(function(r){return r[0]});
sheet2.appendRow(vA);
sheet1.getRange('B5:B25').clearContent();
}

If check box in sheet 1 is true, delete the row with same values in sheet 2 Google spreadsheet

A sheet called 'Report' uses a query to import data from multiple sheets. All sheets but one get data from other files.
There is a sheet called 'SavedDB' to which I can save rows that I want to keep in case they are eliminated from their original source. I got this to work with the help of other posts.
I created two buttons, save and delete, and every row has a checkbox associated with each button.
This is what it looks like
Whenever the user clicks the button Save in the sheet 'Report', the script copies all the rows that are checked TRUE to the sheet SavedDB, it will then be imported by a query in 'Formatted Saved' which in turn is imported by a query in 'Report'
Now I'm trying to implement the reverse process. When the user clicks Delete all the rows in which the column delete is checked should be removed from 'SavedDB'.
The deleted row has to be an exact match in every column except the first 6, which are not exported to 'SavedDB' in the first place.
This is what I have so far:
function deleteRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Report'); //source sheet
var testrange = sheet.getRange('D:D'); //range to check
var testvalue = (testrange.getValues());
var csh = ss.getSheetByName('SavedDB'); //destination sheet
var data = [];
var dataNew =[];
//Condition check in D:D; If true copy the same row to data array
for (i=0; i<testvalue.length;i++) {
if ( testvalue[i] == 'true') {
data.push.apply(data,sheet.getRange(i+1,7,1,25).getValues());
}
}
//####THIS IS WHERE I AM STUCK###
//GET ALL NON-EMPTY ROWS ON 'SavedDB IN THE ARRAY dataNew
//COMPARE BOTH ARRAYS data AND dataNew
// ADD ALL THE UNIQUE ROWS, AND IF A ROW IS REPEATED DISCARD IT ALTOGETHER
//SAVE NEW VALUES TO 'savedDB'
//######
//changes the check boxes back to false(unchecked)
var resetRange = sheet.getRange('E3:E');
var values = resetRange.getValues();
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
if (values[i][j] == true) {
values[i][j] = false; // Modified
}
}
}
resetRange.setValues(values);
}
Thanks folks!
I'm not sure what else you want but this might be a better start.
function deleteRows() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Report');
var rg=sh.getRange(1,4,sh.getLastRow(),1);
var vA=rg.getValues();
var dsh=ss.getSheetByName('SavedDB');
var data = [];
for (i=0; i<vA.length;i++) {
if (vA[i][0]=='TRUE') {
data.push(sh.getRange(i+1,7,1,25).getValues()[0]);
}
}
}

Google Apps Script - copyrange based on for loop matching

https://docs.google.com/spreadsheets/d/1wAxZROq-HqGSZIeBnOShiLP1x-maCpVhvfr6MKixVZE/edit#gid=1767460404
I am attempting to grab the data in a data range on a data sheet, then loop over that data, match the row values in Column C to the row values in a different (tracker) sheet also located in Column C, and for the matched data, copy the whole row in data sheet to the bottom of the data sheet.
All of this is supposed to be triggered when I enter "Open" in a set field in the status tracker.
What I have done so far (hopefully) is to locate the values to match in the data sheet but I am unsure as to how to use the .copyto function correctly now such that it copys the data to the end of the loop. My code so far: (without .copy.
function grabmyRequestID(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
var ss2 = ss.getSheetByName("Status Tracker")
var searchforrange = ss2.getRange("C:C")
var searchfor = searchforrange.getValues()
Logger.log("Request ID: " +searchfor)
return searchfor
}
function findDuplicates(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
var ss2 = ss.getSheetByName("Status Tracker")
var ss3= ss.getSheetByName("All Output")
var sheetNametoWatch = "Status Tracker"
var columntoWatch = 4
var valuetoWatch = "Open"
var searchfor = grabmyRequestID()
if (sheet.getName() == sheetNametoWatch && range.getColumn()
== columntoWatch && range.getValue() == valuetoWatch){
var data = ss3.getRange("C:C").getValues()
for (i=0; i<data.length; i++){
if (data[i] == searchfor && searchfor !=""){
Logger.log('found it')
}
}
}
}
As you can see, I am running two functions, grabmyRequestID, which grabs the id from the tracking sheet and findduplicates, which matches it with the ids from the data sheet.
I now just want it to copy the whole row where it found the matched column and copy that row to the end of the data sheet. I have tried a few ways but I never actually get any output. I am pretty new to this so I hope somebody can help me out.
I am also not sure entirely sure if my trigger works for this loop.
Any help would be appreciated.

Paste values from one Google Sheet to another and remove duplicates based on ID column

I have a similar situation to the one described on this question: two worksheets, with input data coming into the Feed sheet using the importxml function and a Data sheet where new rows get copied thanks to a script set to run daily.
However, the current script is creating daily duplicates. As such, I would like to adapt the answer provided on the question above so that the script checks the IDs on column F and only copies the rows with new IDs.
How should I update the section below that creates a hash to one that looks for the IDs on column F instead? Also my rows are consistent, so is it correct to assume I can just remove the relevant code lines towards the end?
The sample Google Sheet is available here.
function appendUniqueRows() {
var ss = SpreadsheetApp.getActive();
var sourceSheet = ss.getSheetByName('Get Data');
var destSheet = ss.getSheetByName('Final Data');
var sourceData = sourceSheet.getDataRange().getValues();
var destData = destSheet.getDataRange().getValues();
// Check whether destination sheet is empty
if (destData.length === 1 && "" === destData[0].join('')) {
// Empty, so ignore the phantom row
destData = [];
}
// Generate hash for comparisons
var destHash = {};
destData.forEach(function(row) {
destHash[row.join('')] = true; // could be anything
});
// Concatentate source rows to dest rows if they satisfy a uniqueness filter
var mergedData = destData.concat(sourceData.filter(function (row) {
var hashedRow = row.join('');
if (!destHash.hasOwnProperty(hashedRow)) {
// This row is unique
destHash[hashedRow] = true; // Add to hash for future comparisons
return true; // filter -> true
}
return false; // not unique, filter -> false
}));
// Check whether two data sets were the same width
var sourceWidth = (sourceData.length > 0) ? sourceData[0].length : 0;
var destWidth = (destData.length > 0) ? destData[0].length : 0;
if (sourceWidth !== destWidth) {
// Pad out all columns for the new row
var mergedWidth = Math.max(sourceWidth,destWidth);
for (var row=0; row<mergedData.length; row++) {
for (var col=mergedData[row].length; col<mergedWidth; col++)
mergedData[row].push('');
}
}
// Write merged data to destination sheet
destSheet.getRange(1, 1, mergedData.length, mergedData[0].length)
.setValues(mergedData);
}
I'm a novice in this world of Google Apps scripts, so do please let me know if I'm missing any crucial information. Thanks in advance for the help.
You want to copy the values from "Feed" sheet to "Data" sheet.
When the values are copied, you want to copy only new values which are not included in "Data" sheet.
You want to choose the new values using the values of column "F".
If my understanding for your question is correct, how about this modification? In this modification, I modified the script in your shared spreadsheet.
Modification points:
In your script, all values of "Feed" sheet are copied to "Data" sheet. So in order to choose only new values, I used the following flow.
Retrieve the values from column "F". This is used for choosing the new values.
Retrieve the new values using the values from column "F".
Put the new values to "Data" sheet.
The script which reflected above flow is as follows.
Modified script:
From:
This is your script in the shared spreadsheet. Please modify this script to below one.
function Copy() {
var sss = SpreadsheetApp.openById('#####'); // this is your Spreadsheet key
var ss = sss.getSheetByName('Feed'); // this is the name of your source Sheet tab
var range = ss.getRange('A3:H52'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.openById('#####'); //replace with destination ID
var ts = tss.getSheetByName('Data'); //replace with destination Sheet tab name
ts.getRange(ts.getLastRow()+1, 1,50,8).setValues(data);// 49 value refers to number of rows, 8 to columns
}
To:
function Copy() {
var sss = SpreadsheetApp.openById('#####'); // this is your Spreadsheet key
var ss = sss.getSheetByName('Feed'); // this is the name of your source Sheet tab
var range = ss.getRange('A3:H52'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.openById('#####'); //replace with destination ID
var ts = tss.getSheetByName('Data'); //replace with destination Sheet tab name
// Below script was added.
var values = ts.getRange("F3:F").getValues().filter(String);
var copiedValues = data.filter(function(e) {return !values.some(function(f){return f[0] == e[5]}) && e.filter(String).length > 0});
ts.getRange(ts.getLastRow() + 1, 1, copiedValues.length, copiedValues[0].length).setValues(copiedValues);
}

Categories

Resources