I have this simple script:
function myFunction() {
var ssh = SpreadsheetApp.getActiveSpreadsheet();
var ss = ssh.getActiveSheet();
var s = ss.getActiveRange();
var rowIndex = s.getRowIndex();
var colIndex = s.getColumnIndex();
// Get the number of columns in the active sheet.
var colNumber = ss.getLastColumn();
if (colIndex == 1 && rowIndex != 1) {
//Get User Name from inputBox
var name = Browser.inputBox('Owner', 'Enter your Name', Browser.Buttons.OK_CANCEL);
var r1 = ss.getActiveRange().getRow();
//Insert the Name in the active row in the column 6
ss.getRange(r1, 6).setValue(name)
//Here I have other part of the code but is for copy rows to other sheet.
}
}
In column 6 have active data validation (not permit insert values that are not in the list of items).
Example: Charles, Oscar, Paul, Other. If I enter the names all in lower case do not enter. If the value entered is identical as "Charles" the value is entered.
Now, is possible these values may appear as a drop down list in the inputbox? I mean, the user can select from that list and then press Enter or Ok and the value insert into the cell.
Note: This is not a form. This is the spreadsheet.
Thanks,
UPDATED: 01/09/2014
function Historic(e) { //CopyRows
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
if (s.getName() == 'ISP1'){
var r = SpreadsheetApp.getActiveRange();
// Get the row and column of the active cell.
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
// Get the number of columns in the active sheet.
var colNumber = s.getLastColumn();
// Move row based on criteria in column 1, and if row is not the header.
if (colIndex == 1 && rowIndex != 1) { // 1 Is the Comment Column
//Call the Function Menu List
showNamePicker();
//Get values for the active row bases on the criteria.
var status = s.getRange(rowIndex, colIndex).getValue();
// --------------- Copy ROW only when someone modify the Column1 --------------------------
// Do nothing if criteria value is not actually changed to something else.
if (s.getName() != 'Historic') {
// The target sheet is the one with the same name as the criteria value.
var targetSheet = ss.getSheetByName('Historic');
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
//=====Copy the Row from ISP1 to Historic=======
s.getRange(rowIndex, 1, 1, colNumber).copyTo(target);
}
}
}
}
function showNamePicker() {
var app = UiApp.createApplication().setHeight(100).setWidth(180);
var handler = app.createServerHandler('setName');
var list = app.createListBox().setName('list').addChangeHandler(handler);
var names = ['Choose a name here','Charles', 'Oscar', 'Paul', 'Other'];
for(var n in names){
list.addItem(names[n]);
}
handler.addCallbackElement(list);
app.add(list);
SpreadsheetApp.getActive().show(app);
}
function setName(e){
var ssh = SpreadsheetApp.getActiveSpreadsheet();
var ss = ssh.getActiveSheet();
var r1 = ss.getActiveRange().getRow();
ss.getRange(r1, 6).setValue(e.parameter.list);
}
Function Historic: If someone modify the Column 1, the script will copy all data in the row that was modify to historic.
Needed:
The script should be insert the name in the column 6 for that row before the script copy the row to the historic.
Issue:
When someone modify the column 1 the user press ENTER and the new active row change because is not the same and the script not insert the name in the row that was modify.
For example:
I modify the A2 and press ENTER the new row is A3, and the script will insert the information into F3 and not in F2.
I tried to call the function before this line:
//Get values for the active row bases on the criteria.
var status = s.getRange(rowIndex, colIndex).getValue();
but I'm still newbie... I this is very easy but I can't get with the solution.
I will appreciate if you can help me.
EXAMPLE:
Change Cell A2 = ID#12578
The script should be insert the name in the column F2 and then copy all row include the F2 in the sheet called Historic. (The script is not inserting the name into F2 is inserting in F3
You will have to replace you Browser.inputBox with a dialog box that will hold a list box with the desired values.
You can build this dialog box either using UiApp or HTML service.
The problem will be that nothing will prevent to enter a value directly in the cell but it was already the case in your code...
You can store the list values wherever you want, in a hidden column, another sheet, another spreadsheet or in ScriptProperties or in the code itself... that's a matter of choice :-)
Edit : a small example using UiApp :
function showNamePicker() {
var app = UiApp.createApplication().setHeight(100).setWidth(120);
var handler = app.createServerHandler('setName');
var list = app.createListBox().setName('list').addChangeHandler(handler);
var names = ['Choose a name here','Charles', 'Oscar', 'Paul', 'Other'];
for(var n in names){
list.addItem(names[n]);
}
handler.addCallbackElement(list);
app.add(list);
SpreadsheetApp.getActive().show(app);
}
function setName(e){
var ssh = SpreadsheetApp.getActiveSpreadsheet();
var ss = ssh.getActiveSheet();
var r1 = ss.getActiveRange().getRow();
ss.getRange(r1-1, 6).setValue(e.parameter.list);
return UiApp.getActiveApplication().close();// close the Ui
}
Related
I'm a beginner of learning google script.
I need to submit data from one sheet to another using google script. When I click submitData, it should check whether it is previously entered data or not. If previously entered data, code must stop. If it is new entry, data mast sent to "output" sheet. Can anybody help me to figure out my error?
EDIT: I prepared a bio data format. I will share this google sheet among my school friends and asking to fill their details and click SUBMIT button. I want them to stop sending duplicate data. Their Identity Number is to be mention in "A3" cell. These data stored in "output" sheet. Identity number is stored in Column B. "A3" cell data match with Column B data in OUTPUT file and, if duplicate, msg prompt "duplicate".
Now When I run it , Data submitting to "output" sheet even DUPLICATE data entered in "A3" Cell.
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("input"); //Data entry Sheet
var datasheet = ss.getSheetByName("output");
var ttt = formSS.getRange("A3").getValue();
var values = ss.getSheetByName("output").getDataRange().getValues();
for (var i = 0; i < values.length; i++) {
var row = values[i];
if (row[1] == ttt) { //column B of the "output" sheet has project IDs (Unique Number)
SpreadsheetApp.getUi().alert('Duplicate data. you need to click update');
}
else
{
var values = [[formSS.getRange("E2").getValue(),
formSS.getRange("A3").getValue()]],
datasheet.getRange(datasheet.getLastRow()+1, 1, 1, 2).setValues(values);
}
}
}
The "error" is that there isn't anything that stop the script execution when row[1] == ttt is true. One possible fis is to add
return;
immediately after
SpreadsheetApp.getUi().alert('Duplicate data. you need to click update');
This function looks to see if an id matches with col B and if it does it updates and if it doesn't in adds a new row.
function submitOrUpdateData() {
const ss = SpreadsheetApp.getActive();
const ui = SpreadsheetApp.getUi();
const fsh = ss.getSheetByName("input");
const dsh = ss.getSheetByName("output");
const did = fsh.getRange("A3").getValue();//data id
const colB = dsh.getRange(1, 2, dsh.getLastRow(), 1).getValues();
let idx = colB.indexOf(did);
if (~idx) {
dsh.getRange(idx, 1, 1, 2).setValues([[fsh.getRange("E2").getValue(), fsh.getRange("A3").getValue()]]);//update
} else {
dsh.getRange(dsh.getLastRow() + 1, 1, 1, 2).setValues([[fsh.getRange("E2").getValue(), fsh.getRange("A3").getValue()]]);//new data
}
}
Bitwise Not (~)
Ok, title might be confusing. I mean, I'm confused just trying to make this work.
I essentially have 3 sheets.
The Search Sheet - Has a search box & macro button.
The Data Sheet - self explanatory.
The Target Sheet - Sorted into columns.
So, what I'm needing to happen is: when a user enters a value in the Search Sheet & hits the "go" button, it searches the Data sheet for any cells in column B that match. On a match, it modifies the matched cell so it won't match on another search, then copies the adjacent cell 'A' value into the first column of the Target Sheet, contuingin down the sheet & adding each match to the same column.
On a new search, the results will show in the 2nd column, etc...
Search1 = "L1" | Search 2 = "L3"
Data Sheet:
DataSheet
Result Sheet:
Result Sheet
Here's my shitty attempt at scripting it. I probably defined the wrong things & didn't define right things. I'm trying to wrap my head around it, but I think I've gotten into the deep end too fast.
function moveTest() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); //Spreadsheet
var source = ss.getSheetByName("Close"); //Input Sheet
var sourceData = ss.getSheetByName("Raw_Data"); //Data Sheet (List of all data)
var target = ss.getSheetByName("Pallet_Data"); //Target Sheet
var dataRange = data.getRange("B:B").getValues; //Range To Search on Data Sheet
var lastcolumn = target.getLastColumn(); //Last Column of Target
var searchval = [[source.getRange("A2").getValue()]]; //Search String
var targetRange = target.getRange("A"+(lastcolumn+1)+":C"+(lastcolumn+1)); //Define New Range n+1
//var rIndex = getRowIndex(); //row index of Data
//var cIndex = getColumnindex(); //column index of Data
while (dataRange has_data) { // For each row that has data in column B...
if (Bn = searchval) { // If B in row 'n' matches the search value
var rIndex = sourceData.getRowIndex(); // Define that row
var match = sourceData.getActiveCell // Defines B of matched row
var firstcell = rIndex.getRange(??) // Define cell A of that row
match.setValue('Moved'); // Change value of B in matched row so it won't match on new search
firstcell.copyTo(lastcolumn) //Copy Cell A of defined row into last column of target sheet
//Add next match to bottom of SAME Column then start NEW Column when function is run again.
}
}
Thanks
Solution:
Your script could look like this:
function cellMatch() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Data");
var sheet2 = ss.getSheetByName("Result");
var sheet3 = ss.getSheetByName("Search");
var lr = sheet1.getLastRow();
var data = sheet1.getRange(2,1,lr-1,2).getValues();
var lc = sheet2.getLastColumn()+1;
var key = sheet3.getRange("B1").getValue();
var matched = [["Search "+lc]];
for (var i=0; i<lr-1; i++) {
if (data[i][1] == key) {
var temp = [];
temp.push(data[i][0]);
matched.push(temp);
}
}
var result = sheet2.getRange(1,lc,matched.length);
result.setValues(matched);
}
This should take the search key from Search sheet, compare it with the Data sheet, and place the results into Result sheet.
Sample Data:
This is the result after executing the script twice, for L1 and L3.
Sheet1
Sheet2
I'm wondering if anyone could help me create a appscript for terminal invoicing and database purposes? When I click "SUBMIT" as a button in sheet 1 image, it must reflect line by line like in Sheet 2 image. (see sheet 1 image and sheet 2 image)
-after clicking submit it sheet 1 must auto clear
-when I input another set of data after clearing it needs to keep going down line per line in sheet 2
You can use the following code for that:
function myFunction() {
// declarations
var ss = SpreadsheetApp.getActive();
var sourceSheet = ss.getSheetByName('YOUR_SOURCE_SHEET_NAME');
var database = ss.getSheetByName('YOUR_DATABASE_SHEET_NAME');
// obtain common variables for each item
var dateOfOrder = sourceSheet.getRange('B1').getValue();
var dateOfDelivery = sourceSheet.getRange('B2').getValue();
var agent = sourceSheet.getRange('B8').getValue();
var customer = sourceSheet.getRange('B3').getValue();
// compute variables to initiate reading item rows
var rows = [];
var lastItemRow = sourceSheet.getLastRow();
var firstItemRow = 11;
var nItems = lastItemRow - firstItemRow + 1;
if (nItems < 1) return;
// get row-level information and append to database sheet
var itemNames = sourceSheet.getRange(firstItemRow, 1, nItems, 1).getValues();
var itemQuantities = sourceSheet.getRange(firstItemRow, 2, nItems, 1).getValues();
var itemPrices = sourceSheet.getRange(firstItemRow, 3, nItems, 1).getValues();
for (var i=0; i<nItems; i++) {
var itemName = itemNames[i][0];
var itemQuantity = itemQuantities[i][0];
var itemPrice = itemPrices[i][0];
database.appendRow([dateOfOrder, dateOfDelivery, agent, customer, itemName,
itemQuantity, itemPrice, itemQuantity * itemPrice]);
}
// clear source sheet
sourceSheet.getRange("B1:B8").clear();
sourceSheet.getRange("A11:H").clear();
}
The idea is to first obtain data from your source sheet (using getRange() along with getValue() or getValues()) and afterwards insert it using appendRow().
Finally, you can clear the range using the clear() method.
In order to create a button that calls this script, I suggest you check out this (Google spreadsheet - Making buttons that add data into cells into another sheet when pressed) other Stackoverflow answer. When assigning the script to the image, the name of it should be "myFunction" (without the quotes).
I maintain a spreadsheet workbook that tracks cake orders. Column headers (A–H) on the tracking sheet (named CakeOrders) are as follows:
(A1) Pickup Date, (B1) Client Name, (C1) Phone#, (D1) Text on Cake, (E1) Cake Flavor, (F1) Frosting Flavor, (G1) Fruit Filling, (H1) Link to PO
Each row of data below these headers corresponds to a new purchase order (PO) with a unique date, client name, etc. View CakeOrders sheet here.
On a second sheet (named Admin) within the same workbook, I have a table that runs match functions to find the Column# for each column header on CakeOrders. This was set up so that my script, which calls upon these Columns#s, will stay accurate even if I end up rearranging or adding Columns and new headers to the CakeOrders sheet—the script will always reference the appropriate column because of the match functions on the Admin sheet. View the Admin sheet here.
I currently have a script set up that allows me to generate new formatted spreadsheets (designed to be blank POs) directly from this spreadsheet. The script names the new sheet (or PO) based on data from within the selected row, and it adds a link to the new PO in Column H.
I would like to extend this script so that it also fills in select cells on the new PO based on information within its originating row.
Does anyone know a script that would allow me to populate specific cells of a new spreadsheet with data from a specific row of another?
Thanks!
Below is my current script, which creates a new spreadsheet with a name based on row content, stores the new sheet in a specific folder, and includes a link to the spreadsheet in the originating row.
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var customMenu = [{name: "Create PO", functionName: "Create"}];
ss.addMenu("Create PO", customMenu);
};
function Create() {
var sheet = SpreadsheetApp.getActive().getSheetByName("Admin");
var folderID = sheet.getRange("B2").getValue(); //These are column numbers
var templateID = sheet.getRange("B3").getValue();
var pickupDate = sheet.getRange("B4").getValue();
var clientName = sheet.getRange("B5").getValue();
var textOnCake = sheet.getRange("B6").getValue();
var cakeFlavor = sheet.getRange("B7").getValue();
var frostingFlavor = sheet.getRange("B8").getValue();
var fruitFilling = sheet.getRange("B9").getValue();
var POColumn = sheet.getRange("B10").getValue();
var ss = SpreadsheetApp.getActiveSheet(); // Back to CakeOrders sheet
var cell = ss.getActiveCell();
var row = cell.getRow(); //User has to pick the correct row
if (row <= 1){
Browser.msgBox("Cannot create new document within the header. Please select the row to which you'd like to add a new PO doc and run the script again.");
return;
}
try{
var pickupDateValue = Utilities.formatDate(ss.getRange(row,pickupDate).getValue(), "America/Chicago", "MMddYY");
}
catch(e) {
var pickupDateValue = ss.getRange(row,pickupDate).getValue();
}
var clientNameValue = ss.getRange(row,clientName).getValue();//getting the actual values now using column numbers from admin sheet
var textOnCakeValue = ss.getRange(row,textOnCake).getValue();
var cakeFlavorValue = ss.getRange(row,cakeFlavor).getValue();
var frostingFlavorValue = ss.getRange(row,frostingFlavor).getValue();
var fruitFillingValue = ss.getRange(row,fruitFilling).getValue();
var POColumnValue = ss.getRange(row,POColumn).getValue();
if (POColumnValue != ""){
Browser.msgBox("There is already content in the PO column. Please clear the contents and try again.");
return;
}
if (clientNameValue == "" || textOnCakeValue == "" || cakeFlavor == "" || frostingFlavor == ""|| fruitFilling == ""){
Browser.msgBox("Client Name, Text On Cake, Cake Flavor, Frosting Flavor, and Fruit Filling are required. Please enter a value in each of these columns and then try again.");
return;
}
var docName = "PO." + pickupDateValue + "." + clientNameValue;
var template = DriveApp.getFileById(templateID);
var destFolder = DriveApp.getFolderById(folderID);
var newDocID = template.makeCopy(docName, destFolder).getId();
var docLink = "https://docs.google.com/spreadsheets/d/" + newDocID;
ss.getRange(row,POColumn).setValue(docLink);
}
Thanks to Cooper for your help. Based on my situation, the best solution I found was to write a second script bound to the PO template (and its duplicates).
The first script, bound to the CakeOrders database, continues to function as it did originally: when triggered, it creates a copy of a PO template, names it based on origin row values, stores it in a designated folder, and stores a URL to the PO in the database.
The script I added to the PO template (below) allows the user to populate the body of the based on origin row values.
function onOpen() {
var spreadsheet = SpreadsheetApp.getActive();
var menuItems = [ {name: 'Fill from Cake Order Form', functionName: 'FillInOrder'}];
spreadsheet.addMenu('Fill In Order', menuItems);
}
//Creates drop down
function FillInOrder() {
var orderSheet = SpreadsheetApp.openByUrl( 'https://docs.google.com/spreadsheets/d/1jX0bT2suuA-4nrYyXNrA5s9gtqxV7hmcgxeb5zUxOeQ/edit#gid=0');
var cakeOrders = orderSheet.getSheetByName('CakeOrders')
var orderRow = Browser.inputBox('Fill from CakeOrders', 'Please enter the row number of the order to use' + ' (for example, "2"):', Browser.Buttons.OK_CANCEL);
if (orderRow == 'cancel') { return; } var rowNumber = Number(orderRow); if (isNaN(rowNumber) || rowNumber < 2 || rowNumber > cakeOrders.getLastRow()) {
Browser.msgBox('Error', Utilities.formatString('Row "%s" is not valid.', orderRow), Browser.Buttons.OK);
return;
}
//Prompts user for row
var pickupDate = cakeOrders.getRange(rowNumber,1).getValue();
var clientName = cakeOrders.getRange(rowNumber,2).getValue();
var textOnCake = cakeOrders.getRange(rowNumber,3).getValue();
var clientSheet = SpreadsheetApp.getActive().getSheetByName("Client");
//Gets values from source database
clientSheet.getRange("B8").setValue(pickupDate);
clientSheet.getRange("B4").setValue(clientName);
clientSheet.getRange("B12").setValue(textOnCake);
}
//Sets values in new PO
I would probably modify the column headings by making them single word Camel Code and use them as the keys for an associative array. So that when I get data from a row I build an array from a table that look like this:
PickupDate ClientName Phone CakeText CakeFlavor FrostingFlavor FruitFilling LinktoPO
4/15/2017 Bart Simpson 123-456-7899 Your Wierd Bart Dessert Cactus Frozen Spinach Tomato
4/16/2017 Bugs Bunny 987-654-3210 Happy Birthdays Bugs Carrot Carrot Carrots
To an array that looks like this:
var rowA = {PickupData:'4/16/2017',ClientName:'Bugs Bunny',Phone:'987-654-3210',CakeText:'Happy Birthday Bugs',CakeFlavor:'Carrot',FrostingFlavor:'Carrot', FruitFilling:'Carrots',LinkToPO:''}
Now when you go in to your PO form to fill in data you will be able to enter the data like this:
rowA[PickupData]
rowA[ClientName] etc...
The keys come from the column headers and the values come from which ever row your own. So it doesn't really matter what the order of the columns is. And later you can change the names of the variable by changing the names of the columns.
You can store the other information in a file as a string with file.setContent('string') and then take it out with file.getBlob().getDataAsString().split(delimiter) and split it with any delimiter that you choose. I often choose really wierd ones that you'll never expect to see anywhere like '|###|'.
Your final question was "Does anyone know a script that would allow me to populate specific cells of a new spreadsheet with data from a specific row of another?" and here's an answer to that:
function copyToNewSS()
{
var dstlocdict = {PickupDate:'A1',ClientName:'B2',Phone:'C3',CakeText:'D4',CakeFlavor:'E5',FrostingFlavor:'F6',FruitFilling:'G7',LinktoPO:'H8'}
var srcss = SpreadsheetApp.getActiveSpreadsheet();
var srcsht = srcss.getActiveSheet();
var dstss = SpreadsheetApp.openById('Insert ID of Destination Spreadsheet');
var dstsht = dstss.getSheetByName('PO');
var srcrow = srcsht.getActiveCell().getRow();
if((srcrow - 1)==0 || srcrow > srcsht.getLastRow()){SpreadsheetApp.getUi().alert('Error: Invalid Data Row');return;}
var srcdatR = srcsht.getDataRange();
var srcdatA = srcdatR.getValues();
var srcdatdict = {};
var srcnumcols = srcsht.getLastColumn();
var s = '{';
for(var i = 0;i < srcdatA[srcrow - 1].length; i++)
{
srcdatdict[srcdatA[0][i]]= srcdatA[srcrow-1][i];
if(i>0)s += ', ';
s += srcdatA[0][i] + ':' + srcdatA[srcrow-1][i];
}
myUtilities.dispStatus('Source Data Dictionary for Row ' + srcrow , s, 800, 400)
for(var key in srcdatdict)
{
dstsht.getRange(dstlocdict[key]).setValue(srcdatdict[key]);
}
}
If I want my Google Apps Script app get the current selected row in a spreadsheet, I use something like this:
function getCurrentRow() {
var currentRow = SpreadsheetApp.getActiveSheet().getActiveSelection().getRowIndex();
return currentRow;
}
But what if I want to get the first cell in this row (to put a comment in it), how do I proceed?
You can use offset to get a range relative to the active range.
function getFirstCellInRow() {
var sheet = SpreadsheetApp.getActiveSheet();
var activeCell = sheet.getActiveCell();
var firstCell = activeCell.offset(0, 1-activeCell.getColumn());
return firstCell;
}
Or just use getRange(A1notation), starting with what you had:
function getFirstCellInRow2() {
var sheet = SpreadsheetApp.getActiveSheet();
var currentRow = sheet.getActiveSelection().getRowIndex();
return sheet.getRange("A"+currentRow);
}
To write into the first cell in the row:
getFirstCellInRow().setValue('Tada');
There is a getCell() method you can use ( https://developers.google.com/apps-script/reference/spreadsheet/range#getCell(Integer,Integer) )
function getFirstCell() {
var firstCell= SpreadsheetApp.getActiveSheet().getActiveSelection().getCell(1,1);
return firstCell;
}
The following script will insert "My Info" in the first row available in column A.
function FirstCellColumnA() {
// replace with destination ID
var s = SpreadsheetApp.openById('spreadsheetID');
// replace with destination Sheet tab name
var ss = s.getSheetByName('sheetname');
// In Column A first ROW Available ss.getLastRow()+1 = find the
// first row available, 1 = start in column 1, 1 = rows to start,
// 1 = column where to put the data.
ss.getRange(ss.getLastRow() + 1, 1, 1, 1).setValue('My Info');
}
I hope this help you.