Submit values from userform (selected cells) to another google spreadsheet and then find them (search), modify and post it again.
I have a source sheet (userform), I need to get values from the selected cells and ranges, submit the values to the destination sheet (another spreadsheet) using ID.
I have attached a Screenshot explaining with color code where the data should go. https://i.stack.imgur.com/Yrfje.jpg
[SCREENSHOT][1]
Also Shared two spreadsheets with actual data (Userform and Datasheet) for your reference
https://docs.google.com/spreadsheets/d/1NY_ckzEWxU7DCGro5tTqzpiOi6iG5PAQFxpZg0OKodY/edit?usp=sharing
https://docs.google.com/spreadsheets/d/1QL0jaNts2YRkZTlxmS0bk7V1fVVHBsJFmxS5C05PEmA/edit?usp=sharing
Please help to enhance this below code (thanks to #[Yuri Khristich][2])
var ss = SpreadsheetApp.getActiveSpreadsheet();
var form_sheet = ss.getSheetByName('UserForm');
var data1 = form_sheet.getRange(['c3:c8']).getValues().flat();
var [num, date, name, id, project,group] = data1;
var data2 = form_sheet.getRange('b10:e20').getValues();
var data_sheet = ss.getSheetByName('DataSheet');
var nums = data_sheet.getRange('a:a').getValues().flat();
var row = nums.indexOf(num);
if (row < 0 ) {
var new_row = [num, date, name, id, project, group, JSON.stringify(data2)];
data_sheet.appendRow(new_row)
} else {
var range = data_sheet.getRange('g' + ++row);
range.setValue(JSON.stringify(data2));
}
}
function searchRecord() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var form_sheet = ss.getSheetByName('UserForm');
var num = form_sheet.getRange('b1').getValue();
var data_sheet = ss.getSheetByName('DataSheet');
var nums = data_sheet.getRange('a:a').getValues().flat();
var row = nums.indexOf(num);
if (row < 0) {
ss.toast('Nothing was found')
return;
}
row++;
var data1 = data_sheet.getRange('a' + row + ':g' + row).getValues().flat();
var data2 = JSON.parse(data1.pop());
form_sheet.getRange('c3:c8').clearContent().setValues(data1.map(x => [x]));
form_sheet.getRange('b10:e20').clearContent().setValues(data2)
}
// Function to submit the data to DataSheet sheet
function oldsubmitData() {
var myGooglSheet= SpreadsheetApp.getActiveSpreadsheet(); //declare a variable and set with active google sheet
var shUserForm= myGooglSheet.getSheetByName("UserForm"); //delcare a variable and set with the User Form worksheet
var datasheet = myGooglSheet.getSheetByName("DataSheet"); ////delcare a variable and set with the DataSheet worksheet
var namedRanges = SpreadsheetApp.getActiveSheet().getNamedRanges();
if (namedRanges.length > 1) {
Logger.log(namedRanges[0].getName());
}
//to create the instance of the user-interface environment to use the messagebox features
var ui = SpreadsheetApp.getUi();
// Display a dialog box with a title, message, and "Yes" and "No" buttons. The user can also
// close the dialog by clicking the close button in its title bar.
var response = ui.alert("Submit", 'Do you want to submit the data?',ui.ButtonSet.YES_NO);
// Checking the user response and proceed with clearing the form if user selects Yes
if (response == ui.Button.NO)
{return;//exit from this function
}
//Validating the entry. If validation is true then proceed with transferring the data to DataSheet sheet
// if (validateEntry()==true)
{
var blankRow=datasheet.getLastRow()+1; //identify the next blank row
datasheet.getRange(blankRow, 1).setValue(shUserForm.getRange("C3").getValue()); //Date
datasheet.getRange(blankRow, 2).setValue(shUserForm.getRange("C4").getValue()); //UserForm Number
datasheet.getRange(blankRow, 3).setValue(shUserForm.getRange("C5").getValue()); //Student Name
datasheet.getRange(blankRow, 4).setValue(shUserForm.getRange("C6").getValue()); //ID
datasheet.getRange(blankRow, 5).setValue(shUserForm.getRange("C7").getValue()); //Project
datasheet.getRange(blankRow, 6).setValue(shUserForm.getRange("C8").getValue()); //Group Name
//I stuck here, get values from moving row (E,13 to 16)
//datasheet.getRange(blankRow, 8).setValue(shUserForm.getNamedRanges("TotalPresent").getValue());// TotalPresent
//datasheet.getRange(blankRow, 8).setValue(shUserForm.getNamedRanges("SoundRoomDay").getValue());// SoundRoomDAy
//datasheet.getRange(blankRow, 9).setValue(shUserForm.getNamedRanges("GroupDay").getValue());// GroupDay
//datasheet.getRange(blankRow, 10).setValue(shUserForm.getNamedRanges("TotalDays").getValue());// TotalDays
// date function to update the current date and time as submittted on
datasheet.getRange(blankRow, 12).setValue(new Date()).setNumberFormat('yyyy-mm-dd h:mm'); //Submitted On
//get the email address of the person running the script and update as Submitted By
datasheet.getRange(blankRow, 13).setValue(Session.getActiveUser().getEmail()); //Submitted By
var ss = SpreadsheetApp.getActiveSpreadsheet();
var form_sheet = ss.getSheetByName('UserForm');
var num = form_sheet.getRange('c3').getValue();
var data = form_sheet.getRange('b10:e20').getValues();
var datasheet = ss.getSheetByName('DataSheet');
var nums = datasheet.getRange('a:a').getValues().flat();
var row = nums.indexOf(num);
if (row < 0) return;
var range = datasheet.getRange('g' + ++row);
range.setValue(JSON.stringify(data));
ui.alert(' "New Data Saved - StudentID #' + shUserForm.getRange("C5").getValue() +' "');
}
}```
-code by-----------------------
[1]: https://i.stack.imgur.com/Yrfje.jpg
[2]: https://stackoverflow.com/users/14265469/yuri-khristich
I guessed your goal is as follows.
You want to copy the values from UserForm of PRINTNOTE_A to DataSheet of WB-Datasheet 2.
You want to copy the values of cells C3,C7,C8,D8,D6,D4,E8,E19,E20,E21,E22 and B10:E18 of UserForm sheet to the same row.
You want to search the column "A" of DataSheet sheet using the value of cell B1 of UserForm sheet, you want to put the values in the same row.
You want to achieve this using Google Apps Script.
By guessing your question, I propose a sample script as follows.
In order to retrieve the values from the distributed cells, in this sample script, I used Sheets API.
Sample script:
Before you use this script, please enable Sheets API at Advanced Google Services.
From your script, this script is used as the container-bound script of PRINTNOTE_A. So, please copy and paste this script to the script editor of PRINTNOTE_A Spreadsheet.
function sample() {
const dstSpreadsheetId = "###"; // Please set the destination Spreadsheet ID (WB-DataSheet_B).
const dstSheetName = "DataSheet";
const srcSheetName = "UserForm";
// Retrieve values from source sheet and create an array and search value.
const srcSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const ranges = ["B1", "C3", "C7", "C8", "D8", "D6", "D4", "E8", "E8", "E19", "E20", "E21", "E22", "B10:E18"];
const [search, ...values] = Sheets.Spreadsheets.Values.batchGet(srcSpreadsheet.getId(), { ranges: ranges.map(r => `'${srcSheetName}'!${r}`) }).valueRanges.flatMap(({ values, range }) => {
if (range.includes("B10:E18")) return values.flat();
return values[0][0];
});
// Put the array to the destination sheet using the search value.
const dstSheet = SpreadsheetApp.openById(dstSpreadsheetId).getSheetByName(dstSheetName);
const range = dstSheet.getRange("A2:A" + dstSheet.getLastRow()).createTextFinder(search).findNext();
if (range) {
dstSheet.getRange(range.getRow(), 2, 1, values.length).setValues([values]);
} else {
dstSheet.getRange(dstSheet.getLastRow() + 1, 1, 1, values.length + 1).setValues([[search, ...values]]);
}
}
From your replying of but new values are not getting submitted in the next blank row., I updated my proposed answer. In the current script, when the search value is not found, the values are appended to the destination sheet.
Note:
This sample script is for your provided 2 Spreadsheets. And, I tested this script using your provided Spreadsheets. So when you changed the Spreadsheet and your actual Spreadsheets are different from your provided sample Spreadsheet, this script might not be able to be used. Please be careful about this.
References:
Method: spreadsheets.values.batchGet
createTextFinder(findText) of Class Range
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 (~)
Source:
Destination:
Hi everyone,
I have 2 google sheets, Source & Destination. I want to copy a range of data from Source sheet to Destination sheet by using google apps script. So the data should appear at the last row of the Destination sheet. This is my code:
function copyInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Source");
var pasteSheet = ss.getSheetByName("Destination");
// get source range
var source = copySheet.getRange(3,1,1,10);
// get destination range
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,1,1,10);
// copy values to destination range
source.copyTo(destination);
}
Seems like the script only allow me to do the copying within one google sheet (different tab) instead of 2 different google sheet. May I know how should I modified it so that the script able to find my destination google sheet and paste the data at the last row? Any help will be greatly appreciated!
Edit
I tried to use onEdit to triggered the script, however it seems like not working. Below is my script:
function onEdit(e) {
if (e.range.columnStart == 11 && e.range.rowStart == 3){
var ss = SpreadsheetApp.getActiveSpreadsheet();
const id ='1r5Hygl5ysahMi6DQ3duDR5L8c4aGX_0CJba7lXxnejw';
var copySheet = ss.getSheetByName("Sheet1");
var pasteSheet = SpreadsheetApp.openById(id).getSheetByName("Sheet1");
if (e.value == 'Submit'){
var source = copySheet.getRange(3,1,1,10);
const values = source.getValues();
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,1,1,10);
destination.setValues(values);
}
}
}
Source:
https://docs.google.com/spreadsheets/d/1jnOvE-Dc7y9o7GsgN9fjOXZWlUCwiJayugX5q4Y3CA0/edit#gid=0
Destination:
https://docs.google.com/spreadsheets/d/1r5Hygl5ysahMi6DQ3duDR5L8c4aGX_0CJba7lXxnejw/edit#gid=0
Use Range.getValues() and Range.setValues()
const id ='ID of paste Spreadsheet';
var pasteSheet = SpreadsheetApp.openById(id).getSheetByName("Destination");
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,1,1,10);
const values = source.getValues();
destination.setValues(values);
The method getSheetByName is used to define a sheet within a spreadsheet. To define a specific spreadsheet, you should use openById and associate the spreadhseet ID (https://docs.google.com/spreadsheets/d/{spreadsheet ID}/edit).
Define your source sheet as:
var copysheet = SpreadsheetApp.openById('enter id for Source').getSheetByName('Sheet 1')
Define your destination sheet as:
var pastesheet = SpreadsheetApp.openById('enter id for Destination').getSheetByName('Sheet 1')
If I understand correctly, your goal is the following:
/* Every time a user sets the value of cell K3 in source spreadsheet
to "submit". Copy all the values of row 3 and paste them into the
destination sheet under the last row. Then delete the source values
and set the value of K3 to "Clear" again. */
You need a installed trigger and a function to copy the values when triggered. So lets do that step by step.
Example:
First lets create a script that is bound to your source SS. Let's edit your copyInfo() function so that it takes the destination spreadsheet Id as parameter.
function copyTo(destinationSSId) {
// Open source SS at tab named "Source"
let copySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source");
// Open destination SS at tab named "Destination"
let pasteSheet = SpreadsheetApp.openById(destinationSSId).getSheetByName("Destination");
// Get source values
let sourceValues = copySheet.getRange(3, 1, 1, 10).getValues();
// Set values to destination range
pasteSheet.getRange(pasteSheet.getLastRow() + 1, 1, 1, 10).setValues(sourceValues);
// Log the pasted values from the last row
console.log("Last row pasted: " + pasteSheet.getRange(pasteSheet.getLastRow(), 1, 1, 10).getValues()[0]);
}
Make a function to clear the source values and reset the "form".
function clearSubmission() {
let copySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source");
copySheet.getRange(3, 1, 1, 10).clearContent()
copySheet.getRange(3, 11, 1, 1).setValue("Clear");
console.log("Source submitted and cleared.")
}
Set up the function to trigger.
function myTriggeredFunction(e) {
console.log(JSON.stringify(e.range), e.value)
if (e.range.columnStart == 11 && e.range.rowStart == 3) {
if (e.value == 'Submit') {
let destinationSSId = '{YOUR DESTINATION SS ID}';
copyTo(destinationSSId);
clearSubmission();
}
}
}
Install the trigger as "From spreadsheet - On edit" to run the function myTriggeredFunction by going to the "Triggers" tab in your project.
Say I have a spreadsheet in google sheets with three columns EMAIL, TOPIC and TIME where I´d like to send an email to each of the EMAILs in the spreadsheet containing a link to a google form that has a question asking the preferred TIME for the given TOPIC in the spreadsheet. Is it doable to create such individualized google forms based on sheets?
The first thing that should be done is creating the forms and sending the emails. To do that, I wrote a function that loops through all the rows in your sheet (called "Sheet1", change it according to your preferences), creates a form for each row and sends it to the emails found in column A (in the sheet I've been working on, data starts at row 2 and columns are: A - email / B - topic / C - time):
function sendMails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var values = ss.getSheetByName("Sheet1").getDataRange().getValues();
for(var i = 1; i < values.length; i++) {
var email = values[i][0];
var topic = values[i][1]
var formName = email + " - " + topic;
var form = FormApp.create(formName);
var url = form.getPublishedUrl();
form.setTitle(formName);
form.setDestination(FormApp.DestinationType.SPREADSHEET, ss.getId()); // This line bounds the created form to your spreadsheet so that responses will be written in here, in an automatically created sheet
// You can set another destination spreadsheet if you don't want all these sheets created in your spreadsheet
var question = form.addDateTimeItem();
question.setTitle("Please provide a preferred time for your assigned lecture on " + topic);
var userEmail = form.addCheckboxItem();
userEmail.setChoices([userEmail.createChoice(email)]);
var topicName = form.addCheckboxItem();
topicName.setChoices([topicName.createChoice(topic)]);
var checkBoxValidation = FormApp.createCheckboxValidation()
.requireSelectExactly(1)
.build();
userEmail.setValidation(checkBoxValidation);
topicName.setValidation(checkBoxValidation);
MailApp.sendEmail(email, topic, url);
}
}
Next, you need to install an onFormSubmit trigger in your spreadsheet. You can do this to run a function that will write the preferred TIME the user chose in the form every time a form is submitted. To create the trigger, run this function in your script, only once:
function createOnFormSubmitTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('writeTime')
.forSpreadsheet(ss)
.onFormSubmit()
.create();
}
Finally, below is the function that the trigger trigs when a form is submitted. It looks for the row where topic and email match the ones coming from the form, and sets the time:
function writeTime(e) {
var response = e.values;
var time = response[1];
var email = response[2];
var topic = response[3];
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var values = sheet.getDataRange().getValues();
for(var i = 1; i < values.length; i++) {
if(values[i][0] == email && values[i][1] == topic) {
sheet.getRange(i + 1, 3).setValue(time);
}
}
}
I hope this is useful to you.
I have a Google Sheet (example here) with two sheets - Form and Data. I have the Form sheet set up so that entries can be manually input, and once the UPDATE button is clicked, the data is sent to the bottom of the Data sheet as a new row, and the Form fields are cleared, ready for the next input.
I'm trying to take this one step further - if the UPDATE button is clicked, and the Part Number field contains a value which already exists in Column A of the Data sheet (meaning it has already been entered at some point), a new row should not be added, but the existing row with the matching Part Number should be updated with the newly submitted data instead, leaving any unchanged fields at their previous values.
I've had this set up and working well years ago in Excel, but Google Sheets is a new ballgame altogether, and I have been unable to find any helpful information on how this might work with Google Sheets.
Here is the code that is working great for adding new data:
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Form");
var datasheet = ss.getSheetByName("Data");
var values = [[formSS.getRange("B2").getValue(),
formSS.getRange("B3").getValue(),
formSS.getRange("B4").getValue(),
formSS.getRange("B5").getValue()]];
datasheet.getRange(datasheet.getLastRow()+1, 1, 1, 4).setValues(values);
formSS.getRange("B2").clearContent(),
formSS.getRange("B3").clearContent(),
formSS.getRange("B4").clearContent(),
formSS.getRange("B5").clearContent();
}
How can I update this code so that any already existing part numbers submitted in the Form sheet update the corresponding row on the Data sheet, instead of it being entered as a new row?
See if this works
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Form");
var dataSheet = ss.getSheetByName("Data");
var values = formSS.getRange("B2:B5").getValues().reduce(function(a, b) {
return a.concat(b)
});
var partNum = values[0];
var row;
dataSheet.getDataRange().getValues().forEach(function(r, i) {
if (r[0] === partNum) {
row = i + 1
}
})
row = row ? row : dataSheet.getLastRow() + 1;
var data = dataSheet.getRange(row, 1, 1, 4).getValues()[0].map(function (el, ind){
return el = values[ind] ? values[ind] : el;
})
dataSheet.getRange(row, 1, 1, 4).setValues([data]);
formSS.getRange("B2:B5").clearContent()
}
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
}