I have a spreadsheet that is receiving Google Form responses. I'd like to run something on formSubmit() that combs through the entire form response sheet, and clears any cells that have certain values in the text string.
The code I have so far is below. It run, but doesn't clear the cells out.
function badData() {
var file = SpreadsheetApp.openById("[spreadsheetstring]");
var content = file.getSheetByName("Form Responses 1");
return content.value ? (listBadWords(content.value) !== -1 ? content.range.clearContent() : null) : null;
}
function listBadWords(word) {
var listEN = [
'none', 'n/a', 'n.a'
];
return listEN.indexOf(word);
}
Any help/advice you all could provide would be greatly appreciated.
Thanks!
Update:
With #Liora's help, the following works great:
function badMMData() {
var file = SpreadsheetApp.openById("[spreadsheetstring]");
var content = file.getSheetByName("Form Responses 1");
var numRows = content.getLastRow();
var numCols = content.getLastColumn();
var range = content.getRange(1, 1, numRows, numCols);
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
var currentValue = range.getCell(i, j).getValue().toString().toLowerCase();
if (listBadWords(currentValue) !== -1)
range.getCell(i, j).clear();
}
}
}
function listBadWords(word) {
var listEN = [
'none', 'n/a', 'n.a', 'na'
];
return listEN.indexOf(word);
}
The function clear works on a precise range, so you need to loop on all the ranges of the spreadsheet. Something like:
var numRows = content.getLastRow();
var numCols = content.getLastColumns();
var range = content.getRange(1, 1, numRows, numCols);
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
var currentValue = range.getCell(i,j).getValue();
if(listBadWords(currentValue) !== -1)
range.getCell(i,j).clear();
}
}
Related
dears
I need your support to edit this function as I need to copy data with formatting
This is the equation I working on
function copyRows()
{
var copySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet1');
var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet2');
var dataRange = dataSheet.getDataRange();
var dataValues = dataRange.getValues();
for(var i = 1; i < dataValues.length; i++)
{
if(dataValues[i][29] === 'done')
{
copySheet.appendRow([dataValues[i][0],
dataValues[i][1],
dataValues[i][2],
dataValues[i][3],
dataValues[i][4]]);
}
}
for(var i = 1; i < dataValues.length; i++)
{
if(dataValues[i][29] === 'done')
{
var clearRow = i+1;
dataSheet.getRange('A' + clearRow + ':AC' + clearRow).clear();
}
I got the following script from #Mike Grace's website:
// Deletes rows in the active spreadsheet that contain 'Yes' in column A
function readRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if (row[0] == 'Yes') {
sheet.deleteRow((parseInt(i)+1) - rowsDeleted);
rowsDeleted++;
}
}
}
The script works well, but I would like to make a change to it, instead of calling .deleteRow() I want to use .hideRow() instead.
Because the .hideRow() method only accepts a range as far as I understand, I'm getting the following error:
How do I modify this script so that it hides the row instead of deleting them?
there are different hideRow / s () methods, one of them takes a row number as argument.
your code can be simplified like this :
function hideRowsWithYes() {
var sheet = SpreadsheetApp.getActiveSheet();
var values = sheet.getDataRange().getValues();
for (var i = 0; i < values.length; i++) {
if (values[i][0] == 'Yes') {
sheet.hideRows(1+i);
}
}
}
As usual, autocomplete makes the job easier...
Edit following comment :
to unhide row we don't have a simple method with row index so we need to define the range... code goes like this (i has a +1 because values is an array that starts from 0 while sheets are indexed from 1)
function unHideRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var values = sheet.getDataRange().getValues();
var row;
var maxCol = sheet.getMaxColumns();
for (var i = 0; i < values.length; i++) {
if (values[i][0] == 'Yes') {
row = sheet.getRange(1+i, 1, 1, maxCol);
sheet.unhideRow(row);
}
}
}
I have a tremendous volume of sparse matrix data, where i want to programmatically set as active cell wherever there is (0) when I run the below snippet (function).
Which would ease me for manipulation of code labels
The data is purely random. The process has to begin from the current active cell and it has to loop again from beginning if end of the data is found.
I get unexpected results,
function getzero() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var Values = range.getValues();
for (var i = 0; i < Values.length; i++) {
for (var j = 0; j < Values[i].length; j++) {
if (Values[i][j] == 0) {
sheet.setActiveSelection(sheet.getRange(i + 1, j + 1));
break;
}
}
}
}
This should take care of finding all the zeros. Also added a menu for you to run the command from the sheets directly. Just paste code in the script editor and reload the sheet.
// This function addes a menu Zero and submenu getzero to access your function directly from spreadsheet
function onOpen(){
var ss = SpreadsheetApp.getActive()
var menu = [{name:"Find Zero",functionName: "getzero"}]
ss.addMenu("Zeroes", menu)
}
function getzero() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var Values = range.getValues();
var selectedRange = sheet.getActiveRange()
// find active cells row and column
var startRow = selectedRange.getRow() -1
var startCol = selectedRange.getColumn()
var notFoundZero = true
//Use the active cells row and column to start the loop
for (var i = startRow; i < Values.length; i++) {
if (i == startRow){
var j = startCol
}
else {
j =0
}
for (j ; j < Values[i].length; j++) {
// Using "===" makes sure the type is also match else blank is considered as zero too.
if (Values[i][j] === 0) {
Logger.log("Values Row X Col:" + i + " X " + j)
//The below line works as well as sheet.setActiveSelection
sheet.getRange(i + 1, j + 1).activate()
//Below code escapes the outer loop
i = Values.length;
// this boolean is used to runs or stops the next loop
notFoundZero = false;
// breaks inner loop
break;
}
}
}
if(notFoundZero){
for (var i = 0; i <= startRow; i++) {
if (i == startRow){
var runTill = startCol
}
else {
runTill = Values[i].length
}
for (var j=0 ; j < runTill; j++) {
if (Values[i][j] === 0) {
sheet.getRange(i + 1, j + 1).activate()
// same as above
i = Values.length;
//Used to alert if no more zeros found
notFoundZero = false;
break;
}
}
}
}
if(notFoundZero)
{
var ui = SpreadsheetApp.getUi()
ui.alert("No More zero Found")
}
}
This will check cell values after selection if no zeroes are found it will check above the selection. But after that it will stop at the selection and alert no zeroes found, this prevents a runaway loop.
Give it a go and let me know how it goes.
Edit: Below Code for searching in reverse
Below Code Has not been Tested, Might have errors. This was not the primary Question, hence did not check for errors.
function getzeroRev() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var Values = range.getValues();
var selectedRange = sheet.getActiveRange()
// find active cells row and column
var startRow = selectedRange.getRow() -1
var startCol = selectedRange.getColumn()
var notFoundZero = true
//Use the active cells row and column to start the loop
for (var i = startRow; i >=0; i--) {
if (i == startRow){
var j = startCol
}
else {
j =values[i].length
}
for (j ; j >=0; j--) {
// Using "===" makes sure the type is also match else blank is considered as zero too.
if (Values[i][j] === 0) {
Logger.log("Values Row X Col:" + i + " X " + j)
//The below line works as well as sheet.setActiveSelection
sheet.getRange(i + 1, j + 1).activate()
//Below code escapes the outer loop
i = Values.length;
// this boolean is used to runs or stops the next loop
notFoundZero = false;
// breaks inner loop
break;
}
}
}
if(notFoundZero){
for (var i = values.length; i >= startRow; i--) {
if (i == startRow){
var runTill = startCol
}
else {
runTill = 0
}
for (var j=0 ; j >= runTill; j--) {
if (Values[i][j] === 0) {
sheet.getRange(i + 1, j + 1).activate()
// same as above
i = Values.length;
//Used to alert if no more zeros found
notFoundZero = false;
break;
}
}
}
}
if(notFoundZero)
{
var ui = SpreadsheetApp.getUi()
ui.alert("No More zero Found")
}
}
I'm working with a set-list for a cover band in which I have listed all of our songs by decade on separate sheets, including a full set list on its own sheet. When we work on new songs, I color those cells green. I would like to see those same songs highlighted green wherever they may appear on the other sheets whenever I change color (onEdit, that is).
Here's what I've got so far pieced together from other sources:
function replace() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activecell = ss.getActiveSheet().getActiveCell().getA1Notation();
var activecellvalue = ss.getActiveSheet().getActiveCell().getValue();
var activecellcolor = ss.getActiveSheet().getActiveCell().getBackground();
var allsheets = ss.getSheets();
var s = 0;
var cells = [];
if (activecellvalue != 'Yes'|'No' && activecellcolor == '#00ff00'){
for (var s=0; s < allsheets.length; s++) {
var allcells = allsheets[s].getDataRange().getValues();
for (var i=0; i < allcells.length; i++) {
for (var j=0; j < allcells[i].length; j++) {
if (allcells[i][j].toString().match(activecellvalue) == activecellvalue) {
var newcells = allsheets[s].getRange(i+1,j+1).getA1Notation();
cells.push(newcells);}
}
}
allsheets[s].getRange(newcells).setBackground('#00ff00');
// cells.push(newcells);
Logger.log(newcells);
Logger.log(allsheets);
Logger.log(cells)
}
}
}
The "Yes" and "No" refer to cells containing messages in the negative or affirmative as to whether or not we have finished a song.
I have been able to get the script to color the same text in different cells in different sheets, but something still needs to be fixed which is allowing the same cell values in EVERY sheet to be highlighted, as well.
Thank you in advance for your help!
EDIT:
I have a working (albeit, seemingly inefficient) code that will seek out the text of an active cell elsewhere and change its cell color:
function colorchange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activecell = ss.getActiveSheet().getActiveCell().getA1Notation();
var activecellvalue = ss.getActiveSheet().getActiveCell().getValue();
var activecellcolor = ss.getActiveSheet().getActiveCell().getBackground();
var allsheets = ss.getSheets();
var s = 0;
var name = allsheets[s].getName();
if (activecellvalue != 'Yes'|'No' && activecellcolor == '#00ff00'){
for (var s=0; s < allsheets.length; s++) {
var cells = allsheets[s].getDataRange().getValues();
for (var i=0; i < cells.length; i++) {
for (var j=0; j < cells[i].length; j++) {
if (cells[i][j].toString().match(activecellvalue) == activecellvalue) {
var check = cells[i][j]
var newcells = allsheets[s].getRange(i+1,j+1).getA1Notation();
allsheets[s].getRange(newcells).setBackground('#00ff00');
}
}
}
}
}
else if (activecellvalue != 'Yes'|'No' && activecellcolor == '#ffffff'){
for (var s=0; s < allsheets.length; s++) {
var cells = allsheets[s].getDataRange().getValues();
for (var i=0; i < cells.length; i++) {
for (var j=0; j < cells[i].length; j++) {
if (cells[i][j].toString().match(activecellvalue) == activecellvalue) {
var check = cells[i][j]
var newcells = allsheets[s].getRange(i+1,j+1).getA1Notation();
allsheets[s].getRange(newcells).setBackground('#ffffff');
}
}
}
}
}
}
The problem is getting this script to trigger on a change to background color. According to this, such a feature is not yet possible. Can anyone provide a potential solution?
UPDATE:
Working solution. Triggered by a drop-down menu selection.
function songStatus()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = ss.getDataRange();
var curCell = sheet.getActiveCell();
var curCol = curCell.getColumn();
var curRow = curCell.getRow();
var allSheets = ss.getSheets();
var songs = [];
var status = sheet.getRange(curRow, 3).getValue();
var genre = sheet.getRange(curRow, 11).getValue();
if (status == "Now") {
sheet.getRange(curRow, 1).setBackground('#f884ff');
sheet.getRange(curRow, 3).setBackground('#f884ff');
var song = sheet.getRange(curRow, 1).getValue().toString();
for (var s=7; s < allSheets.length; s++) {
var row = allSheets[s].getDataRange().getLastRow();
var col = allSheets[s].getDataRange().getLastColumn();
var cells = allSheets[s].getDataRange().getValues();
for (var i=0; i < row; i++) {
for (var j=0; j < col; j++) {
if (cells[i][j].toString().match(song) == song) {
allSheets[s].getRange(i+1,j+1).setBackground('#f884ff');
}
}
}
}
}
else if (status == "Next")
{
sheet.getRange(curRow, 1).setBackground('#f2a2a2');
sheet.getRange(curRow, 3).setBackground('#f2a2a2');
var song = sheet.getRange(curRow, 1).getValue().toString();
for (var s=7; s < allSheets.length; s++) {
var row = allSheets[s].getDataRange().getLastRow();
var col = allSheets[s].getDataRange().getLastColumn();
var cells = allSheets[s].getDataRange().getValues();
for (var i=0; i < row; i++) {
for (var j=0; j < col; j++) {
if (cells[i][j].toString().match(song) == song) {
allSheets[s].getRange(i+1,j+1).setBackground('#f2a2a2');
}
}
}
}
}
}
Unfortunately, onEdit trigger only fires when an "Edit" is made by the user. However, you are right, changing the color is not considered as an edit. I would suggest a slightly different approach that would work in such a scenario. Instead of tracking your new songs by highlighting them with green and having the sheet run a script to detect if the color has been changed for that cell and then running a script to find that same song in other sheets, I'd suggest either tying your Yes/No drop-down to the onEdit function to fire the color change and the other scirpt to search for that song in other sheets, or making a new New/Old drop-down list to do that for you. Here's a small pseudo-code to do that:
function onEdit()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = ss.getDataRange();
var curCell = sheet.getActiveCell();
var curCol = curCell.getColumn();
var curRow = curCell.getRow();
var allSheets = ss.getSheets();
//Assuming your New/Old column in E
var status = sheet.getRange(curRow, 6).getValue();
if (status == "New")
{
sheet.getRange(curRow, 1, 1, range.getLastColumn()).setBackgroundRGB(230,240,220);
//Assuming your song name is in Column B
var song = sheet.getRange(curRow, 3).getValue();
for (var i=0; i<allSheets.length; i++)
{
var sRange = allSheets[i].getDataRange();
var sData = sRange.getValues();
var sRows = sRange.getLastRow();
for (var j=0; j<sRows; j++)
{
if (sData[j][1] == song)
{
allSheets[i].getRange(j+1, 1, 1, sRange.getLastColumn()).setBackgroundRGB(230,240,220);
}
}
}
}
}
Another advantage of having a code like this is that if your sheet evolves to say, track all the songs that were Old, New, In-progress, On hold or any different statuses that you could think of, and each of these had to be tracked by a color code at a glance, it's much easier to add else-if statements to do that for you.
Hope this helps!
A gs I have been using in the past to check for duplicates, is no longer working. The script would check all cells in the spread sheet if any were identical it would highlight all their occurrences green. I also had another function that would revert all the cells back to white.
setBackgroundColors() has been deprecated; people have been recommended to now use setBackground(). The script still doesn't work...
Here is my gs, make a copy and fiddle with it. Many Thanks...
https://docs.google.com/spreadsheets/d/1UELTxZRZPKQKU9NsQwNefvdxJDM0xDt8904sZy3etoY/edit#gid=0
Here is the script.
/**
* Retrieves all the rows in the active spreadsheet that contain data and logs the
* values for each row.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function readRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
Logger.log(row);
}
};
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Check Directory",
functionName : "CheckDirectory"
}];
spreadsheet.addMenu("Script Center Menu", entries);
};
function CheckDirectory() {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var numRows = data.length;
var numColumns = data[0].length;
var formats = [];
var values = [];
for (var i = 0; i < numRows; i++) {
formats[i] = [];
for (var j = 0; j < numColumns; j++) {
formats[i][j] = 'white';
if (data[i][j] != '') {
values.push([data[i][j], i, j]);
}
}
}
var numValues = values.length;
for (var k = 0 ; k < numValues - 1; k++) {
if (formats[values[k][1]][values[k][2]] == 'white') {
for (var l = k + 1; l < numValues; l++) {
if (values[k][0] == values[l][0]) {
formats[values[k][1]][values[k][2]] = 'green';
formats[values[l][1]][values[l][2]] = 'green';
}
}
}
}
dataRange.setBackground(formats);
};
function resetCheckDirectory() {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var numRows = data.length;
var numColumns = data[0].length;
var formats = [];
var values = [];
for (var i = 0; i < numRows; i++) {
formats[i] = [];
for (var j = 0; j < numColumns; j++) {
formats[i][j] = 'white';
if (data[i][j] != '') {
values.push([data[i][j], i, j]);
}
}
}
var numValues = values.length;
for (var k = 0 ; k < numValues - 1; k++) {
if (formats[values[k][1]][values[k][2]] == 'white') {
for (var l = k + 1; l < numValues; l++) {
if (values[k][0] == values[l][0]) {
formats[values[k][1]][values[k][2]] = 'white';
formats[values[l][1]][values[l][2]] = 'white';
}
}
}
}
dataRange.setBackground(formats);
};
Use setBackgrounds(). With an s since it's a method that applies multiple background colors to multiple cells