Im trying to create a simple script that firstly checks (all cells in row 3 starting from column 3) for whether they contain a name different from the available sheets and if so create a new one. If not go to the next cell down. Preferably until the row is empty but I didnt get that far. Currently I have
var row = 3; //Global Variable
function Main() { // Main Function
Activate();
GetNames();
}
function Activate() { // Initialize
var get = SpreadsheetApp.getActiveSpreadsheet();
var import = get.getSheetByName("Import");
}
function GetNames() { // Get Names and check for existing Sheets
var ss = SpreadsheetApp.getActiveSpreadsheet();
var import = ss.getSheetByName("Import");
var sheet = ss.getSheets()[0];
for (i = 0; i < 1000; i++) { // Loop which I think is broken
var names = import.getRange(row,3).getValue();
if (import.getSheetByName(names) == null) {
import.insertSheet(names);
import.activate();
}
row + 1;
}
}
And here is the Data
It succeeds to add the first sheet but fails to continue in the loop I think.
As you will probably see I'm very new to this and any help would be appreciated.
You probably wanted to increase row by 1 here:
row + 1;
But you're not. row + 1 is just an expression with a value (4, in your example, because row remains 3 throughout). What you would need is the statement
row = row + 1;
But if this is all that you're using the global variable row for, you don't need it at all. Just use the loop variable i that's already counting from 0 to 1000. You probably want something like import.getRange(i+3,3).
Related
I'm trying to use a script that automatically creates divisions on a spreadsheet. It receives as a value the number of times it has to create the same category of division. Each division/label it's composed of a merge of 6 cells in the same line.
I'm trying to make it work by using getLastRow as a base of the placement of the label, but I can't make it work it out with the merge.
Basically what I'm doing is:
function resumo() {
let ss = SpreadsheetApp.getActive();
let resumo = ss.getSheetByName("Resumo");
let numEntrada = resumo.getRange("c12").getValue();
criaParcela();
function criaParcela() {
for (i = 0;i < numEntrada; i++){
var fLine = resumo.getLastRow();
var bcell = (fLine+1);
var fcell = (fLine+6);
resumo.getRange(fcell,1).setValue("Entrada");
resumo.getRange(bcell,1,6,1).mergeVertically();
}
}
}
As you can notice, I'm not professional programmer.
Assuming that this is the end result you are looking for:
You can try the below script:
function doStuff() {
let spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
let sheetResumo = spreadsheet.getSheetByName("Resumo");
let numEntrada = sheetResumo.getRange("C12").getValue();
for (let i = 0; i < numEntrada; i++) {
let lastRow = sheetResumo.getLastRow() + 1;
sheetResumo.getRange(lastRow, i+1, 6, 1).mergeVertically();
}
}
The most notable changes that have been done to your script are the following:
+ using only one function;
Apps Script does not accept a function within a function in the way you had tried to use it.
+ getRange method is getting the proper parameters in order to perform the merge operation successfully;
As you can see, the i index is needed if you want to merge the same cells numEntrada multiple times.
Reference
Apps Script Sheet Class - getRange(row, column, numRows, numColumns).
I have a google sheet with a list of job names in column F. Each job name can appear multiple times in the list and I need to count or add a unique ID into another column in the same row for every new Jobname entered in column F.
The caveat is, the entries in column F can be "penciled" meaning a value will be entered before it is added to the dropdown list that validates column F (a named range called "JobList"). Those entries should not have a unique ID added.
I've seen a few different solutions online and wondering what could be the best option for my requirements to proceed with. Linked below
Automatically generate a unique sequential ID in Google Sheets
https://yagisanatode.com/2019/02/09/google-apps-script-create-custom-unique-ids-in-google-sheets/
Apologies if we are not allowed to link other sites, I will remove immediately if so.
Currently, I'm thinking of building this solution
Function1 to return number of times jobname appears in Col F
Function2 to add +1 to Function1 (unless its 1) and append to row
onEdit(e) > update this function to call Function2 when Col F is edited and send parameters of current row and value (jobname)
Seems like it could work - will come back with my progress
---- UPDATE ---
I have made a function that seems to work, it does take about 8 seconds to run, however, and seems like it could be prone to issues on many edits, but any onEdit function I think would behave in a similar way.
function onEdit(e) {
var range = e.range;
var ss = e.source;
var sheet = ss.getActiveSheet().getName();
var row = range.getRow();
var col = range.getColumn();
var jobname = e.value;
var count = 0;
var job = jobname;
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calendar v2");
var joblist = sh.getRange("F:F").getValues();
if(sheet=="Calendar v2" && col==6){
//range.setNote(sheet+' + '+row+' + '+col+' + '+jobname+ 'Last modified: ' + new Date());
// count = countJobname();
for (var i=0;i<joblist.length;i++){
if(joblist[i]==job){
count = count + 1;
Logger.log(count);
} SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheet).getRange(row,15).setValue("TRIGGER "+count);
}
}
}
I did build out working separate functions but for some reason, they were not working when called in onEdit, I rebuilt the onEdit function line by line and it eventually worked, will rework the functions back in but still open to suggestions if anyone has a better method. Still a rookie at this stuff :)
Another UPDATE
the last setValue line was running inside the for loop, badly formatted code introduces the dumbest problems. it runs almost instantly now!
Here is the revised code, it's a pretty simple solution and hits the core functionality and I will be building it out further to provide unique ID codes based off 2 columnns (Jobname + Category).
I haven't added the check for "pencil" entries, currently it checks all values in column F.
To implement that check instead we would add the commented code instead in the countJobname function find the Named Range instead
function onEdit(e) {
var range = e.range;
var ss = e.source;
var sheet = ss.getActiveSheet().getName();
var row = range.getRow();
var col = range.getColumn();
var jobname = e.value;
var count = 0;
if(sheet=="Calendar v2" && col==6){
count = countJobname(jobname);
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheet).getRange(row,15).setValue("TRIGGER "+count);
}
}
function countJobname(jobname){
var job = jobname;
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calendar v2");
var joblist = sheet.getRange("F:F").getValues(); //.getRangeByName("JobList").getValues();
var count = 0;
for (var i=0;i<joblist.length;i++){
if(joblist[i]==job){
count = count + 1;
Logger.log(count);
}
}return count
}
I'm trying to append rows from one sheet to another sheet based on two conditions. I'm fairly new to google script and coding in general.
You can find a copy of the worksheet here.
I want to extract all rows with a weeknum (column I of MASTER sheet) that matches the previous weeknum (found on the B2 cell of the DASHBOARD sheet) and that also have "Not Coming" (column K of MASTER SHEET).
The goal is to create a call list (on the Call List Cancelled W-1) every week with people that did not honor their appointments the week before. Ideally the rows would be appended on the top of the call list sheet.
I've managed to build this code as for now. But it does not work.
// Creating Call List from cancelled appointments in W-1
var ss = SpreadsheetApp.getActiveSpreadsheet();
//CALL LIST
var sheetCallList = ss.getSheetByName("Call List Cancelled W-1");
var rangeCallList = sheetCallList.getDataRange();
//MASTER
var sheetMaster = ss.getSheets()[0];
var dataRangeMaster = sheetMaster.getDataRange();
var valuesMaster = dataRangeMaster.getValues();
var lastRowMaster = sheetMaster.getLastRow();
var cameOrNot = sheetMaster.getRange("K:K").getValues();
var weekNumColumn = sheetMaster.getRange("I:I").getValues()
//DASHBOARD
var sheetDashboard = ss.getSheets()[1];
var weeknum = sheetDashboard.getRange(2, 2).getValue();
var lastweeknum = weeknum - 1
function appendRowsToCallList() {
for (var i = 2; i < lastRowMaster; i++); {
if ( lastweeknum == weekNumColumn && cameOrNot == "Not Coming") {
sheetCallList.rangeCallList.appendRow(valuesMaster);
}
}
}
Solution:
There is a typo in your for loop:
for (var i = 2; i < lastRowMaster; i++);
Since there's an extra semicolon, this would loop but execute nothing.
Also, to append rows, you need to refer to individual arrays in valuesMaster and check individual values in the other arrays. Also indexes start with 0 so to check from the second value you start the index with 1.
Function code:
function appendRowsToCallList() {
for (var i = 1; i < lastRowMaster; i++) {
if ( lastweeknum == weekNumColumn[i][0] && cameOrNot[i][0] == "Not Coming") {
sheetCallList.appendRow(valuesMaster[i]);
}
}
}
Output:
I have a sheet with rows I'd like to move to another sheet based on a cell value. I tried following this post's solution (refer below), but I'm having trouble editing the script towards what I want it to do.
I'm doing Check-Ins for an event. I would like to be able to change the value in Column F, populate Column G with the time the status changed, and for the row data to migrate to the Attendee Arrived sheet.
I believe the script already does this, but one has to run it manually. It also takes care of deleting the row data in A (Event) after migrating it to B (Attendee Arrived).
My question is could someone please help me set it up in order for script to run continuously (on edit), and also accomplish all of the above if I missed something?
I don't believe the script will respect the drop down format as it runs so I'm willing to manually type in something. It'd be cool if it could stay that way though - makes it easier for one.
Here's the sheet I'm testing on.
https://docs.google.com/spreadsheets/d/1HrFnV2gFKj1vkw_UpJN4tstHVPK6Y8XhHCIyna9TLJg/edit#gid=1517587380
Here's the solution I tried following. All credit to Jason P and Ritz for this.
Google App Script - Google Spreadsheets Move Row based on cell value efficiently
Thank you D:
function CheckIn() {
// How Many Columns over to copy
var columsCopyCount = 7; // A=1 B=2 C=3 ....
// What Column to Monitor
var columnsToMonitor = 6; // A=1 B=2 C=3 ....
//TARGET SPREAD SHEETS
var target1 = "Attendee Arrived";
//Target Value
var cellvalue = "Attendee Arrived";
//SOURCE SPREAD SHEET
var ss = SpreadsheetApp.openById('1HrFnV2gFKj1vkw_UpJN4tstHVPK6Y8XhHCIyna9TLJg');
var sourceSpreadSheetSheetID = ss.getSheetByName("Event");
var sourceSpreadSheetSheetID1 = ss.getSheetByName(target1);
var data = sourceSpreadSheetSheetID.getRange(2, 1, sourceSpreadSheetSheetID.getLastRow() - 1, sourceSpreadSheetSheetID.getLastColumn()).getValues();
var attendee = [];
for (var i = 0; i < data.length; i++) {
var rValue = data[i][6];
if (rValue == cellvalue) {
attendee.push(data[i]);
} else { //Fail Safe
attendee.push(data[i]);
}
}
if(attendee.length > 0){
sourceSpreadSheetSheetID1.getRange(sourceSpreadSheetSheetID1.getLastRow() + 1,
1, attendee.length, attendee[0].length).setValues(attendee);
}
//Will delete the rows of importdata once the data is copided to other
sheets
sourceSpreadSheetSheetID.deleteRows(2,
sourceSpreadSheetSheetID.getLastRow() - 1);
}
Try this:
I imagine that you already know that you'll need an installable onEdit Trigger and that you can't test a function of this nature by running it without the event object.
function checkIn(e) {
var sh=e.range.getSheet();
if(sh.getName()!="Event") return;
if(e.range.columnStart==6) {
if(e.value=="Attendee Arrived"){
e.range.offset(0,1).setValue(Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "M/d/yyyy HH:mm:ss"));
var row=sh.getRange(e.range.rowStart,1,1,sh.getLastColumn()).getValues()[0];
e.source.getSheetByName("Attendee Arrived").appendRow(row);
sh.deleteRow(e.range.rowStart);
}
}
}
I am trying to write a script in Google Apps Script that takes cell information from one sheet and copies it to another sheet, both for just grabbing certain columns to display on the second sheet and also a condition based on the values inside cells in a certain column. Here is what I have so far:
function onMyEdit() {
var myMaster = SpreadsheetApp.openById("xxxxx");
var masterSheet = myMaster.setActiveSheet(myMaster.getSheets()[0]);
var myNames = SpreadsheetApp.openById("xxxxx");
var namesSheet = myNames.setActiveSheet(myNames.getSheets()[0]);
var row1 = masterSheet.getRange(1, 1, masterSheet.getLastRow(), 1);
var rowV = row1.getValues();
var firstArray = masterSheet.getDataRange().getValues();
var dataList = [];
for (var i = 1; i < rowV.length; i++) {
dataList.push(firstArray[i][0]);
dataList.push(firstArray[i][1]);
dataList.push(firstArray[i][2]);
dataList.push(firstArray[i][3]);
}
for (var j = 0; j < rowV.length - 1; j++) {
namesSheet.getRange(2, j + 1, 1, 1).setValue(dataList[j]);
}
}
So as of now it only works on one row, starting from the second row (to allow for column headers). And I suppose when I want to grab rows conditionally based on cell data, I will use an 'if' statement for the condition inside the 'for' loop, but I want the data to copy to the next available row in both sheets. I suppose I'd use something like:
' getLastRow + 1 '
or something like that. I need this code to be as efficient as possible because of the amount of data and its purpose. I am pretty new to programming so please explain in detail, and thanks again.
I'm not sure I understood exactly what you wanted to do but -from what I understood- this code snippet should give you a better way to start with...
(I added a few comments to explain in the code itself)
function onMyEdit() {
var myMaster = SpreadsheetApp.openById("MasterSheet ID");
var masterSheet = myMaster.getSheets()[0]; // get 1rst sheet
var myNames = SpreadsheetApp.openById("NamesSheet ID");
var namesSheet = myNames.getSheets()[0]; // get 1rst sheet
var firstArray = masterSheet.getDataRange().getValues();
var dataList = [];
for ( r = 1; r < firstArray.length; r++) { // iterate the first col of masterSheet
if(firstArray[r][0]=='some condition'){ // if value in the first column == 'some condition get the second column cell in the new array (here you could change what you want to get)
dataList.push([firstArray[r][1]])
}
}
Logger.log(dataList)
if(dataList.length>0){
namesSheet.getRange(1,namesSheet.getLastColumn()+1,dataList.length,1).setValues(dataList);//copy data in a column after last col
}
}