How to rename a new google sheet using cell references? - javascript

So currently, I am trying to make a google script that exports separate google sheets for each unique username -- i.e., to try to make a customizable report for each client. Basically, I have a list of unique usernames -- a list called uniqueUserName -- and I want to set the name of the new sheet to the "Name" which corresponds to the username. For example, suppose Sally1 is in the following table. The code would search through the usernames (with a for loop) and, once the for loop hits Sally1, the code would return Sally Wall -- i.e., the name corresponding to her username. Sally Wall would then be the new name of the document.
Username
Name
Timmy
Tim Jones
Sally1
Sally Wall
catsforlife
John Mueller
ready2learn
Cindy Rodney
I have tried the following code:
newSheet.setName(function(uniqueName, values){
for (var i=0; i < values.length; i++) {
if (values[i][0].Username === uniqueName) {
return values[i][1].Name;
break;
}
}
});
(I include the break function, because, if someone's name shows up twice, I don't want to copy their name twice. )
How would I have to adjust this code to serve these ends? Is this on the right track?
Honestly, I've been at this code for a while, looking up as much as I can, on stack overflow, YouTube, so your help is much appreciated!

One problem is that you're passing a function to the setName() method, but it expects a string. One straightforward way to solve this would be to immediately call the function after it's declared, passing the arguments as well.
Another thing is that you're trying to access the properties Name and Username of elements in values, but, assuming you received values from getValues(), those properties don't exist. You can get the values you want by just using the indices, as you're already doing: values[i][0] and values[i][1].
Also, you don't need to use break because the loop will be interrupted by the return statement anyway.
Considering the above and assuming there's a sheet called Names (that has the names you posted) and another called Report Template, you can change your code to something like:
function newNamedSheetTest() {
const uniqueName = 'Sally1';
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const values = spreadsheet.getSheetByName('Names').getDataRange().getValues();
const newSheet = spreadsheet.getSheetByName('Report Template').copyTo(spreadsheet);
newSheet.setName(function (uniqueName, values) {
for (let i = 0; i < values.length; i++) {
if (values[i][0] === uniqueName) {
return values[i][1];
}
}
}(uniqueName, values));
}
Another option would be to use filter and map to get the name of the sheet:
function newNamedSheetTestShort() {
const uniqueName = 'Sally1';
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const values = spreadsheet.getSheetByName('Names').getDataRange().getValues();
const newSheetName = values.filter(row => row[0] === uniqueName).map(row => row[1]);
const newSheet = spreadsheet.getSheetByName('Report Template').copyTo(spreadsheet);
newSheet.setName(newSheetName);
}

Related

Javascript Search to Loop and Display Objects one at a time

I am very new to JavaScript so please forgive the question if easy.
I have created a Google Sheet. I have used the first tab called Form, to create a data entry form, this data is then saved, using JavaScript to another tab called, Removal_list. All works fine.
I have added a search function to recall the data from the Removal_list to Form using names. What I cannot work out is how to show not just the first object that meets the criteria. Example, I will have a list of names (column B in the sheet), which can be duplicated. When I search it will only return the first occurrence. What I would like is the search to allow me to see each occurrence, one at a time. So if John Smith is in my list five times, the first occurrence will populate (as it does now), if this is not the one I want to see then, I somehow, move on to the next occurrence.
// search values
var SEARCH_COL_IDX = 1
function Search() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formS = ss.getSheetByName("Form");
var valuesFound = false;
var str = formS.getRange("D18").getValue();
var values = ss.getSheetByName("Removal_list").getDataRange().getValues();
for (var i = 0; i < values.length; i++) {
var row = values[i];
if (row[SEARCH_COL_IDX] == str) {
formS.getRange("B5").setValue(row[0]);
formS.getRange("B7").setValue(row[1]);
formS.getRange("B9").setValue(row[2]);
formS.getRange("B11").setValue(row[3]);
formS.getRange("B13").setValue(row[4]);
formS.getRange("B15").setValue(row[5]);
formS.getRange("E5").setValue(row[6]);
formS.getRange("E7").setValue(row[7]);
formS.getRange("E9").setValue(row[8]);
formS.getRange("E11").setValue(row[9]);
formS.getRange("E13").setValue(row[10]);
formS.getRange("E15").setValue(row[11]);
formS.getRange("G9").setValue(row[12]);
formS.getRange("G11").setValue(row[13]);
formS.getRange("G14").setValue(row[14]);
valuesFound=true;
return;
}
if(valueFound=false){
var ui=SpreadsheetApp.getUi();
ui.alert("No record found");
}
}}

Script setValue based on the values of column based on value of other column matching reference

https://docs.google.com/spreadsheets/d/1g5mLRcwBb9rLaJ4qIUy1PLaBNNfuwvXwct1cBr2QVgk/edit#gid=1271563337
basicly im trying to figure out a script that would:
Find match in Relação!A:A to content of Config!B3
in my example ABEV3 it would be Relação!A3
that would find a correponding row 3
so the matching cel in Relação!L:L would be Relação!L3
update Relação!L3 with content of Config!D9
basic idea with part of code that i can do to try to ilustrate
function setSheetID()
{
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet_c = ss.getSheetByName('Config');
var ticket = ss.getRange(3,2,1,1).getValues(); // Config!B3
var sheetID = ss.getRange(9,4,1,1).getValues(); // Config!D9
const sheet_r = ss.getSheetByName('Relação');
var LR = sheet_r.getLastRow();
var LC = sheet_r.getLastColumn();
var row_to_match_with_ticket = sheet_r.getRange(1,1,LR,1).getValues(); // Relação!A:A
// that part i have no idea how to get range for target where ticket would match with row_to_match_with_ticket, so i will put the result as example
for (var i = 0; i <= 1; i++) // i dont understand that, just setting exemple from posts ive seen
{
if (row_to_match_with_ticket[i] == ticket )
{
var target = sheet_r.getRange(3,12,1,1); // Relação!L3 // im harcoding result, cos i dont fully understant what i wrote in the example
sheet_r.getRange(target).setValues(sheetID);
}
}
};
now i will try to ilustrate with a query: (im not in USA, so ; instead of ,)
to find my target:
query('Relação'!A:L; "SELECT L WHERE (A = '"&Config!B3&"') LIMIT 1";0)
update that cell
UPDATE WITH Config!D9 ( Relação!L:L WHERE Relação!A:A = Config!B3 )
in this case update Relação!L3 WITH VALUES OF Config!D9
searched and results where too complex to me understand and be able to try to adapt to my needs
thanks in advance
Edit: tried to simplify, to make it easier to understand as im terrible to explain aparently, but that script would run on multiple SS that i quite often replace as i improve it, so i need each sheet to update a main sheet
Edit 2: tried to provide a logical way to understant the inputs and outputs, its might be easier to see in the sheet i provided as its comented and colored, tried to describe the best possible way i could
Edit 3: added basic code to try to show what i want to do
I believe your goal is as follows.
You want to retrieve the value of cell "B3" of "Config" sheet.
You want to search the retrieved value from the column "A" of "Relação" sheet.
When the value is found, you want to put the value of cell "D9" of "Config" sheet to the column "L" of the same row of the searched value.
In this case, how about the following sample script?
Sample script:
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const [src, dst] = ["Config", "Relação"].map(s => ss.getSheetByName(s));
const [b3, d9] = ["B3", "D9"].map(r => src.getRange(r).getValue());
const search = dst.getRange("A2:A" + dst.getLastRow()).createTextFinder(b3).findNext();
if (!search) return;
search.offset(0, 11).setValue(d9);
}
In this answer, the value is searched using TextFinder.
Reference:
createTextFinder(findText)

Google Script return value from one sheet to another sheet

This is my first Google Script and I'm struggling a little bit while trying to bring back the values from a specific cell & sheet to another sheet.
I have a total of 18 columns, being the first one the ID which is going to be the input that the user would need to add in order to retrieve the data from one sheet to another. As the first one is the ID, and will be already be inputted by the user, I would need to retrieve the data from columns 2 to 18
Here is my code:
function SearchID() {
var columnIndex = 0;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formS = ss.getSheetByName("Manual Costs App"); // App sheet
var str = formS.getRange("D6").getValue(); // The ID to search will be inputted here
var dataS = ss.getSheetByName("Inputs").getDataRange().getValues(); // Retrieving the data based on the user input
for (var i = 0; i<=dataS.length; i++) {
var row = dataS[i];
if (row[columnIndex] == str) {
formS.getRange("D9").setValue(row[1]);
formS.getRange("D13").setValue(row[2]);
formS.getRange("D14").setValue(row[3]);
formS.getRange("D15").setValue(row[4]);
formS.getRange("D16").setValue(row[5]);
formS.getRange("D18").setValue(row[6]);
formS.getRange("D19").setValue(row[7]);
formS.getRange("D20").setValue(row[8]);
formS.getRange("D21").setValue(row[9]);
formS.getRange("D22").setValue(row[10]);
formS.getRange("D23").setValue(row[11]);
formS.getRange("D25").setValue(row[12]);
formS.getRange("D26").setValue(row[13]);
formS.getRange("D27").setValue(row[14]);
formS.getRange("D28").setValue(row[15]);
formS.getRange("D29").setValue(row[16]);
formS.getRange("D30").setValue(row[17]);
break;
}
}
}
The link to a sample spreadsheet of what I'm building is here
Update: Everything is fixed now! What I did was removing the space in the for loop. After that, it retrieved the data but a TypeError: Cannot read property '0'. Also solved it adding a break after the loop to avoid it.
It's a type in your for loop, notice how spelled length:
for (var i = 1; i <= values.lenght; i++)
You also don't want to set values line by line like you do, get a longer range and set the values with setValues() rather than setValue(). There's quite a bit of refactoring to do there actually.
The user did found the answer and updated it on the question.
Posting here as community wiki so it can be seen more clearly.
User's answer:
Update: Everything is fixed now! What I did was removing the space in the for loop. After that, it retrieved the data but a TypeError: Cannot read property '0'. Also solved it adding a break after the loop to avoid it.
function SearchID() {
var columnIndex = 0;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formS = ss.getSheetByName("Manual Costs App"); // App sheet
var str = formS.getRange("D6").getValue(); // The ID to search will be inputted here
var dataS = ss.getSheetByName("Inputs").getDataRange().getValues(); // Retrieving the data based on the user input
for (var i = 0; i<=dataS.length; i++) {
var row = dataS[i];
if (row[columnIndex] == str) {
formS.getRange("D9").setValue(row[1]);
formS.getRange("D13").setValue(row[2]);
formS.getRange("D14").setValue(row[3]);
formS.getRange("D15").setValue(row[4]);
formS.getRange("D16").setValue(row[5]);
formS.getRange("D18").setValue(row[6]);
formS.getRange("D19").setValue(row[7]);
formS.getRange("D20").setValue(row[8]);
formS.getRange("D21").setValue(row[9]);
formS.getRange("D22").setValue(row[10]);
formS.getRange("D23").setValue(row[11]);
formS.getRange("D25").setValue(row[12]);
formS.getRange("D26").setValue(row[13]);
formS.getRange("D27").setValue(row[14]);
formS.getRange("D28").setValue(row[15]);
formS.getRange("D29").setValue(row[16]);
formS.getRange("D30").setValue(row[17]);
break;
}
}
}

Apps Script doesn't compare 2 values in if-statement

I've created a new project that should compare a name from Sheet1 with a list of names in Sheet2 and check if the name is already in that list. For that I chose a for-loop to get through the list in Sheet2 and compare every list entry with the name from Sheet1. Only if the name already exists in the list stuff should happen.
function myFunction() {
var tabSheet1 = 'Sheet1';
var tabSheet2 = 'Sheet2';
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName(tabSheet1);
var sheet2 = ss.getSheetByName(tabSheet2);
var lastRow1 = sheet2.getLastRow() + 1;
var playerNameSheet1 = sheet1.getRange(1, 1).getValue();
for (var j = 1; j < lastRow1; j++) {
var playerNameSheet2 = sheet2.getRange(j, 1).getValue();
if (playerNameSheet2 == playerNameSheet1) {
...stuff...
}
}
}
Now my problem is that it seems like the script isn't able to identify that a name already exists in the list. Both values (playerNameSheet1 and playerNameSheet2) are completely identical (no space or other hidden obstacles), however the script would never continue with stuff in the if-statement. My example name to test my script was "Oliver Baumann".
I'm a bit confused about it - even more, because another comparison a bit later in the script code works just fine.
I've already tried to change the operator into === but that wouldn't work either.
if (playerNameSheet2 === playerNameSheet1) {
...stuff...
}
I've also observed that if I put a dot behind both variables I'm only able to choose further functions with playerNameSheet2, but not with playerNameSheet1. Maybe I did a typing error and am just too blind to see it? I don't know. Anyone an idea how to resolve the issue?
The complete project can be found here. However, a lot of stuff is in german and very rudimental. I just started it and haven't got time to clean it up. Just so you don't wonder.
You will likely benefit from a change to your inspection routine - currently what you have is not scalable due to the slow, repeated calls to the Spreadsheet Service. Use a batch method - getValues() - to return a Javascript Array that contains all the content you could want from your 'master list' of names:
// Create an N x 1 array of arrays, e.g. [ [r1c1], [r2c1], [r3c1], ... [rNc1] ],
// of data in column A in sheet2. There will be blanks at the end if other columns have more data.
var allNames = sheet2.getRange(1, 1, sheet2.getLastRow(), 1).getValues();
To check if the name from the first sheet is present, we can replace this code:
for (var j = 1; j < lastRow1; j++) {
var playerNameSheet2 = sheet2.getRange(j, 1).getValue();
if (playerNameSheet2 == playerNameSheet1) {
/* do stuff */
with this code (note j now starts at 0):
for (var j = 0; j < allNames.length; ++j) {
if (playerNameSheet1 === allNames[j][0]) {
/* do stuff */
If you only need to do stuff on a name once in the function call (e.g. you don't need to execute the loop body twenty times when the sheet 1 name is "Bob" and there are twenty instances of "Bob" on sheet 2), you can simplify checking allNames for a value with the Array#indexOf method. First, one must collapse the "2D" array of arrays of values into an array of values. We want to apply a function to every element of the outer array and construct an array of its outputs, so we choose to call Array#map on it:
var db = allNames.map(function (row) { return row[0]; });
The function we use simply returns the first element of the passed element - i.e. the value in the first column, resulting in an output like [ r1c1, r2c1, r3c1, ... rNc1 ].
The replacement code is then:
if (db.indexOf(playerNameSheet1) === -1) {
console.log({
message: "Did not find '" + playerNameSheet1 + "' in database.",
database: db, original: allNames, searched: playerNameSheet1
});
return;
}
/* do stuff */
Which says "if the name is not on sheet 2, log the failed lookup and then quit running the function." To promote actual logging, the log is sent to Stackdriver, which will keep it for much longer than the native Logger class would.
If your do stuff bits use the j index, you can still obtain that index and use the associated row in sheet 2:
var index = db.indexOf(playerNameSheet1);
if (index === -1) {
console.log({
message: "Did not find '" + playerNameSheet1 + "' in database.",
database: db, original: allNames, searched: playerNameSheet1
});
return;
}
/* do stuff with the user's existing row of data, e.g.
var userDataRow = sheet2.getRange(index + 1, 1, 1, sheet2.getLastColumn()).getValues();
var userData = userDataRow[0];
...
*/
A possible improvement to the indexOf modification, which I leave for you to investigate and/or implement, would be to use an Object to hold the names as "keys" (object properties) and the index of the associated sheet data (or even the data directly) as the associated value of the key-value pair.
you can try to convert data in array and compare in for-loop:
var dataRangeSpieler = sheetSpieler.getDataRange().getValues();
var dataRangeDBSpiele = sheetDBSpieler.getDataRange().getValues();
for (i in dataRangeSpieler ) {
for (j in dataRangeDBSpiele) {
if (dataRangeSpieler[i][1] == dataRangeDBSpiele[j][0]) {
Logger.log(dataRangeSpieler[i][1]); //Oliver Baumann
}
}
}

Google Script to see if text contains a value

I have a google form that when the user submits it will trigger my function to run which is creating a summary of what they submitted as a Google Doc. I know it can automatically send an email but I need it formatted in a way that my user can edit it later.
There are some check boxes on the form -- but the getResponse() is only populated with the items checked and I need it to show all possible choices. Then I will indicate somehow what was checked.
I can't find a way to see if a text contains a value.
Like in Java with a String, I could do either .contains("9th") or .indexOf("9th") >=0 and then I would know that the String contains 9th. How can I do this with google scripts? Looked all through documentation and I feel like it must be the easiest thing ever.
var grade = itemResponse.getResponse();
Need to see if grade contains 9th.
Google Apps Script is javascript, you can use all the string methods...
var grade = itemResponse.getResponse();
if(grade.indexOf("9th")>-1){do something }
You can find doc on many sites, this one for example.
Update 2020:
You can now use Modern ECMAScript syntax thanks to V8 Runtime.
You can use includes():
var grade = itemResponse.getResponse();
if(grade.includes("9th")){do something}
I had to add a .toString to the item in the values array. Without it, it would only match if the entire cell body matched the searchTerm.
function foo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('spreadsheet-name');
var r = s.getRange('A:A');
var v = r.getValues();
var searchTerm = 'needle';
for(var i=v.length-1;i>=0;i--) {
if(v[0,i].toString().indexOf(searchTerm) > -1) {
// do something
}
}
};
I used the Google Apps Script method indexOf() and its results were wrong. So I wrote the small function Myindexof(), instead of indexOf:
function Myindexof(s,text)
{
var lengths = s.length;
var lengtht = text.length;
for (var i = 0;i < lengths - lengtht + 1;i++)
{
if (s.substring(i,lengtht + i) == text)
return i;
}
return -1;
}
var s = 'Hello!';
var text = 'llo';
if (Myindexof(s,text) > -1)
Logger.log('yes');
else
Logger.log('no');

Categories