How to copy data validation in a relative way, specifically list from range (with or without scripts) Google Sheets - spreadsheet

I have created a spread sheet to track appointments. Within this spread sheet I have dynamic dependent drop down lists, so the choice from list 1 will populate the options in list 2. This is as follows:
Cell C2: Client - Client 1 or Client 2. (this is for the use of the example, the actual lists will expand.)
If cell C2 = Client 1 then the address drop down is as below:
Cell C3: Address - Address 1 or Address 2.
If cell C2 = Client 2 then the address drop down is as below:
Cell C3: Address - Address 3 or Address 4.
The data validation for the client list is simple because this is constant and can be copied from column to column. The data validation for the dependent address list, however, can not be copied across multiple columns as it will always refer to column C and lose connection with the relative client list.
The actual data validation for the cell C3 (Address List) is below:
Cell Range = 'DIARY (V-2.1)'!C3
Criteria = 'DIARY (V-2.1)'!C53:C55
The cells C53:C55 are populated by a filter formula which will sort the relevant addresses dependent on the choice of client in cell C2, this in turn populates the address list in C3.
It may be worth noting that I have 10 sets of these appointment slots per column (10 per day) so I have used a filter function for each of these separate appointments so they work independently, but even this is tedious so my need is to be able to copy the column (or just the data validation) from column C onward and have it stay relative to the filter functions in that column.
Please see the below link to the example spreadsheet and this will all make sense! In the example I have copied column C to column D and the data validation for the address list has detached for all ten appointment slots. (permission is free for all to edit.)
https://docs.google.com/spreadsheets/d/1sOlQEzG1D29RaY86YeR1Da--c8t94J-ZAGjv52U4dsY/edit#gid=1950191921
Note: These cells must be drop down lists - list from range - for the functionality of this specific spreadsheet.
If anyone can help with this it would be MASSIVELY appreciated as I have diligently scoured the forums and cannot find a solution. I did see this video (which is way over my head) that seems to accomplish this using java script:
https://www.youtube.com/watch?v=ZiYnuZ8MwgM&feature=youtu.be

Google Sheets does not currently have a built-in solution for copying/filling data validation references or formulas relatively. But somebody already wrote a nice script in this Google Docs forum post. To avoid just a link as an answer, I'm going to copy in the script and instructions here. Credit to AD:AM from Google Docs forum.
How to use their script:
Select a range of cells across which you want to copy a data validation rule, relatively
From the Validation+ custom menu, select the appropriate option (all references relative, columns absolute, or rows absolute)
The validation of the upper-left cell will be copied to the rest of the range
Link to original solution's example Google Sheets with script already included - you can save your own copy and then start using.
Or to recreate from scratch, here is the script.
function onOpen()
{
SpreadsheetApp.getActiveSpreadsheet().addMenu
(
"Validation+",
[
{name: "Copy validation (all relative references)", functionName: "copyValidation"},
{name: "Copy validation (relative rows, absolute columns)", functionName: "copyValidationColumnsAbsolute"},
{name: "Copy validation (absolute rows, relative columns)", functionName: "copyValidationRowsAbsolute"}
]
);
}
function copyValidation(rowsAbsolute, columnsAbsolute)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var r = ss.getActiveRange();
var dv = r.getDataValidations();
var dvt = dv[0][0].getCriteriaType();
if (dvt != SpreadsheetApp.DataValidationCriteria.VALUE_IN_RANGE) return;
var dvv = dv[0][0].getCriteriaValues();
Logger.log(dvv);
for (var i = 0; i < dv.length; i++)
{
for (var j = i ? 0 : 1; j < dv[0].length; j++)
{
dv[i][j] = dv[0][0].copy().withCriteria(dvt, [dvv[0].offset(rowsAbsolute ? 0 : i, columnsAbsolute ? 0 : j), dvv[1]]).build();
}
}
r.setDataValidations(dv);
}
function copyValidationRowsAbsolute()
{
copyValidation(true, false);
}
function copyValidationColumnsAbsolute()
{
copyValidation(false, true);
}

If you only need the relative copy for a single sheet, you can produce an ods with OpenOffice or LibreOffice that has a relative validation. This is done by removing the $ signs. If you then open load that sheet to your google drive and allow it to be converted to a google sheet, data validation range will be relative if you copy it anywhere in the same sheet. It is not relative if you copied it to another sheet in the same workbook or other google spreadsheets.
For example, if you make the validation for A7 to be the three cells to the right, you'll have something like follows:
Once you save it without the $ it is relative. Then when you upload it you have a sheet with relative validations.

Related

Google Sheets Script - save as PDF - Get Name from Cell

Ok, I'm 99% there thanks to a lot of other posts about how to do this.
What am I doing?
I have a google form. When that form is completed and the answers are in the respective google sheet I have another tab that has a template (with a bunch of formulas) that auto-populates pay rates for people. The first formula is the name and it is drive off of the Form Responses tab. The following script hides all other sheets, saves the one tab I want to a PDF, in the folder that I want (then unhides the other sheets).
The problem
When I run this as a test it works perfectly. The PDF that drops into the folder is named with the output from the cell E5 (which is a formula) pulling the person's name. However when I set the trigger to when a form answer comes in then everything is right (all the data on the sheet is right) just the name of the file is showing as "Yes". I'm so confused as to why it is "Yes". If I run the script right afterwards it is the name of the person from the cell E5..... Here is my code.
Is the trigger to fast to pull the response? I don't think it can be as the output on the PDF is right.
function topdf() {
var foldersave=DriveApp.getFolderById('1dSOK6bBCRyEO0_fTuuMFH9sNa4wAWYW8');
var d= new Date();
var request = {
"method": "GET",
"headers":{"Authorization": "Bearer "+ScriptApp.getOAuthToken()},
"muteHttpExceptions": true
};
var key='1-e8dhOOZ5zwfeIBSTSH7yFNKgxVTxwqZvqcTNtQUQrA';
var fetch='https://docs.google.com/spreadsheets/d/'+key+'/export?format=pdf&size=letter&portrait=false'
var ss= SpreadsheetApp.getActiveSpreadsheet();
var sheets=ss.getSheets()
var name=ss.getRange("E5").getValue()
sheets[0].hideSheet()
sheets[1].hideSheet()
sheets[2].hideSheet()
sheets[3].hideSheet()
sheets[4].hideSheet()
sheets[5].hideSheet()
sheets[6].hideSheet()
var pdf = UrlFetchApp.fetch(fetch, request);
pdf = pdf.getBlob().setName(name);
var file = foldersave.createFile(pdf)
sheets[0].showSheet()
sheets[1].showSheet()
sheets[2].showSheet()
sheets[3].showSheet()
sheets[4].showSheet()
sheets[5].showSheet()
sheets[6].showSheet()
}
You're calling getRange() E5 from Spreadsheet ss, which may or may not be the sheet you're looking to get the range from. E5 may be yes from an another sheet. Try
ss.getSheetByName('Sheet1').getRange('E5')

Data Mapping Between Excel Files and Third Part Applications

I'm working on a macro which named "MasterTool". All of macro code will be in this "MasterTool". This tool's main role is taking value of certain string name from excel sheet (input sheet) and write this values another excel sheet (output sheet) for same string name.
Additionally there's 2 different term I would like to describe you from now to understand easily.
Input Sheet
Excel file which stores some specific informations (E.g. Vehicle Height : 3m ) ( One of the cell has my string value: Vehicle Height and adjacent next cell has it's value 3m )
Output Sheet
This is also an excel sheet like report page which contains also specification information which comes from Input Sheet.
I wonder is it common usage data mapping methods in Excel VBA ?
My first attempt is:
Naming cells in Input Sheet like that: strCellVehicleHeight and I'm writing string name: Vehicle Height, also naming cell of this feature's value strCellVehicleHeightValue and I'm writing 3.
On output sheet I named cells same and then mapping via cell names. It's a bit hard way to use I think.
Isn't there more possible ways or other formats like XML JSON etc. I would be glad if you help me about this situation.

Google Spreadsheet API Query Tabs

Can I query my spreadsheet tabs via tab index instead of the tab title or tab id?
https://sheets.googleapis.com/v4/spreadsheets/{my sheet id}/values/'Hero Video Copy Section'?key={secret code}
'Hero Video Copy Section' is the title of the tab, but I want to find the tab via index.
You may refer with this SO thread(quite old question). Given example is if the row number is in A1, and the column number is in A2:
=OFFSET(A1;A1-1;A2-1)
=INDIRECT("R"&A1&"C"&A2)
=INDEX(A1:400000;A1;A2)
Also, you can check this documentation about Google Apps Script which uses an array to log the name of the second sheet.
// The code below will log the name of the second sheet
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
if (sheets.length > 1) {
Logger.log(sheets[1].getName());
}

Finding last written row in Google Spreadsheet API

Is there any way to find the last row you have written in a google spreadsheet in Java?
I tried to do that by having a variable which I keep in another file and I update that every time I do another writing. Is there any other way?
Finding last written row in Google Spreadsheet API
I'll give you a concept first using REST calls but you'll have to apply that in Java.
Exceed the range of cells where you're writing.
So to find last written row between cells A1:A10, use the range A1:A11 or A1:B (using B means all the rows in cell A will be traversed).
Fetch a range of cells, using GET. Parse the response result. And get the length of the parsed values. The length will always indicate the last row since Sheetsv4 ignores blank/empty cells.
So example I have a range of cells between A1:A10. I wrote "hello" in A10. Following the concepts above I do this:
..
xhr.open('GET', 'https://sheets.googleapis.com/v4/spreadsheets/'+myspreadsheetId+'/values/Sheet1!A1:A10);
..
xhr.onload = function (oEvent) {
arrayBuffer = xhr.response;
myArray = JSON.parse(arrayBuffer);
console.log("last row is " + myArray.values.length)
.. //output is 'last row is 10'
This part of my XHR request returns 10. Now I know that the last written row in my sheet is A10.
To do this in Java use the solution based on this SO thread.
mService.spreadsheets().values().get("ID_SHEET", "Sheet1!A1:B").execute();
Also check this thread about writing on data cells using Java. I think it offers additional insight as well.

Getting a merged cell width on Google Spreadsheet API

I'm using the Google Spreadsheet API to convert a document containing workers shifts into event calendars.
The only problem is that shifts are represented by merged cells according to days and hours (with days and hours as rows and different work slots as cols), and when I read a certain cell, which is merged and spans over 6 cells, I cannot get the cells certain width or its merged area.
For example:
If I try to get the values between (4C:4E) I will get "Bob, , ," and not "bob,bob,bob", and I cannot even find a way to know how many cells "bob" take.
Do you guys know how can I know how many cells the merged one spread to? Or at least it's total width.
Thanks in advance!
Download from google drive as html, see:
Get FontStyle information from Google spreadsheet into appengine
Drive driveService = new Drive.Builder(TRANSPORT, JSON_FACTORY, credential).build();
File file = driveService.files().get(this.spreadsheetKey).execute();
String downloadUrl = file.getExportLinks().get("application/pdf");
downloadUrl = downloadUrl.replaceFirst("exportFormat=pdf", "exportFormat=html");
downloadUrl = appendWorksheetGid(downloadUrl); // adds "&gid="+sheetGid
HttpResponse resp =
driveService.getRequestFactory().buildGetRequest(new GenericUrl(downloadUrl))
.execute();
System.out.println("downloadUrl:"+downloadUrl);
InputStream fileContent = resp.getContent();
extractStyleFromHtml(fileContent,downloadUrl);
extractStyleFromHtml uses Jsoup - (Jsoup impressed me)
It's not possible via spreadsheet API. I was looking for same. Google admits the same in their documentation.
The literal value of the cell element is the calculated value of the
cell, without formatting applied. If the cell contains a formula, the
calculated value is given here. The Spreadsheets API has no concept of
formatting, and thus cannot manipulate formatting of cells.
Related question:
Set cell format in Google Sheets spreadsheet using its API & Python
One alternate way can be to download the doc in excel format programmatically. It will contain formatting information. Then using excel API to extract the info.