I have a spreahsheet A on Googlesheet with a range, list of cities for example.
I have a spreadsheet B on Googlesheet where I'd like to use Data Validation validating from the other file.
Goal
The purpose is to 'hide' or make it less available, if I use protect/hide any download to Excel removes the protection and it's not really protected.
I thought I could use a custom function to set dataValidation and it works but if I add a city in spreadsheet A it's not reflected in the previous cells.
Option 1
This works but the validation rule is not refreshed
var sheetA = SpreadsheetApp.openById("spread-a").getSheetByName("Data");
var currentSpreadsheet = SpreadsheetApp.getActive();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dataSheet.getRange('Cities').getValues()).build();
getActiveSpreadsheet().getActiveCell().setDataValidation(rule);
Option 2
Custom function doesn't work
*using it as Formula *=getList('Cities')**
function getList(name) {
var cell = SpreadsheetApp.getActiveSpreadsheet().getActiveCell();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dataSheet.getRange(name).getValues()).build();
cell.setDataValidation(rule);
return cell
}
Related
I have a script I am using to copy data from a form in a Google Sheet. ( Yes I know I can just use Google Forms but the client I am working with would like to keep it all in one Google Sheet)
Here is the code I am using now, and it works great. It does exactly what I want, but there is one field that an image is to be placed into. I have it set up so the user goes to "Insert" and then from there inserts an image into the cell. I can manually copy and paste the image from one sheet to another but when I run the script it will not copy over the image all the other data does copy over. Any help would be amazing. Here is the script. The image is in cell I3, as I said everything else works as expected.
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Form"); //Form Sheet
var datasheet = ss.getSheetByName("Data"); //Data Sheet
//Input Values
var values = [[formSS.getRange("E3").getValue(),
formSS.getRange("I3").getValue(),
formSS.getRange("E6").getValue(),
formSS.getRange("I6").getValue(),
formSS.getRange("E10").getValue(),
formSS.getRange("I10").getValue(),
formSS.getRange("E15").getValue(),
formSS.getRange("I15").getValue(),
formSS.getRange("E19").getValue(),
formSS.getRange("I19").getValue(),
formSS.getRange("E22").getValue(),
formSS.getRange("I22").getValue(),
formSS.getRange("E25").getValue(),
formSS.getRange("I25").getValue(),
formSS.getRange("E28").getValue()]];
datasheet.getRange(datasheet.getLastRow()+1, 1, 1, 15).setValues(values);
formSS.getRange('E3:E29').clearContent();
formSS.getRange('I3:I29').clearContent();
}
I have modified your script to fit the image in the Data sheet.
IMPORTANT: Unmerge the picture cells on the Form sheet and leave the background white. What the script will do is move the values from the Form to the Data (the background color will be moved as well)
The script will get the first value alone and put it in the first column, last row +1.
Now the last row is the one required (not the last +1), and then the script moves the image and inserts the other values as you were doing before.
The script:
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Form"); //Form Sheet
var datasheet = ss.getSheetByName("Data"); //Data Sheet
//Input Values
var values = [[formSS.getRange("E6").getValue(),
formSS.getRange("I6").getValue(),
formSS.getRange("E10").getValue(),
formSS.getRange("I10").getValue(),
formSS.getRange("E15").getValue(),
formSS.getRange("I15").getValue(),
formSS.getRange("E19").getValue(),
formSS.getRange("I19").getValue(),
formSS.getRange("E22").getValue(),
formSS.getRange("I22").getValue(),
formSS.getRange("E25").getValue(),
formSS.getRange("I25").getValue(),
formSS.getRange("E28").getValue()]];
// Get the first value and insert into the first column
var firstColumn = formSS.getRange("E3").getValue()
datasheet.getRange(datasheet.getLastRow()+1, 1,).setValue(firstColumn);
// Get the image and intert into the second column of the same row
var image = formSS.getRange("I3").moveTo(datasheet.getRange(datasheet.getLastRow(), 2));
// Get all the other values and insert them into the other columns of the same row
datasheet.getRange(datasheet.getLastRow(), 3, 1, 13).setValues(values);
formSS.getRange('E3:E29').clearContent();
formSS.getRange('I3:I29').clearContent();
}
I have a spreadsheet that I'm working on and I'm writing a code to copy select tabs and paste them as values/formatting into a new workbook that I can share with users and allow them to edit some fields. I need to move the data to a new sheet because my data sheet includes QUERY() functions that I don't want the users to be able to break, but I want the users to be able to filter and add notes as necessary. The final step that I can't get to work correctly is the banding/alternating colors format. They apparently don't save as backgroundcolor so that doesn't copy over.
function exportToDashboard() {
var fromSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var toSpreadsheet = SpreadsheetApp.openByUrl(
"myURL"
);
var fromSheet = fromSpreadsheet.getSheetByName("Contact Summary.DASH");
var toSheet = toSpreadsheet.getSheetByName("Contact Summary.DASH");
var fromRange = fromSheet.getRange("A1:E");
var values = fromRange.getValues();
// var banding = fromRange.getBandings();
var colors = fromRange.getFontColors();
var fontstyle = fromRange.getFontWeights();
var fontsizes = fromRange.getFontSizes();
var toRange = toSheet.getRange(1,1,values.length,values[0].length);
toRange.clearContent();
toRange.getBandings().forEach(function (banding) {
banding.remove();
});
toRange.setValues(values);
// toRange.applyRowBanding(SpreadsheetApp.BandingTheme.GREEN);
toRange.setFontColors(colors);
toRange.setFontSizes(fontsizes);
toRange.setFontWeights(fontstyle);
I want the source banding to carry over, but when I try and use the defined variable banding the applyRowBanding() function doesn't work and gives an error. I can use applyRowBanding(SpreadsheetApp.BandingTheme.GREEN) to apply the banding theme that I want, but it applies to the entire columns and not only to my data (where I want it to stay). Because alternating color formatting is not stored as a cell background color, I'm not able to copy that piece of format and paste it over either.
Really I just want to either copy or set the banding to my data only.
I have set up an item on my Google Form to set list based on values from a Google spreadsheet, code is:
function updateForm(){
var form = FormApp.openById("FormID");
var namesList = form.getItemById("ItemID").asListItem();
var ss = SpreadsheetApp.getActive();
var names = ss.getSheetByName("SourceSheetName");
var namesValues = names.getRange(2, 1, names.getMaxRows() - 1).getValues();
var List = [];
for(var i = 0; i < namesValues.length; i++)
if(namesValues[i][0] != "")
List[i] = namesValues[i][0];
namesList.setChoiceValues(List);
}
This works perfectly fine.
What I really want is to set each of the items listed on a spreadsheet to take you to a specific section on the Google Form.
I know this can be done manually on the Google Form by using 'Go To Section Based On Answer', but I was wondering if I can add a second column on the source spreadsheet to list the sections and amend my code accordingly?
EDIT - this is not a duplicate to another question which is mentioned below. The question asked previously had 2x choices set in the code. My question involves a set of responses set in a Googlesheet that auto populates the Google Form. What I really want is to auto set Go To Section Based on Answer automatically too. I hope this makes sense. Thanks
I'm trying to create an in-cell data validation drop down menu (in google spreadsheet) by using If/Else function.
Actually, I've 2 range of lists from which I only want to show one decided by a variable cell.
It sounds like this: If A1 is ABC then show range 1 in-cell dropdown & if A1 is XYZ then show range 2 in-cell dropdown.
Here's the code. Let me know what I'm doing wrong.
function dataval (){
var cell = SpreadsheetApp.getActive().getRange('B12');
if (cell=="Price") {
var cell = SpreadsheetApp.getActive().getRange('C12');
var range = SpreadsheetApp.getActive().getRange('D12:D19');
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(range).build();
cell.setDataValidation(rule);
};
if (cell=="Technical") {
var cell = SpreadsheetApp.getActive().getRange('C12');
var range = SpreadsheetApp.getActive().getRange('E12:E19');
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(range).build();
cell.setDataValidation(rule);
};
};
P.S.: I'm new to coding & this is my first ever ever post on SOF.
A problem with your code is the comparison cell=="Price". The variable cell is an object of class Range, not a string. To get the value it contains, you need cell.getValue(), so the comparison would be cell.getValue() == "Price".
You should also handle the event of the content of B12 changing. A simple way is to put the data validation code in onEdit trigger, and check whether the edit was to B12: e.g.,
if (e.range.getA1Notation() == 'B12') {
// change data validation
}
If the goal was simply to have a rule that forces inputs to be in one of two ranges, depending on another cell, that can be done without a script, using a custom formula with if and index. But that wouldn't provide a dropdown of values.
First off, here are two basic spreadsheets for what I am talking about:
Page one: https://docs.google.com/spreadsheets/d/1GZs_I9_beIO9xYBXatoxStRMmk9Aj3-UxPQpB9-iA-I/edit?usp=sharing
Page two: https://docs.google.com/spreadsheets/d/1R86_0SrAtyIJPAhMW0Ura-3gwOLn5l9u7Seuj2V0YCA/edit?usp=sharing
Essentially I am using a Google script to "update" the spreadsheet titled "The copy to update". This copy will automatically copy all of the pages from "The copy to pull updates from", delete the current pages on "The copy to update", and then rename the copied sheets back to what they were before. This means that any changes I make to "The copy to pull updates from" will automatically be updated on the other spreadsheet without having to redistribute the spreadsheet.
When the button is pressed on the "Update page" sheet the pages are successfully transferred across. The changes are successfully "updated" on the to update spreadsheet. However, the page updated first in the code has errors. Any cell with a formula that acquires data from another sheets returns "#REF!" with the error "Unresolved sheet name 'Insert sheet name here'." This means that the formula/cell can not see the newly copied sheet from the script. I can remedy this situation by clicking on any cell afflicted by this and pressing enter - Essentially "refreshing" the cell. However I am doing this on a project with 100+ cells like this and I only want to have to press one button to be able to do this.
Should I try and solve this issue using script, or change my method of updating the Spreadsheet pages a different way? Thanks to all help in advance!
Here is the script that I am using:
<code>
function Update() {
//Sets the ID of the page to update from
var ID = "1R86_0SrAtyIJPAhMW0Ura-3gwOLn5l9u7Seuj2V0YCA"
//Pulls the correct sheet using the ID
var source = SpreadsheetApp.openById(ID);
//Identifies the active spreadsheet in use to update. (The spreadsheet you pressed "Update" on)
var destination = SpreadsheetApp.getActiveSpreadsheet();
//Sheet to pull and copy to the current spreadsheet
var sheet1 = source.getSheetByName("1");
//Copying the sheet accross
sheet1.copyTo(destination);
//Identifies the old copy of the sheet
var sheet1 = destination.getSheetByName('1');
//Deletes the old copy of the sheet
destination.deleteSheet(sheet1);
//Gets the new copy of the sheet
var sheet1 = destination.getSheetByName('Copy of 1');
//Renames the new copy of the sheet
sheet1.setName("1")
//Repeating the same code with page 2
//Sheet to pull and copy to the current spreadsheet
var sheet1 = source.getSheetByName("2");
//Copying the sheet accross
sheet1.copyTo(destination);
//Identifies the old copy of the sheet
var sheet1 = destination.getSheetByName('2');
//Deletes the old copy of the sheet
destination.deleteSheet(sheet1);
//Gets the new copy of the sheet
var sheet1 = destination.getSheetByName('Copy of 2');
//Renames the new copy of the sheet
sheet1.setName("2")
//Repeating the same code
}
</code>
This is related to Force formula refresh through Apps Script
I'm having the exact same problem. Most of my formulas are =ArrayFormula formulas in the first or second row. My solution iterates through all cells in the first two rows of a given Spreadsheet and reevalutes any formulas.
This could probably be cleaned up to only modify the cell if it is a formula (rather than resetting the text value for non-formulas). It could also be modified to run over an entire Spreadsheet by changing the assigned range.
You might run this function on the sheet after it has been copied to the new location, or you could call myFunction while the desired sheet is active.
function updateFormulasTwoRows(given_sheet) {
var last_col = given_sheet.getDataRange().getLastColumn();
var range = given_sheet.getRange(1,1,2,last_col);
// contains empty strings or cell formulas
var formulas = range.getFormulas();
// contains text, formula errors, formula output
var contents = range.getValues();
// formulas[0][0].length > 1 ==> is a formula
for (var r = 0; r < range.getHeight(); r++) {
for (var c = 0; c < range.getWidth(); c++) {
var cell = range.getCell(r+1,c+1);
// clear only the contents, not notes or comments or formatting.
cell.clearContent();
if (formulas[r][c].length > 1) {
// cell was a formula, so insert the formula back in place
cell.setValue(formulas[r][c]);
} else {
// cell was not a formula, so insert the text content back in place
cell.setValue(contents[r][c]);
}
}
}
}
// run this after selecting a sheet to reevalute formulas on
function myFunction() {
var curr_sheet = SpreadsheetApp.getActiveSheet();
updateFormulasTwoRows(curr_sheet);
}
Building on #bryan's answer above, I found a more efficient version of the code is the following, which performs the clearContent() and setValue() calls at the range level, rather than on each individual cell, thus saving a lot of calls to the back-end.
var updateFormulasAllRows = function updateFormulasAllRows(sheet) {
var range = sheet.getDataRange();
var formulas = range.getFormulas();
var contents = range.getValues();
var rangeWidth = range.getWidth(), rangeHeight = range.getHeight();
for (var r = 0; r < rangeHeight; r++) {
for (var c = 0; c < rangeWidth; c++) {
if (formulas[r][c].length > 1) {
contents[r][c] = formulas[r][c];
}
}
}
range.clearContent().setValues(contents);
};
This also changes the code to run over all the rows of the spreadsheet as suggested as an improvement.