Drop down list should be automated to copy and paste - google-apps-script

Lets say I selected Funded in drop down list located in C2 than I would like the value of B2 copied to A2
There are numbers in the column UPCOMING INCOME and drop down list in the next column. When we choose in drop down Payed (PENDING, PAYED, PAUSED) it should copy the number from the Upcoming income column and paste to column FUNDED. enter image description here

Moving F to A
function onEdit(e) {
const sh = e.range.getSheet();
if(sh.getName() == "Your Sheet Name" && e.range.columnStart == 8 && e.range.rowStart > 1 ) {
e.range.offset(0,-7).setValue(e.range.offset(0,-2).getValue());
}
}
creating markdown tables
google-apps-script reference
javascript reference
Learn More

This should theoretically do what you're asking it to do, you just need to set a trigger for 'on edit' in the triggers tab when setting up your script.
function someFunction(){
//Gets the spreadsheet with the name you specified
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet4')
//Creates a 2D-Array of values based on the range you specify
var dataRange = ss.getRange(2,6,ss.getLastRow()-1,3).getValues()
//Runs through the 2D-array, checking every value for a match
for(var i = 0; i < dataRange.length; i ++){
for(var j = 0; j < dataRange[i].length; j++){
//If there is a match, pastes the value from the 'Upcoming Income' column to the 'Funded' column
dataRange[i][j] == 'Payed' ? ss.getRange('A'+(i+2)).setValue(dataRange[i][0]) : null
}
}
}
This is at least how I would solve it, but I'm sure there are many other quicker more elegant ways of doing so. You will have to make adjustment so that it will work with your spreadsheet, but I believe they should be fairly simple. If there is an error, please let me know, and I'll do my best to fix it.
In the future, please do what #Cooper recommended and make sure your question is more clear in what it is asking, and please attempt to code it yourself first before asking for help from others.

Related

Change values depending of others values generated automatically

I have developed a web app to manage the bonuses of a company.
It has two pages, the first one to fill a form and declare a "no-bonus" reason and the second one to consult who will be entitled to a bonus at the end of the month.
The main rule is that for two no-bonus reasons filled in for one person, the bonus will not be paid. Each employee's counter is reset to zero each month.
So I was able to make the application with the form without any problems. I was also able to upload the different "no-bonus" in the consultation page. However, I would like to add a table with the list of employees, the number of "no-bonus" of the month and if they are entitled to their bonus or not.
To do this, I made a specific tab in my Google Sheets with a column for "employee", one for the number of "no-bonus" (with a CountIfs formula) and one to know if the bonus is granted or not. I added the onEdit(e) function in my code to be able to display "No" if the number of "no-bonus" is greater than 1 and "Yes" in the opposite case.
The problem I have is that my onEdit(e) acts when I make a modification in a cell of the no-bonus column. It does not act when I fill in the form. And I don't see how to counter this.
Here is the code of my onEdit(e) function:
function onEdit(e) {
var ss = e.source;
var activeSheet = ss.getActiveSheet();
var cell = e.range;
if (activeSheet.getName() == "Sheet1" && cell.getColumn() == 2 && cell.getRow() > 1) {
var choice1 = cell.getValue();
if (choice1 > 1){
cell.offset(0,1).clearDataValidations()
cell.offset(0,1).setValue("No");
}
else{
cell.offset(0,1).clearDataValidations()
cell.offset(0,1).setValue("Yes");
}
}
}
Here is the link of the Sheets in question: link
For those who don't want to access the link, here is a screenshot of the tab where the fromulaire requests are saved :
And here is the table where the onEdit(e) function is used:
Sorry for my English, it is quite average. Thanks in advance for your help.

Hide rows based on multiple checkbox values

The project I am working on is to calculate costs of remaining sets in a mobile game. It has a spreadsheet with a list of all the sets, and checkboxes for all 5 pieces, Columns B:F. I want to include the option to hide all sets that are completed, so all Checkboxes are checked. This is done via another Checkbox, H16.
I have modified the Checkbox values to use Yes and No.
I have never used Google Apps Script before, and am very new to coding in general. I think what I need is, to use onEdit, then every time a cell is edited, check if H16 is TRUE, then scan through each row to check the B:F values. If all are true, hide that row. I don't know the best way to type that out, though.
Bonus points, I also want to include a reset checkbox, so when checked, set all values in B:F to false, and show the rows.
Here is a link to the spreadsheet
EDIT: My current GAS code, which isn't much because I don't know what I am doing:
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var maxSheet = 100;
if(H16 == true)
{
for(i, i<=maxSheet, i = i + 1) {
}
} else {
sheet.showRows(1, maxSheet);
}
}
Hiding rows when all five columns are true
This may not be exactly what you wish but I think it's close. I did not use yes and no values because it's easier for me to leave it true false but you can change that. I'm using Sheet0 and you can change that as well. I used less rows so you can also change that. But the basic idea is that when H16 is clicked it hides rows that have all five columns checked.
Code:
function onEdit(e) {
e.source.toast('entry');//debug
const sh = e.range.getSheet();
const sr = 2;//data start row
const lr = 15;//last row of data
sh.getRange('K1').setValue(JSON.stringify(e));//debug
if(sh.getName() == "Sheet0" && e.range.columnStart == 8 && e.range.rowStart == 16 & e.value == "TRUE" ) {
e.source.toast('past if');//debug
e.range.setValue("FALSE");
let vs = sh.getRange(sr,2,lr - sr + 1, 5).getValues();
vs.forEach((r,i) => {
if(r[0] && r[1] && r[2] && r[3] && r[4]) {
e.source.toast(`Row: ${sr + i}`);//debug
sh.hideRows(sr + i);
}
});
}
}
Image of Sheet0:
I use K1 to provide me with the event object while I debug the script. And I also use the e.source.toast in several location to get an idea of what is going on.
Animation:
an incomplete description of the event object
You can get a better understanding of the event object by using the JSON.stringify code as show in my example.
Most new people want to run the code from the script editor so I'll tell upfront that unless you provide the event object to populate the e then it's not going to work. Just copy and past it and get you unique stuff set like sheet name and data space and then proceed to edit the page and figure out how it works.

Google sheets script writing, how do I prevent an auto update or recacluation of my timestamps in googel sheets?

I attached a copy of the spreadsheet I run in google. The concept is when someone begins picking an order, they will for instance type their name in I3 and their time will start. once complete they will type their name in J3 , each causing a time stamp below leading to a total duration time. later it will factor percentages.
The problem is the time stamps seem to randomly update without prompting to do so. it seems to be when it is printed or reopened. This will cause inaccuracies in the times and percentages. Any assistance would be greatly appreciated
It would appear that I should write a script to accommodate this need, but I haven't the slightest on how to do this. I was directed to this forum from a reply in google docs help forum
enter link description here
I don't think you can choose on which cell you update or recalculate (Tell me if I'm wrong).
A non-optimized workaround (Maybe some expert have got better solution):
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var i = 3;
while(i <= sheet.getLastRow())
{
var data = sheet.getRange(i, 9, 3, 2).getValues();
if(data[1][0].length == 0)
{
if(data[0][0] != "")
{
var d = new Date();
sheet.getRange(i+1, 9).setValue(d);
}
}
if(data[1][1].length == 0)
{
if(data[0][1] != "")
{
var d = new Date()
sheet.getRange(i+1, 10).setValue(d);
}
}
i=i+3;
}
}
The onEdit(e) function is a simple trigger implement in Google Spreadsheet. It will trigger each time a cell is edit.
On this code above, we iterate to check on each element if a name was added or not. If so, the code will set the date and time below the name just added. Since you set the value on one single moment, no auto update will modify those time.
for this workaround, you need to remove the formula you put on the cell where you want your timestamp (i.e I4 and J4). You can keep the cells which calculate the difference between time, they should work with no problem.
Paste below script in the script editor and save it.
function onEdit(e) {
if (e.range.rowStart % 3 != 0 || [9, 10].indexOf(e.range.columnStart) == -1) return;
var o = e.range.offset(1, 0);
if (!o.getValue()) o.setValue(new Date())
}
Don't run the script by clicking the play button in the script editor. Instead to back to any of the tabs, clear all cells where you now have the =now() formula and enter a name. See if the timestamp appears.

'onEdit' function doesn't always fire when editing multiple cells quickly

Purpose
This is for a checklist.
People type 'x' into a cell. If x is the only thing in the cell, it should change to ✓
Script
function onEdit(e) {
var r = e.range;
if (r.getValue() === 'x' || r.getValue() === 'X') {
r.setValue('✓');
r.setHorizontalAlignment('center');
}
}
Problem
Going slowly works.
But when inputting quickly (ie: type 'x', move to another cell with the arrow keys, type 'x', move, [quickly repeat this multiple times]), some cells change, but some remain as x.
EDIT:
I now have a working (but inelegant) solution. I'd still like to know if there's a more elegant solution.
This works
// Checks 300 rows and 11 columns, starting from E10 (row 10, col 5)
// if the value is 'x' or 'X', it changes it to a '✓'
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
// getRange(row, column, numRows, numColumns)
var values = sheet.getRange(10, 5, 300, 11).getValues();
for (var i=0; i<values.length; i++) {
for (var j=0; j<values[i].length; j++) {
if ( values[i][j] === 'x' || values[i][j] === 'X') {
var cell = sheet.getRange( 10 + i, 5 + j );
cell.setValue('✓');
cell.setHorizontalAlignment('center');
}
}
}
}
This checks every cell in the tables (3300 of them) each time onEdit fires. Since onEdit seems to always catch the last edit (but not the ones in between), this changes every x to ✓.
Background
At work, I've been asked to convert a checklist into a Google Doc. There are hundreds of checkboxes in various tables.
I've been asked to make the boxes have checks, ✓, since we print and show this checklist to clients.
Many of my colleagues are not computer literate, so the input method has to be very simple.
Questions
Is there a way to fix the original script, or is there another better way to do this?
I don't know if having data validation is an option? Else you can do this;
type in a cell: =char(10003) which will output as ✓
create data validation and choose list with items
copy the symbol (not the formula) and paste it in the box (and put a comma behind it)
if you need another symbol for not completed, repeat the previous steps with =char(10005), which will output as ✕
Besides that you can maybe use the square root symbol, which on my mac is easily entered using option-shift-V and looks like √ (you will have to look up that combination for your OS).

deleteRow based off cell edit on another sheet of same spreadsheet

WHAT I HAVE One google spreadsheet named "Script Test" with two sheets named "delete" and "non delete".
WHAT I NEED If a row in Col B on "non delete" is changed to 'DELETE' via the drop down menu, the row with the same Buy Number on "delete" will be deleted.
WHAT I HAVE TRIED
What has worked = By researching on stack I found an onEdit function that deletes a row on "delete" based on if a cell has a specific value. In this case, that value is 'DELETE'. The problem with this is, I can only get it to work if that cell is on the sheet "delete" rather than the sheet "non delete". If I'm working off of "non delete" and need to go back to "delete" to delete a row of information, I can just right click on the row number and manually delete it. So, this script isn't necessarily saving me time.
This script is as follows:
function onEdit(e) {
try {
var ss = e.source;
var s = ss.getActiveSheet();
if (s.getName() == 'delete' &&
e.range.columnStart == 1 && e.range.columnEnd == 1 && // only look at edits happening in col A which is 1
e.range.rowStart == e.range.rowEnd ) { // only look at single row edits which will equal a single cell
checkCellValue(e);
}
} catch (error) { Logger.log(error); }
};
function checkCellValue(e) {
if (e.value == 'DELETE') {
e.source.getActiveSheet().deleteRow(e.range.rowStart);
}
}
What has not worked = I fiddled with the script a bit to have it read Col F on "delete" and in Col F I have an Index Match of Col B in "non delete". However, this does not delete the row on "delete" when Col F changes to 'DELETE'. Now I'm not 100% on this but I can pretty much deduce that this is happening because Col F isn't being "edited", rather the formula inside of it is "updating". I've also tried fiddling with other scripts that I found on stack but none seem to have gotten me as close as the script above.
THINGS TO THINK ABOUT
First of all, thanks for any help you guys can give me. Just before posting this question, I came across a filter function that I think may be a direction to head in if I'm right about the Index Match. I found one function that hides rows based on a filter but I would need the row to be deleted so I'm assuming that is as simple as switching hideRows with deleteRows. I've tried adding screenshots of what I need done but I don't have enough reputation. I can and will add a link to a copy of the spreadsheet if that helps. Once again, thanks for any tips or guidance.
Copy of Script Test
Use the getSheetByName() method to get the delete sheet.
function checkCellValue(argRowToDelete) {
if (e.value == 'DELETE') {
var toDeltSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("delete");
toDeltSheet.deleteRow(argRowToDelete);
}
}
If you want a separate function just for deleting the row, maybe do the check for the 'DELETE' text in the main function, and pass the row number to the delete function:
I've tested the following code, and it works. When the drop down list is used to select 'DELETE' in the 'non delete' sheet, it deletes the corresponding row in the 'delete' sheet.
I made multiple changes to the code. Even though this code deletes a row in a sheet different from where the edit is taking place, there is still a potential problem. Once a row in the 'delete' sheet is deleted, the rows will shift. If you start deleting rows at the top or middle, then every row below the deleted row is no longer synced with the rows in the 'delete' sheet.
So, this answers your question, but now you have yet another problem.
function onEdit(e) {
try {
var ss = e.source;
var s = ss.getActiveSheet();
var colStart = e.range.columnStart;
var colEnd = e.range.columnEnd;
Logger.log('colStart: ' + colStart);
Logger.log('colEnd: ' + colEnd);
var thisRow = e.range.getRow();
Logger.log('s: ' + s.getName());
//Avoid looking at multi column edits. If column start and column end is same column,
//then not a multi column edit
var editedFromNonDelete = (s.getName() === 'non delete');
Logger.log('editedFromNonDelete: ' + editedFromNonDelete);
var editedFromColB = (colEnd === 2) && (colStart === colEnd);
// only look at edits happening in col B
if (editedFromNonDelete && editedFromColB) {
Logger.log('e.value: ' + e.value);
if (e.value === 'DELETE') {
fncDeleteRow(thisRow);
};
}
} catch (error) {
Logger.log(error);
}
};
function fncDeleteRow(argRowToDelete) {
var toDeltSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("delete");
toDeltSheet.deleteRow(argRowToDelete);
};
After testing out the filter function for a couple minutes, I've pretty much got it to do what I needed. Thanks anyways!