I need to approach this a different way. My sheet has date fields for selecting a range of dates (A2 and B2). This works exactly as I need, I can pull a list of trips for any range of dates in the list of field trips.
My problem is that the script to duplicate trips overwrites all the data rows with the new data, so my formula is lost. I need the formula to stay for the next time I need to pull a trip schedule.
I think the solution is to move the formula to a different row. The script skips the first three rows. How can I move the formula into, let's say D1, but have the formula output to cell A4?
Here is my spreadsheet. Look at the sheet called Trip Schedule. I need the date pickers (cell A2 and B2) to choose the selection of trips (this already works), then I run the duplicate trips script, then take that list of results and build a trip schedule document.
function duplicateTrips() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Trip Schedule")
var data = sheet.getRange(4,1,sheet.getLastRow(), sheet.getLastColumn()).getValues();
var newData = [];
for(var n in data){
newData.push(data[n]);
if(!Number(data[n][2])){continue};// if column 3 is not a number then do nothing
for(var c=1 ; c < Number(data[n][2]) ; c++){ // start from 1 instead of 0 because we have already 1 copy
newData.push(data[n]);//store values
}
}
sheet.getRange(4,1,newData.length,newData[0].length).setValues(newData);// write new data to sheet, overwriting old data
}
Consider this answer executed by a script:
onEdit
createTrips()
- builds the Trip Schedule sheet
tripArray
) is used to build the contents of the Trip SchedulesetValues(tripArray)
function onEdit(e) {
// Logger.log(JSON.stringify(e)) // DEBUG
var editedValue=e.value
var editedSheet = e.range.getSheet().getName()
var editedRow = e.range.rowStart
var editedCol = e.range.columnStart
// Logger.log("DEBUG: edited value = "+editedValue+", edited sheet = "+editedSheet+", edited row = "+editedRow+", edited Column = "+editedCol)
var sheet2Watch = "Trip SchedulebyScript"
// Logger.log("DEBUG: edited sheet = "+editedSheet+", sheet to watch = "+sheet2Watch+", edited value = "+editedValue)
// test for sheet and edited value
if (editedSheet != sheet2Watch || editedValue != "TRUE") {
// no match, do nothing
// Logger.log("DEBUG: no match, do nothing")
return
}
// Logger.log("DEBUG: match = build trip schedule")
createTrips()
}
function createTrips() {
var tripSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Trip SchedulebyScript")
// clear existing data from tripSheet
var clearTripRange = tripSheet.getRange(4,1,tripSheet.getLastRow()+1,tripSheet.getLastColumn()).clear({contentsOnly: true});
Logger.log("DEBUG: cleared existing data")
// get the user variables
var startDate = tripSheet.getRange("A1").getValue()
var endDate = tripSheet.getRange("B1").getValue()
// Logger.log("DEBUG: Start date = "+startDate+"\nEnd date = "+endDate)
// Logger.log("DEBUG: value of Start date = "+startDate.valueOf())
// get the data
var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data")
var data = dataSheet.getDataRange().getValues()
// convert the date column of the data into a 1d array for analysis
var dates = data.map(function(e){return e[0]})
// Logger.log(dates) // DEBUG
// create a temporary Array to hold the data rows
var tripArray = new Array
// loop through dates to find matches of the Start and End dates
for (var i=0;i<dates.length;i++){
if ((dates[i].valueOf() >= startDate.valueOf()) && (dates[i].valueOf() <= endDate.valueOf())){
// Logger.log("DEBUG: row "+(i+1)" is a match: "+startDate+"="+dates[i])
// duplicate the rows as required
for (var b=0;b<data[i][2];b++ ){
tripArray.push(data[i])
}
}
}
// Logger.log("DEBUG: number of trip rows = "+tripArray.length+", number of trip columns = "+tripArray[0].length)
// paste triparray into the spreadsheet
tripSheet.getRange(4,1,tripArray.length,tripArray[0].length).setValues(tripArray)
Logger.log("DEBUG: updated Trip Schedule sheet")
}
SAMPLE - Checkbox
ADDENDUM - "Delete" rows instead of "clear" rows
The OP asks how to "delete the rows of data rather than "clear" them. The process is slightly more complicated.
The "sheet" method deleteRows(rowPosition, howMany) replaces the "range" method clear(options). This should be straightforward but a couple of issues were noted during testing.
.setFontWeight("normal")
to the line that updates the data. It ensures that all the data is formatted without bolding.In function createTrips()
:
Remove these lines
// clear existing data from tripSheet
var clearTripRange = tripSheet.getRange(4,1,tripSheet.getLastRow()+1,tripSheet.getLastColumn()).clear({contentsOnly: true});
Logger.log("DEBUG: cleared existing data")
Substitute these lines
// delete existing rows of data from tripSheet
// get the number of rows of data - include a test for no rows
var numOfRowsData = +tripSheet.getLastRow()-4+1
if (numOfRowsData <1 ){
numOfRowsData = 1
}
Logger.log("last row = "+tripSheet.getLastRow()+", number of rows = "+numOfRowsData+", columns = "+tripSheet.getLastColumn())
// delete the rows
tripSheet.deleteRows(4, numOfRowsData)
Logger.log("DEBUG: deleted the rows")
Amend this line
tripSheet.getRange(4,1,tripArray.length,tripArray[0].length).setValues(tripArray).setFontWeight("normal");