My issue is, I have data being moved from one Sheet to another via script when marked "Complete". In the "Completed" sheet is where I want to sort the data. I already have an Autosort script that works only when debugging, not even on edit (tried editing everywhere), Let alone when data is moved to the sheet.
I want to be able to Auto sort whenever data is moved to the new sheet (I don't think its an onEdit function?)
I am not a programmer and I'm fairly new to Google Apps Script. I just dabble into code once in a while because I find it interesting, so I don't even know where to start to get the results I'm looking for.
This is the Auto Sort,
function AutoSortOnEdit() {
var sheetNames = ["Complete"];
var ss = SpreadsheetApp.getActiveSpreadsheet();
sheetNames.forEach(function(name) {
var sheet = ss.getSheetByName(name);
var range = sheet.getRange(4, 1, sheet.getLastRow() - 1,
sheet.getLastColumn());
range.sort({column: 2, ascending: true});
});
}
EDIT: I realized I was using a script for multiple sheets. I changed it for one sheet, same issues though.
function AutoSortOnEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Completed Returns");
var range = sheet.getRange(4, 1, sheet.getLastRow() - 1,
sheet.getLastColumn());
range.sort({column: 2, ascending: true});
}
Any help would be greatly appreciated!
I managed to get it working by throwing the 2 scripts together under 1 function like so. I could not figure out how to get the event function to run while calling multiple functions, so I just combined them. Above the 2 "}" brackets is the move Script and below them is the Auto sort.
function onEdit(e) {
var ss = e.source;
var s = ss.getActiveSheet();
var r = e.range;
var actionCol = 24;
var nameCol = 24;
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
var colNumber = s.getLastColumn();
if (e.value == "TRUE" && colIndex == actionCol) {
var targetSheet = ss.getSheetByName("Completed Returns");
if (ss.getSheetByName("Completed Returns")) {
var targetSheet = ss.getSheetByName("Completed Returns");
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
sourceRange.copyTo(targetRange);
s.deleteRow(rowIndex);
}
}
var sheet = ss.getSheetByName("Completed Returns");
var range = sheet.getRange(4, 1, sheet.getLastRow() - 1, sheet.getLastColumn());
range.sort({column: 2, ascending: true});
}
Thanks Everyone for the response!
You can add your function to one another
function AutoSortOnEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Completed Returns');
var range = sheet.getRange(
4,
1,
sheet.getLastRow() - 1,
sheet.getLastColumn()
);
range.sort({ column: 2, ascending: true });
}
function copyData() {}
function userActionRun() {
copyData();
AutoSortOnEdit();
}
At now you can bind it ti EDIT event
function onEdit(){
userActionRun();
}
You can use the Sort function to sort a data-set.
If you have a function that moves data form one sheet to another when the row is marked as complete, then you can add a line at the end of that to sort it.
You could also create a FilterView that sorts the whole sheet based on your parameters. Unlike Filters, FilterViews are saved between sessions.
Related
I'm trying to add a script to my sheet that would help to keep in cleaner by moving all completed rows from 'Main' sheet/tab to 'Completed' if the row is in the 'Complete' status. Filtering unfortunately isn't enough.
I was hoping it's something I can figure out on my own but have been running into errors when running the script I modified. Not sure if it's the right one. Could anyone point me towards a correct script?
Any guidance would be much appreciated.
Here is the example sheet:
https://docs.google.com/spreadsheets/d/1dGm-XddcndmvwcP-K61OViLpNTcMmKpI2rEQOYpVuJQ/edit?usp=sharing
Here is the script I found and tried to modify to my own sheet but still got errors when renamed sheets and edited ranges:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Custom Menu')
.addItem('doneCopy', 'doneCopy')
.addToUi();
}
function doneCopy() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Current");
var values = sheet.getRange(1, 8, sheet.getLastRow(), 1).getValues();
var moveRows = values.reduce(function(ar, e, i) {
if (e[0] == "DONE") ar.push(i + 1);
return ar;
}, []);
var targetSheet = ss.getSheetByName("OLD");
moveRows.forEach(function(e) {
sheet.getRange(e, 1, 1, sheet.getLastColumn()).moveTo(targetSheet.getRange(targetSheet.getLastRow() + 1, 1));
});
moveRows.reverse().forEach(function(e) {sheet.deleteRow(e)});
}
There are three syntax errors in your code:
the name of the source sheet
var source = ss.getSheetByName("Main")
the name of the target sheet
var target = ss.getSheetByName("Completed")
the value to match
e[0] == "Complete"
function doneCopy() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Main");
var values = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
var moveRows = values.reduce(function(ar, e, i) {
if (e[0] == "Complete") ar.push(i + 1);
return ar;
}, []);
var targetSheet = ss.getSheetByName("Completed");
moveRows.forEach(function(e) {
sheet.getRange(e, 1, 1, sheet.getLastColumn()).moveTo(targetSheet.getRange(targetSheet.getLastRow() + 1, 1));
});
moveRows.reverse().forEach(function(e) {sheet.deleteRow(e)});
}
I have a form that is filled in and i would like for the answers coming in to be formatted as follow:
Text to be Wrapped, Centred Vertically as well as horizontally within the cell. As well as for the answers to be sorted from the youngest to the oldest based on column A
I have managed to pull some scripts but cannot seem to get them working in conjunction. Please help !!
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var s= ss.getActiveSheet()
var lr = s.getLastRow()
var r= s.getRange(1, 1, lr,4)
var set=r.setHorizontalAlignment("center")
var range = e.range;
range.setWrap(true);
}
function sortResponses() {
var sheet = SpreadsheetApp.getActive().getSheetByName("Form Responses 1");
sheet.sort(1, false);
}
and second
function Alignment() {
const spreadsheet = SpreadsheetApp.getActive();
const sheets = spreadsheet.getSheets();
sheets.forEach(sheet=>{
let rg=sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());
rg.setHorizontalAlignment('center')
.setVerticalAlignment('middle');
});
};
Please help
Here is a little script snippet I use for doing a similar thing.. Its not my best code but does the job.
The following function is set to run with a On Form Submit trigger,
function sort_and_format_FormResponses() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses 1');
//Sort Responses by Date Stamp
var range = sheet.getRange("A2:G");
range.sort({column: 1, ascending: false})
range.setWrap(true);
//Column Specific Formatting...
//Format column D to Plain text
range = sheet.getRange("D:D");
range.setNumberFormat('#STRING#');
range.setHorizontalAlignment('left');
}
function sort_and_format_FormResponses() {
var sh = SpreadsheetApp.getActive().getSheetByName('Form Responses 1');
var rg = sh.getRange("A2:G" + sh.getLastRow());//Don't use unterminated ranges like A2:G in apps script because in generates a lot of nulls for lastrow to maxrows
rg.sort({column: 1, ascending: false})
rg.setWrap(true);
rg = sh.getRange("D1:D" + sh.getLastRow());
rg.setNumberFormat('#STRING#');
rg.setHorizontalAlignment('left');
}
I have been asked to create a live Google Sheets Spreadsheet to track the work schedule at our yard. I have no experience with a script but found out I could program my sheet instead of hiding formulas and it would yield a cleaner result. I have been able to make the sheet organize itself and I was able to make it Archive manually (onEdit). What I'm looking for is to have it automatically run the code at 1 am so when we arrive at work it archives based on a cell value in a certain column.
This is an example of my onEdit script that works, but when someone is trying to check off the "YES" column there is some lag and can cause the wrong cell to be checked, which I then manually correct.
function onEdit() {
var sheetNameToWatch = "Schedule";
var columnNumberToWatch = 28;
var valueToWatch = "Yes";
var sheetNameToMoveTheRowTo = "Archive";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange);
sheet.deleteRow(range.getRow());
}
}
So this code runs at 100% failure but saves and executes, and I honestly don't know why. Could be I misunderstand the values I need to insert after the "function" area. I did have this setup with an "Auto Archive" trigger that created a menu button with a "Run" option on the sheet, but when you click that it only does the last row with "Yes" in column 28 (every press of the button will move 1 row until all rows are moved) and the button won't work for the other users of the sheet.
function createTrigger() {
ScriptApp.newTrigger("Move Archive") //Move Archive is the name of the script
.timeBased()
.everyMinutes(1) // only set to 1 minute for testing, I can change this out for a daily timer
.create();
}
function myFunction() {
var sheetNameToWatch = "Schedule"; // "schedule" is the sheet we enter info on
var columnNumberToWatch = 28; //Column is "AB"
var valueToWatch = "Yes";
var sheetNameToMoveTheRowTo = "Archive"; //"Archive is the sheet the info is sent to"
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange); // I get its programmed for last row with "Yes" here, unsure on how to change this.
sheet.deleteRow(range.getRow());
function myfunction() {
ScriptApp.deleteTrigger("Move Archive"); // could have wrong value here
}
}
}
All I want is the sheet to "Archive" based on a "Yes" value in Column 28 (AB). I want every row with that column value to Archive at 1 am automatically. Any help is appreciated. If someone even wants to recommend a book or digital instruction for beginners that would be great.
You have four project files each containing scripts of the same name, performing the same or similar tasks. You are experiencing lagging because you have multiple simple and installable scripts of the same name. Essentially, they are all trying to execute at the same time.
The following answer should be considered as one possible solution to your situation.
The elements of this script are:
There is a single project file. Unnecessary project files have been deleted.
There is a single function.
The function is a single "simple" trigger (onEdit(e)) which takes advantage of the various event objects returns by onEdit. There are no installable triggers, and any/all installable triggers have been deleted.
The function updates the "Schedule" and "Archive" sheets as described in the question; and then sorts both the "Schedule" and "Archive" sheets.
If there is a change on the "Railcars" sheet, the function sorts that sheet.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var testrange = e.range;
var testsheet = testrange.getSheet();
var testsheetname = testsheet.getSheetName();
var testrow = testrange.getRow();
var testcolumn = testrange.getColumn();
var testvalue = e.value;
var testsheetLC = testsheet.getLastColumn();
var testsheetRange = testsheet.getRange(testrow,1,1,testsheetLC);
//Logger.log("DEBUG: the test sheet range is "+testsheetRange.getA1Notation());
//Logger.log("DEBUG: Range: "+testrange.getA1Notation());
//Logger.log("DEBUG: The row is "+testrow+", and the column is "+testcolumn);
//Logger.log("DEBUG: The spreadheetsheet is "+e.source.getName()+", the sheet name is "+testsheet+", the range = "+testrange.getA1Notation()+", and the new value = "+testvalue);
//Logger.log(JSON.stringify(e));
// Copy/Paste to Schedule/Archive
var sheetNameSchedule = "Schedule";
var colNumberSchedule = 28;
var valueSchedule = "Yes";
var sheetNameArchive = "Archive";
// Sort Schedule
var sortSchedule = [{column: 1, ascending: true},{column: 2, ascending: true},{column: 7, ascending: false}];// date // Appt (time) // Type (Out/In/RR)
// Sort Railcars
var sheetNameRailcars = "Railcars";
var sortRailcars = [{column: 1, ascending: true}];
if (testsheetname === sheetNameSchedule && testcolumn === colNumberSchedule && testvalue === valueSchedule){
// this is a match
// Logger.log("DEBUG: this was a match");
// copy/paste to archive
var targetSheet = ss.getSheetByName(sheetNameArchive);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
//Logger.log("DEBUG: the target range is "+targetRange.getA1Notation());
testsheetRange.moveTo(targetRange);
testsheet.deleteRow(testrow);
// sort the Schedule Sheet
var Avals = testsheet.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
//Logger.log("DEBUG: The last row of content (in column A) = "+Alast+", and the last column = "+testsheetLC);
var sortrange = testsheet.getRange(2,1,Alast-1,testsheetLC);
//Logger.log("DEBUG: the sort range = "+sortrange.getA1Notation());
sortrange.sort(sortSchedule);
// sort the Archive Sheet
var ATvals = targetSheet.getRange("A1:A").getValues();
var ATlast = ATvals.filter(String).length;
//Logger.log("DEBUG: The last row of content (in column A) = "+ATlast+", and the last column = "+testsheetLC);
var sortrange = targetSheet.getRange(2,1,ATlast-1,testsheetLC);
//Logger.log("DEBUG: the sort range = "+sortrange.getA1Notation());
sortrange.sort(sortSchedule);
}
else if (testsheetname === sheetNameRailcars){
// sort the sheet
var Avals = testsheet.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
//Logger.log("DEBUG: The last row of content (in column A) = "+Alast+", and the last column = "+testsheetLC);
var sortrange = testsheet.getRange(2,1,Alast-1,testsheetLC);
//Logger.log("DEBUG: the sort range = "+sortrange.getA1Notation());
sortrange.sort(sortRailcars);
}
}
You can set up an installable trigger to run this function at 1am every morning:
function scheduleToArchive() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var schedule = sheet.getSheetByName("Schedule");
var archive = sheet.getSheetByName("Archive");
var scheduleData = schedule.getRange(2, 1, (sheet.getRange('A:A').getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()), 28);
for (row = 2; row <= scheduleData.getNumRows(); row++){
var data = schedule.getRange(row, 1, 1, 28).getValues();
if (data[0][27] == 'Yes'){
archive.getRange((archive.getLastRow() + 1), 1, 1, 28).setValues(data);
}
schedule.getRange(row, 1, 1, 28).clear();
}
}
In your spreadsheet, when getDataRange() is run on the sheet named 'Schedule', it returns row 631 as the last row with data even though there is only data in the first 20 rows, so to get around that I've used SpreadsheetApp.Direction.DOWN instead and run that on column A.
I've written script to sort a google sheet by column A, and then take you to the cell next to the one you just edited, and I have it working perfectly for me the owner, but for editors, nothing seems to work starting from the "sort" function.
I assume this means some part of it is an installable trigger? but as far as I can tell I've made it all with simple triggers.
function onEdit(e) {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var cell = sheet.getActiveCell();
var NEXTcell = sheet.getActiveRange().offset(0,1);
var range = e.range;
var columnOfCellEdited = range.getColumn();
var sheet = spreadsheet.getActiveSheet();
// When Column A edited
if (columnOfCellEdited === 1) {// Column 1 is Column A
//Set marker
NEXTcell.setValue('sorting');
// Sort whole sheet excluding first 2 rows by Column A.
sheet.getRange(1, 1, sheet.getMaxRows(), sheet.getMaxColumns()).activate();
spreadsheet.getActiveRange().offset(2, 0, spreadsheet.getActiveRange().getNumRows() - 2).sort({column: 1, ascending: true});
// Find original cell after sorting
var rowoffset = 3;
var rng = sheet.getRange(rowoffset, 2, 600);
var data = rng.getValues();
var search = "sorting";
for (var i=0; i < data.length; i++) {
if (data[i][0] == search) {
data[i][0] = "";
rng.setValues(data);
var foundcell = sheet.getRange((i+rowoffset), 2);
foundcell.activate();
break;
}
}
}
}
So Stackdriver logs for-the-win.
Turns out protections I hadn't considered are the culprit.
Ive been working on automatically sorting my data (ascending based on 2nd row 1st column data) and I found some tips through searching online but encountered an error which seems I cant find an answer through the net.
so heres the scenario:
I have 2 sheets, Sheet1 & Sheet2, the data from sheet1 is linked through sheet2 although sheet2 has additional columns,
this is sheet1
and this is sheet2
notice that the Column lastname and code in both sheets are thesame, the difference is the column Gender (Formatted on drop-down list) & Bdate(cell formatted as date)
I found a script that seems to work but I does not properly work completely, here is the output after I run the script.
notice the columns that inside the red box, it seems gender and bdate didnt follow the auto sort.
here is my code:
function autosortOnEdit() {
var sheetNames = ["Sheet1", "Sheet2"];
var ss = SpreadsheetApp.getActiveSpreadsheet();
sheetNames.forEach(function(name) {
var sheet = ss.getSheetByName(name);
var range = sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn() -1);
range.sort({column: 1, ascending: true});
});
}
my observation is I think this script does not work on cells that are formatted like the example above.
I want to sort this automatically based on column A "last name".
how can i make this script work even on formatted cells?
Thanks in Advance, I will continue searching through the net.
Not sure how to use range.sort({column: 1, ascending: true}); or how does it work, but whenever I want to sort sheet values, I do the following:
function myFunction()
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var rows = sheet.getLastRow();
var columns = sheet.getLastColumn();
var sortedValues = sheet.getRange(2, 1, rows-1, columns).getValues().sort();
sheet.getRange(2, 1, rows-1, columns).setValues(sortedValues);
}
Try this instead of your code, hope this helps as it is successfully sorting all the values when I tested.
EDIT
To apply the same to all sheets inside a spreadsheet, you can get sheet names and iterate it in for loop one by one. Check the code:
function myFunction()
{
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var currentSheetName, currentSheet;
for(var i=0; i<sheets.length; i++)
{
currentSheetName = sheets[i].getName();
currentSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(currentSheetName);
var rows = currentSheet.getLastRow();
var columns = currentSheet.getLastColumn();
var sortedValues = currentSheet.getRange(2, 1, rows-1, columns).getValues().sort();
currentSheet.getRange(2, 1, rows-1, columns).setValues(sortedValues);
}
}