is there any script or formula that can help me do the data cleaning. For example in the sheet below, https://docs.google.com/spreadsheets/d/1mLZ8TYNpNHVN1Kc8QF80Ns3RX-EXdSz5s9WmHoIS8Pw/edit?usp=sharing, I have "Form responses 1" which capture the data entry from google form and "cleaning data" sheet. I tried to use Arrayformula and Importrange but i cannot edit the data in "Cleaning data" sheet. Currently, I just copy and paste manually to the other sheet.
What I wanna do
Respondent enter data in google form.
Data appear in "Form responses 1" sheet.
Updated data in "Form responses 1" automatically copied and paste in the "Cleaning data" sheet by row.
Thank you!
In your situation, how about the following sample script?
Sample script:
Please copy and paste the following script to the script editor of Google Spreadsheet. And, please install OnSubmit trigger to the function onSubmit. When you use this script, please submit your Google Form. By this, the script of onSubmit is run by firing the OnSubmit trigger.
function onSubmit(e) {
const range = e.range;
const srcSheet = range.getSheet();
const dstSheet = e.source.getSheetByName("Cleaning Data");
const srcRange = srcSheet.getRange(range.rowStart, 1, 1, srcSheet.getLastColumn());
const dstRange = dstSheet.getRange(dstSheet.getLastRow() + 1, 1);
srcRange.copyTo(dstRange, {contentOnly: true});
}
Note:
In this script, please don't directly run this function with the script editor. Because this script uses the event object of OnSubmit trigger. When you directly run this script an error like TypeError: Cannot read property 'range' of undefined occurs. Please be careful this.
References:
Installable Triggers
Event Objects
Related
I tried writing an AppsScripts script to refresh sheet each time I press a button that the script is assigned to.
The only thing that must change each time is the cell with formula "=INDIRECT("A"&RANDBETWEEN(1;20))"
In your situation, I thought that these threads might be useful. "https://stackoverflow.com/q/56893480", "https://stackoverflow.com/q/61300428" But, in this case, the event object is used and a part of the formula is used. So, in this answer, I would like to introduce a sample script for refreshing the cells including the specific function =INDIRECT("A"&RANDBETWEEN(1;20)) by clicking a button on the Spreadsheet.
Sample script:
Please copy and paste the following script to the script editor of Spreadsheet and save the script. And, please assign the function name of myFunction to a button on the Spreadsheet. By this, when you click the button, the script is run.
function myFunction() {
const formula = '=INDIRECT("A"&RANDBETWEEN(1;20))'; // This is from your question.
const temp = formula.replace(/([=()])/g, "\\$1");
const dummyFormula = "=sample";
const obj = [
{ "from": `^${temp}|^${temp.replace(/;/g, ",")}`, "to": dummyFormula },
{ "from": `^\\${dummyFormula}`, "to": formula }
];
const sheet = SpreadsheetApp.getActiveSheet();
obj.forEach(({ from, to }) =>
sheet.createTextFinder(from).matchFormulaText(true).useRegularExpression(true).replaceAllWith(to)
);
}
When this script is run, the cells including a formula of =INDIRECT("A"&RANDBETWEEN(1;20)) in the active sheet are refreshed.
Note:
This sample script is for refreshing your provided formula of =INDIRECT("A"&RANDBETWEEN(1;20)) on the active sheet. When you change the formula, this script might be required to be modified. Please be careful about this.
Reference:
createTextFinder(findText) of Class Sheet
When I open a hidden sheet by a link, the system shows me notification that it's hidden with Unhide button:
When I click on Unhide I want to execute a script. Is it possible?
Issue and workaround:
In the current stage, there are no methods for directly running the script by clicking "Unhide" button in your situation. So, in this case, it is required to use a workaround. In this workaround, onSelectionChange of the simple trigger is used. When onSelectionChange is used, the change of tab can be detected. Ref When "Undide" button is clicked, the tab is changed. This workaround uses this situation.
Usage:
1. Sample script.
Please copy and paste the following script to the script editor of Spreadsheet.
function onOpen(e) {
const prop = PropertiesService.getScriptProperties();
const sheetName = e.range.getSheet().getSheetName();
prop.setProperty("previousSheet", sheetName);
}
function onSelectionChange(e) {
const prop = PropertiesService.getScriptProperties();
const previousSheet = prop.getProperty("previousSheet");
const range = e.range;
const sheetName = range.getSheet().getSheetName();
if (sheetName != previousSheet && range.getRichTextValue().getLinkUrl() != "") {
// When the tab is changed, this script is run.
range.setBackground("red");
}
prop.setProperty("previousSheet", sheetName);
}
2. Testing.
In order to use this script, please reopen Google Spreadsheet. By this, the tab name is stored to PropertiesServices. The detection of change of tab uses this information.
And, in this case, as a sample situation, it supposes that "Sheet2" is hidden. And, the cell link of "Sheet2" is put in "Sheet1". When this link is clicked, a dialog is opened. When "Unhied" button is clicked, the tab is changed. And this change of tab is detected by onSelectionChange. By this, the script can be run.
The demonstration is as follows.
Note:
Unfortunately, the simple trigger of onSelectionChange cannot use all methods of Google Apps Script. Ref Although I'm not sure about your script, I thought that this is an important point of this workaround.
References:
onSelectionChange(e)
Related thread.
Is there a google spreadsheet trigger that fires after a tab is changed?
I previously used an array formula to assign a unique ID to new form submissions; but with 27 columns and over 5000 rows of data, the cost to run the array formula interferes with my onformsubmit to send out a custom email to a subset of people blocking it from sending out emails.
I'm trying to assign the value "Txxxxxx" where xxxxxx is the next number of the submissions in Column 22, i.e. T05000 or T00100
I have no idea on how to write the code to do this, anyone have any ideas? Would I have to trigger it with an onformsubmit? Would that interfere with the onformsubmit I already have to send out emails?
I believe your goal as follows.
You want to put a counter value when the Google form is submitted.
In your situation, the counter value is put to the column "V" as the format like T001216 and T001217.
When the previous counter is T001217, when the Google form is submitted, you want to put the value of T001218 to the column "V" of the submitted row.
In this case, I would like to propose the following sample script. In this sample script, the method of autoFill in Class Range is used.
Sample script:
Please copy and paste the following script to the container-bound script of Google Spreadsheet that the value is submitted from Google form. And please install the OnSubmit trigger to the function of onSubmit. By this, when the Google form is submitted, the value like T01218 is added to the column "V".
function onSubmit(e) {
const initialValue = "T001216"; // This is the initial value at the row 2.
const counterColumn = 22; // 22 is the column "V".
const range = e.range;
const sheet = range.getSheet();
if (range.rowStart == 2) {
sheet.getRange(2, counterColumn).setValue(initialValue);
return;
}
const previousRange = sheet.getRange(2, counterColumn, range.rowStart - 2);
previousRange.autoFill(previousRange.offset(0, 0, range.rowStart - 1), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
}
In this sample script, when the 1st value is submitted of Google form, the value of initialValue is used as the initial value. In this sample script, the value of T001216 is used because of your sample image.
Note:
This sample script is run by the installable OnSubmite trigger, when the Google form is submitted. So, when you directly run the function of onSubmit at the script editor, an error like TypeError: Cannot read property 'range' of undefined occurs. Please be careful this.
References:
Installable Triggers
autoFill(destination, series)
I have a spreadsheet where users can enter data and then execute a function when clicking on a button. When the button is clicked it logs the time and entered data in a new row on another sheet in that spreadsheet.
To make sure that sheet is not accidentally edited by the users I want to create a non-shared backup of that data.
I import the range to another spreadsheet, but just importing the range means that if the original sheet is edited/erased that data will also be edited/erased, so I wrote the following script to log the changes as they come in.
function onEdit(event){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var incomingSheet = ss.getSheetByName('Incoming');
var lastRow = incomingSheet.getLastRow();
var incomingData = incomingSheet.getRange(lastRow,1,1,7);
var permanentSheet = ss.getSheetByName('PermanentLog')
var newdataRow = permanentSheet.getLastRow();
incomingData.copyTo(permanentSheet.getRange(newdataRow+1,1));
}
This works when Run from the Apps Script Editor, however, when I enter new data and click the button on the original spreadsheet, it logs the data to the log sheet there, and the range is imported to the 'Incoming' sheet of the new Spreadsheet, but the data is not copied over to the 'Permanent Log' sheet (unless I Run it manually from within the Apps Script Editor). It also works if I remove the ImportRange function from the first sheet and then just manually enter data in on the 'Incoming' sheet.
So does this mean new rows from an Imported Range do not trigger onEdit? What would be the solution? I don't want to run this on a timed trigger, I want to permanently capture each new row of data as it comes in.
Also, am I overlooking a more elegant and simple solution to this whole problem?
Thank you for your time.
This function will copy the data to a new Spreadsheet whenever you edit column 7 which I assume is the last column in your data. It only does it for the sheets that you specify in the names array. Note: you cannot run this from the script editor without getting an error unless you provide the event object which replaces the e. I used an installable onEdit trigger.
The function also appends a timestamp and a row number to the beginning of the archive data row
function onMyEdit(e) {
e.source.toast('entry');//just a toast showing that the function is working for debug purposes
const sh = e.range.getSheet();//active sheet name
const names = ['Sheet1', 'Sheet2'];//sheetname this function operates in
if (~names.indexOf(sh.getName()) && e.range.columnStart == 7) {
const ass = SpreadsheetApp.openById('ssid');//archive spreadsheet
const ash = ass.getSheetByName('PermanentLog');//archive sheet
let row = sh.getRange(e.range.rowStart, 1, 1, 7).getValues()[0];
let ts = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy/MM/dd HH:mm:ss");//timestamp
row.unshift(ts, e.range.rowStart);//add timestamp and row number to beginning
Logger.log(row);//logs the row for debug purposes
ash.appendRow(row);//appends row to bottom of data with ts and row
}
Logger.log(JSON.stringify(e));
}
Restrictions
Script executions and API requests do not cause triggers to run. For example, calling Range.setValue() to edit a cell does not cause the spreadsheet's onEdit trigger to run.
https://developers.google.com/apps-script/guides/triggers
So yeah, as far as I understand you it can't be done that way.
I am trying to get this script to only run if is sees data in A3. the data is coming to this sheet from another sheet. I tried the onChange but it wouldnt trigger when the new data arrived in "Top Up Needed". add the onchange to the project triggers but still doesnt run script.
function TopUpNeeded() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('TOP UP NEEDED'), true);
var sheet = spreadsheet.getSheetByName('TOP UP NEEDED');
sheet.getRange('J3').activate().setFormula('=QUERY({\'SKU & Qty\'!$A$3:$C},"SELECT * WHERE Col1 MATCHES \'" & JOIN("|",FILTER(I2:I, NOT(ISBLANK(I2:I)))) & "\' ")');
}
also tried this code above my code,but no good.
function onChange() {
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("TopUpNeeded")
.forSpreadsheet(sheet)
.onChange()
.create();
}
Thanks In Advance
onChange does not run if changes were not made by a human, see restrictions
The exception is if the data is being updated with the cell formula IMPORTRANGE
You can paste into cell "A3" of sheet "Top Up Needed" the formula
IMPORTRANGE(spreadsheet_url, range_string)
specifying the spreadsheet and range that is expected to populate the cell content.
In this case your first function will fire on onChange trigger each time the content of A3 updates.