Automatically copy information once text in cell was changed - google-apps-script

I need some help from the experts here.
Please take a look at this spreadsheet:
https://docs.google.com/spreadsheets/d/1tSl8LxhLGoQMVT_83Ev4jMu_Fo1AW8lN6N8Yw8kX44U/edit#gid=640017957
Here is the story (in short):
Our company deals with many different sellers of e-commerce businesses that want to sell their business to new owners. For each seller, we have a specific sheet (seller A, seller B, seller C in the example spreadsheet above) where we fill out various data, including the last action and next action that we took/need to take when handling the communication regarding the sell of the business with each of our potential buyers. We try to find an easy way to automatically store the data that we fill out in the “last step” column so that every time we update a cell in this column, the data will be automatically copied to a sheet that store all the communication history with each buyer for each deal.
I thought about creating a tab such as the “all actions” sheet in the example spreadsheet above, where every time we update the data in the “last action” column, a new row will be automatically added to the “all actions” sheet with the relevant data shown there.
Is there any way to achieve this goal? If not, will you recommend a different method to get similar results so that we can automatically store (and see once needed) all the data that was entered in the past in the “last action” column?

You can use triggers to do this.
In your sheet, click Tools > Script Editor.
In the script editor, click Edit -> Current Project Triggers
In that window, in the lower right, there is a button to "Add Trigger".
When you add the trigger set the "Select Event Type" to "On Change".
Reference the function you wish to run that will do the work of adding the information.
You will need to write the JavaScript function (in the script editor) to do the insert.
If you are not familiar with JavaScript and using it to work with Google Sheets, the learning curve isn't very steep to do this basic thing. I recommend digging in. The power you will wield with your spreadsheets is well worth the time.

You need to use Google Apps Script and the onEdit trigger in particular.
Try this:
function onEdit(e) {
var row = e.range.getRow();
var col = e.range.getColumn();
if ( e.source.getActiveSheet().getName() != "All actions" && row>1 && col==2 ){
s_name = e.source.getActiveSheet().getName();
b_name = e.source.getActiveSheet().getRange(row,1).getValue();
a_taken = e.source.getActiveSheet().getRange(row,2).getValue();
e.source.getSheetByName("All actions").appendRow([s_name,b_name,a_taken,new Date()])
}
}
In order to use this function you need to go to the Spreadsheet file menu; click on Tools => Script editor, clear the code.gs file and copy the aforementioned code snippet. Then, everytime a seller edits the last action column the relevant information will be appended to the All actions sheet.

Try this:
function onEdit(e) {
var sh=e.range.getSheet();
var s_name=sh.getName();
if ( s_name!= "All actions" && e.range.rowStart>1 && e.range.columnStart==2 ){
values=sh.getRange(e.range.rowStart,1,1,2).getValues()[0];
e.source.getSheetByName("All actions").appendRow([s_name,values[0],values[1],new Date()])
}
}

Related

Looking for a script that will add in a blank row after a new value is detected

I work for a small business selling hot wheels and other diecast related products, and we are constantly needing to create lists in google sheets for pre-ordered products. I am looking for a script that will insert a blank row between every customer.
I have already automated everything to organize the data when importing a .CSV file using scripts I've found here, but manually inserting a blank row between each customer is what takes the most time. If more information is needed, just please let me know.
I found a script here that allowed me to auto fill the customers names into the empty cells below until it detects a new value. (when importing .csv, if the customer has multiple items in an order, it doesn't put their name in all cells of the customer column, only the first cell)
I'm probably wrong on this, but it seems like I might be able to adapt this script to recognize when a value is different from the one above, then add a blank row.
I am new to google sheets and scripting. So if possible, please try to explain as simply as you can. Thanks!
Edit:
Link to spreadsheet with data: https://docs.google.com/spreadsheets/d/1W8peYL9kZhtQWdeCPP2uDkmsqy3nL1kVPmgJJq4T_80/edit#gid=2100307022
Edit:
Updated spreadsheet to show input/output examples and added more information to main post
Insert a row into sheet when a new value appears during an edit
function onEdit(e) {
Logger.log(JSON.stringify(e));
e.source.toast('Entry');//debug
const sh = e.range.getSheet();
if(sh.getName() == 'Sheet name' && e.value) {
sh.insertRows(e.range.rowStart);
}
}
onEdit

How to create a function that triggers whenever a new sheet is created? [duplicate]

This question already has an answer here:
How to set sheet create event as a trigger in apps script
(1 answer)
Closed 1 year ago.
I have a spreadsheet with a sheet of modification times for each of my other sheets. For example, I have a 'Signing' and 'Profile' sheet, and in my modifications times sheet I have:
Sheet Name
Modification Time
Signing
1639335205000
Profile
1639335207338
I want to create a function that, whenever I create another sheet, automatically adds it to the modifications times sheet as a new row.
I have looked at ScriptApp triggers and events but haven't found anything that is related(onEdit for example might be useful if there was a way to know if the edit was creating a sheet (if it even catches those events) but would also be triggered all the time).
I've actually wondered this myself and I hope someone can post a better answer than my method.
First, I create a named range that's going to store the number of sheets in the workbook (in below code I used sheetCount). Make sure this is at the workbook level (which by default google does).
Then leverage onEdit with this:
function onEdit(e) {
//var range = e.range;
const ss = SpreadsheetApp.getActiveSpreadsheet();
const storedSheetCount = ss.getRange("sheetCount")//<-- need to setup named range
var sCount = ss.getNumSheets();
if(storedSheetCount.getValue()!=sCount){
if(storedSheetCount.getValue()<sCount){
// more
Browser.msgBox("You addeded a spreadsheet!")
}else{
//for less
Browser.msgBox("you took one away")
}
//both cases update the value
storedSheetCount.setValue(sCount); //<--- updates stored count
}
}
I am well aware that this is not ideal for a variety of reasons including:
No code is executed until an edit ACTUALLY happens.
Stated differently, adding a sheet is not an edit event, so a user must then click into a cell or delete a blank one to kickoff the procedure.
Takes up space on the spreadsheet front end.
I hate helper columns/cells. Names is one area that Excel definitely crushes GoogleShhets as it allows direct references to values. Thus with Excel, I could avoid cluttering a spreadsheet by setting a named rage to the sheetCount (ie. refersTo:=3). One alternative to this would be to use the spreadsheet's file description, but this requires granting permissions to Drive Service which opens up all kinds of security risks for such a trivial request.
If anyone can do better, please share.

GoogleSheets - Is there a way to extract user info from "show edit history" to a cell?

I am trying to document in a certain column, for each row, the user info as it is shown when using the "show edit history" option (by right-clicking a cell).
More specifically- for a given row, if the cell in column G was last modified by me- the cell in column B should say "Yaniv A" or "yaniva#emaildomain.com". Of course this should apply the same way for any other editor.
New information should replace any old in column B one anytime the coresponding cell in column G is modified.
On Apps Script you can set up an onEdit trigger that retrieves the username of the editor and cell where the change was made; but you will have to keep in mind that there may be cases where the username is not retrievable (mainly if the user haven't accepted the script scopes), you can read more about those situations on getActiveUser docs.
You can achieve what you are requesting with the following function. It will use the event object to check if the change was made on the G column, and if it was, the email of the user (or Unknown if the scopes weren't accepted) will be written on the B column of the same row.
function onEdit(e) {
var range = e.range;
var editor = e.user.getEmail();
if (editor == '' || editor == null) {
editor = 'Unknown';
}
if (range.getA1Notation().search('G') != -1) {
range.offset(0, -5).setValue(editor);
};
}
After saving this function you will have to create a installable trigger. To do so, go to Edit 🡆 Current project's triggers. After that, click on + Add Trigger and fill this settings:
Choose which function to run: onEdit
Choose which deployment should run: Head
Select event source: From spreadsheet
Select event type: On edit
Failure notification settings: as you wish
After saving the trigger you could test the function by yourself modifying a cell in the G column. Please, do not hesitate to ask for any clarification about my answer or the code itself.

Accessing same spreadsheet but show different records, filtered by category in google spreadsheet?

Good day,
Just want to ask if it is possible to access same google-spreadsheet by different google account and show different records depend on the category or primary key that they have or they belong?
thank you so much.
Yes, you can functionally do this, but it isn't neat and creates more problems than it solves. Here's a simple example:
function hideSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Your sheet");
// Get the user accessing the sheet
var user = Session.getActiveUser().getEmail();
// Match an email. If you're using an array of people, you'll need to loop it.
if(user != "email#email.com") {
// If they don't match the test, hide the sheet.
ss.hideSheet();
} else {
ss.showSheet();
}
Set an onOpen() trigger for the function. The users will need editing rights (which kind of defeats the purpose) or the script won't run. If it's a shared sheet, it will also hide for you unless you test for your account, but showing the sheet will also show for shared users.
A better solution would be to start a master sheet and =IMPORTRANGE(url, range) on slave sheets.
Create a master sheet only you have access to. Title each sheet by region. Create slave sheets titled by the region you want to give to someone else. In cell A1, use =IMPORTRANGE("theMasterSheetUrl","New York!A:Z"). Changing the range value allows you to share only portions of a master spreadsheet, so the New York rep doesn't see the San Francisco, etc. It avoids all the hassle of adding/removing permissions through a script and ensures up to date data on the region they need access to.

Script in Google Apps Script that copies values in a range to another sheet

I am working on a tool that will allow my company to track its financial investments.
I need to create a simple data entry form for users to input transaction data, which will then populate a master sheet which is the basis for the analyses the tool does. I cannot do this via Google Forms because the data entry form uses a lot of conditional formatting based on other data in the sheet.
I have uploaded a very simplified sheet to illustrate what I need: this
What I am looking for is a script that, upon clicking Submit in the Data Entry sheet, copies the values (NOT the formulas) in B12:E12 to the first empty row (in this case, row 8) in the "Master Table" sheet. Ideally, clicking "Submit" will also clear the data entry fields in C4:C7 in the "Data Entry" sheet.
I have looked through various forums for a solution but have not found anything that does exactly that. I am sorry to say I am a complete newbie at Google Apps Script, therefore I could not write my own code to share, which I am aware is customary when asking a question here.
If anyone could point me in the right direction regardless, it would be much appreciated. I am currently trying to learn JavaScript and Google Apps Script using online resources, but for this specific project, it would take too long for me to reach a level where I could help myself.
Thank you very much, GEOWill!
Your answer solved my problem and thanks to your comments, I was able to understand exactly what your code does. I changed the code only to remove the Menu (but thank you very much for showing me how that is done anyway) - I tied the function to a Submit button inserted as a drawing. I also added some code to clear the contents of the entry range after clicking the button (this was suggested by someone else).
The final code that I used is:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var entry_sheet = ss.getSheetByName("Data Entry");
var master_sheet = ss.getSheetByName("Master Table");
function mySubmit() {
var entry_range = entry_sheet.getRange("B12:E12")
var val = entry_sheet.getRange("B12:E12").getDisplayValues().reduce(function (a, b) {
return a.concat(b);
});
Logger.log(val);
master_sheet.appendRow(val);
entry_sheet.getRange("C4:C7").clearContent()
}
I hope this helps others with a similar problem! Love how supportive this community is. Thanks for helping out.
I would begin by using a menu function to run your code in (rather than a cell button). You could use a cell button, but I believe you need to insert an image and assign a javascript function to that image anyways.
Basically, you begin by going to tools, script editor. Create an onOpen function and create a trigger that runs the onOpen() function each time the spreadsheet is opened. Inside the onOpen() function, we create a menu into which a physical menu item (a kind of button) exists (called 'Submit'). Finally, we associate a function to this button (I called it mySubmit()).
Inside of the mySubmit() function is where most of the functionality you are looking for exists. At this point, it is just a matter of copying from one range of cells and pasting them to another range of cells. For this, you'll notice that I had to setup a few variables ahead of time (ss, entry_sheet, master_sheet, entry_range, and master_row).
One last thing, you may want to protect the Master table sheet because if someone accidentally edits a cell beyond the last one edited, the input row would be copied to that row (due to how the getLastRow() function operates).
Hope this helps!
var ss = SpreadsheetApp.getActiveSpreadsheet();
var entry_sheet = ss.getSheetByName("Data Entry");
var master_sheet = ss.getSheetByName("Master Table");
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('MyMenu')
.addItem('Submit', 'mySubmit')
.addToUi();
}
function mySubmit() {
var entry_range = entry_sheet.getRange("B12:E12");
var master_row = (master_sheet.getLastRow() + 1);
entry_range.copyValuesToRange(master_sheet, 1, 3, master_row, master_row);
}