Custom function in google sheet using indexOf - javascript

I've got a list of emails that I need to clean and identify which of these emails are company emails (i.e info#, hello#, etc)
I've had an idea to add rows in one google sheet, then check this against another google sheet with a column of company alias'. This will then return Trueof False in the column Company Alias? in the Input sheet.
Here is my Google sheet example.
I think it needs to iterate through the values of the second sheet and compare for email 1 field in the first sheet to see if it contains that value. I have made an apps script below:
function CHECKALIAS(x) {
var app = SpreadsheetApp;
var aliasSheet = app.getActive().getSheetByName('Company_Alias').getRange(2, 1, 45, 1);
var aliasRange = aliasSheet.getValues();
var str = x;
if(str.indexOf(aliasRange) !== -1){
return false;
} else {
return true;
}
}
I get the below error:
TypeError: Cannot read property 'indexOf' of undefined (line 13, file "Code")

Are you running the function without passing it a value? It's giving you the error because str has no value.
Anyway, there's no need for a custom function here. This will return true if there's a match with one of the aliases.
=REGEXMATCH(A1, JOIN("|",FILTER(Company_Alias!A2:A, NOT(ISBLANK(Company_Alias!A2:A)))))

str is a string and aliasRange is an array. Instead of searching for the array in the string, you should search for the string in the array.
Another problem is that .getValues​​() returns an array of arrays:
[["info #"], ["support #"], ["sales #"], ...].
To transform it into a 1D array, use the flat() function:
function CHECKALIAS(x) {
let app = SpreadsheetApp;
let aliasSheet = app.getActive().getSheetByName('Company_Alias').getRange(2, 1, 45, 1);
let aliasRange = aliasSheet.getValues().flat(); // Transforms 2D array in 1D
let userDomain = x.split('#'); // split "admin#somedomain.com" into [ "admin", "somedomain.com" ]
let usr = userDomain[0] + '#'; // "admin#
return aliasRange.indexOf(usr) !== -1; // Is usr in aliasRange?
}

Related

(JS) Google Script App Search / Filter for keyword

I have been stumped on this for a while. I am fairly new to Google script app and wanted to see if there is a way to make this happen. So far, I've used a few methods within Google Sheet but seem to not get it working.
The code below does give me an output of all the data, however, the data that is nested in the data.custom_fields[x] has multiple objects that is separated by ",". I would like to be able to filter out the other key words and just use whatever is inside "display_value=". The display_value= is not always in the same area so have to run a search for them.
I am assuming some kind of If statement would be used here..
An example of the object is:
{type=x, resource_subtype=x, created_by={name=x, gid=x, resource_type=x}, display_value=Cool Value, description=x, enabled=x, resource_type=custom_field, gid=x, enum_options=[x.lang.Object;x, enum_value={x}, name=x}
I've tried to split function as well but not sure how to filter out the words I need.
function Users() {
var options = {
"headers" : {
"Authorization": "API Key here"
}
}
var response = UrlFetchApp.fetch("URL here", options);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getSheetByName("Tab Name here"); // specific sheet name getSheetByName(""); alternatively use ss.getActiveSheet()
var dataAll = JSON.parse(response.getContentText()); //
var dataSet = dataAll.data; // "data" is the key containing the relevant objects
var rows = [],
data;
for (i = 0; i < dataSet.length; i++) {
data = dataSet[i];
rows.push([
data.gid,
data.name,
data.permalink_url,
data.due_on,
data.custom_fields[1],
data.custom_fields[2],
data.custom_fields[4],
data.custom_fields[5],
data.custom_fields[6],
data.custom_fields[7],
data.custom_fields[8],
data.custom_fields[9],
]); //your JSON entities here
}
// [row to start on], [column to start on], [number of rows], [number of entities]
dataRange = sheet.getRange(2, 1, rows.length, 12);
dataRange.setValues(rows);
Thank you in advance!
Example Image of JSON imported data
Although they appear separated by ,'s, that is only how they're displayed in the log. Because you're using JSON.parse, you're receiving/converting to an Object, not a string.
Because data.custom_fields is an array of objects, you can access the property/key values as : data.custom_fields[x].display_value.
Learn More:
JSON.parse()
Accessing Object Properties
If you want to extract display_value, try
let myVal = myData.match(/(?<=display_value=)[^,]+/g)[0]
I guess that myData could be data.custom_fields[5], so replace it by
data.custom_fields[5].match(/(?<=display_value=)[^,]+/g)[0]

Invalid argument: replacement error when populating google doc using google script

I have written a code to populate data from a spreadsheet into a google doc and save it to drive using g-sript. Here is the code for the same :
function onOpen() {
const ui = SpreadsheetApp.getUi();
const menu = ui.createMenu('Invoice creator');
menu.addItem('Generate Invoice', 'invoiceGeneratorFunction');
menu.addToUi();
}
function invoiceGeneratorFunction() {
const invoiceTemplate = DriveApp.getFileById('125NPu-n77F6N8hez9w63oSzbWrtryYpRGOkKL3IbxZ8');
const destinationFolder = DriveApp.getFolderById('163_wLsNGkX4XDUiSOcQ88YOPe3vEx7ML');
const sheet_invoice = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('New Invoice Sheet');
const rows = sheet_invoice.getDataRange().getValues();
Logger.log(rows);
rows.forEach(function(row, index) {
if (index === 0) return;
if (row[12] != "") return;
const copy = invoiceTemplate.makeCopy(`${row[1]} VIN Number: ${row[2]}`,destinationFolder);
const doc = DocumentApp.openById(copy.getId());
const body = doc.getBody();
var friendlyDateBilled = new Date(row[0]).toLocaleDateString();
var friendlyDateDelivery = new Date(row[3]).toLocaleDateString();
body.replaceText('{{Date Billed}}',friendlyDateBilled);
body.replaceText('{{Customer Name}}',row[1]);
body.replaceText('{{VIN Number}}',row[2]);
body.replaceText('{{Date of Delivery}}',friendlyDateDelivery);
body.replaceText('{{Package}}',rows[4]);
body.replaceText('{{Price}}',rows[5]);
body.replaceText('{{Output CGST}}',rows[6]);
body.replaceText('{{Output SGST}}',rows[7]);
body.replaceText('{{Discount}}',rows[8]);
body.replaceText('{{Total Price}}',rows[9]);
body.replaceText('{{Balance}}',rows[10]);
body.replaceText('{{Remarks}}',rows[11]);
doc.saveAndClose();
const url = doc.getUrl();
sheet_invoice.getRange(index+1, 13).setValue(url);
})
}
I have created a menu button for the script to run. But when i run it I get an error saying :
Exception: Invalid argument: replacement
at unknown function
at invoiceGeneratorFunction(Code:17:8)
(Here line 32 is body.replaceText('{{Package}}',rows[4]);
and line 17 is the start of forEach)
Interestingly when I comment out the rest of body.replaceText lines after that line, the code works. I can't understand what the problem is, if it's working if I comment out the lines.
In your script, rows is 2 dimensional array retrieved with sheet_invoice.getDataRange().getValues(). When I saw your loop, after the line of body.replaceText('{{Package}}',rows[4]);, rows is used. In this case, rows[4] is 1-dimensional array. It is required to be the string for the arguments of replaceText(searchPattern, replacement). I think that this might be the reason for your issue. In order to remove this issue, how about the following modification?
From:
body.replaceText('{{Package}}',rows[4]);
body.replaceText('{{Price}}',rows[5]);
body.replaceText('{{Output CGST}}',rows[6]);
body.replaceText('{{Output SGST}}',rows[7]);
body.replaceText('{{Discount}}',rows[8]);
body.replaceText('{{Total Price}}',rows[9]);
body.replaceText('{{Balance}}',rows[10]);
body.replaceText('{{Remarks}}',rows[11]);
To:
body.replaceText('{{Package}}',row[4]);
body.replaceText('{{Price}}',row[5]);
body.replaceText('{{Output CGST}}',row[6]);
body.replaceText('{{Output SGST}}',row[7]);
body.replaceText('{{Discount}}',row[8]);
body.replaceText('{{Total Price}}',row[9]);
body.replaceText('{{Balance}}',row[10]);
body.replaceText('{{Remarks}}',row[11]);
Note:
I'm not sure about your actual values of rows. So I'm not sure whether the values of row[4] to row[11] are what you want. If those values are not the values you expect, please check your Spreadsheet again.
Reference:
replaceText(searchPattern, replacement)

How do you loop through an object and replace text

I have a script that should create a pdf file from a google form submission and grabs the data to be changed as an object. However I am using the replaceText action to make the changes to the doc and I'm getting the following error.
Exception: Invalid argument: replacement
at Create_PDF(Code:37:8)
at After_Submit(Code:13:19)
It is supposed to change the values in the generated doc file and it worked when I used the namedValues function. However now that I'm using range instead it doesn't seem to work.
function After_Submit(e){
var range = e.range;
var row = range.getRow(); //get the row of newly added form data
var sheet = range.getSheet(); //get the Sheet
var headers = sheet.getRange(1, 1, 1, 129).getValues().flat(); //get the header names from A-O
var data = sheet.getRange(row, 1, 1, headers.length).getValues(); //get the values of newly added form data + formulated values
var values = {}; // create an object
for( var i = 0; i < headers.length; i++ ){
values[headers[i]] = data[0][i]; //add elements to values object and use headers as key
}
Logger.log(values);
const pdfFile = Create_PDF(values);
sendEmail(e.namedValues['Email Address to Receive File '][0],pdfFile);
}
function sendEmail(email,pdfFile){
GmailApp.sendEmail(email, "Subject", "Files Attached", {
attachments: [pdfFile],
name: "From Email"
});
}
function Create_PDF(values) {
const PDF_folder = DriveApp.getFolderById("ID_1");
const TEMP_FOLDER = DriveApp.getFolderById("ID_2");
const PDF_Template = DriveApp.getFileById('ID_3');
const newTempFile = PDF_Template.makeCopy(TEMP_FOLDER);
const OpenDoc = DocumentApp.openById(newTempFile.getId());
const body = OpenDoc.getBody();
console.log(body);
body.replaceText("{{Timestamp}}", values['Timestamp'][0]);
body.replaceText("{{Location}}", values['Location'][0]);
body.replaceText("{{Item1}}", values['Item1'][0]);
body.replaceText("{{Item2}}", values['Item2'][0]);
body.replaceText("{{Itme3}}", values['Item3'][0]);
body.replaceText("{{e1}}", values['e1'][0]);
body.replaceText("{{e2}}", values['e2'][0]);
body.replaceText("{{e3}}", values['e3'][0]);
body.replaceText("{{e4}}", values['e4'][0]);
body.replaceText("{{e5}}", values['e5'][0]);
body.replaceText("{{e6}}", values['e6'][0]);
body.replaceText("{{e7}}", values['e7'][0]);
body.replaceText("{{e8}}", values['e8'][0]);
body.replaceText("{{e9}}", values['e9'][0]);
body.replaceText("{{e10}}", values['e10'][0]);
body.replaceText("{{e11}}", values['e11'][0]);
body.replaceText("{{e12}}", values['e12'][0]);
body.replaceText("{{e13}}", values['e13'][0]);
body.replaceText("{{e14}}", values['e14'][0]);
body.replaceText("{{e15}}", values['e15'][0]);
body.replaceText("{{e16}}", values['e16'][0]);
body.replaceText("{{e17}}", values['e17'][0]);
body.replaceText("{{e18}}", values['e18'][0]);
body.replaceText("{{e19}}", values['e19'][0]);
body.replaceText("{{e20}}", values['e20'][0]);
body.replaceText("{{e21}}", values['e21'][0]);
body.replaceText("{{e22}}", values['e22'][0]);
body.replaceText("{{e23}}", values['e23'][0]);
body.replaceText("{{e24}}", values['e24'][0]);
body.replaceText("{{e25}}", values['e25'][0]);
body.replaceText("{{e26}}", values['e26'][0]);
body.replaceText("{{e27}}", values['e27'][0]);
body.replaceText("{{e28}}", values['e28'][0]);
body.replaceText("{{e29}}", values['e29'][0]);
body.replaceText("{{e30}}", values['e30'][0]);
body.replaceText("{{e31}}", values['e31'][0]);
body.replaceText("{{e32}}", values['e32'][0]);
body.replaceText("{{e33}}", values['e33'][0]);
body.replaceText("{{e34}}", values['e34'][0]);
body.replaceText("{{e35}}", values['e35'][0]);
body.replaceText("{{e36}}", values['e36'][0]);
body.replaceText("{{e37}}", values['e37'][0]);
body.replaceText("{{e38}}", values['e38'][0]);
body.replaceText("{{e39}}", values['e39'][0]);
body.replaceText("{{H1}}", values['H1'][0]);
body.replaceText("{{H2}}", values['H2'][0]);
body.replaceText("{{H3}}", values['H3'][0]);
body.replaceText("{{H4}}", values['H4'][0]);
body.replaceText("{{H5}}", values['H5'][0]);
body.replaceText("{{H6}}", values['H6'][0]);
body.replaceText("{{H7}}", values['H7'][0]);
body.replaceText("{{H8}}", values['H8'][0]);
body.replaceText("{{H9}}", values['H9'][0]);
body.replaceText("{{H10}}", values['H10'][0]);
body.replaceText("{{H11}}", values['H11'][0]);
body.replaceText("{{H12}}", values['H12'][0]);
body.replaceText("{{H13}}", values['H13'][0]);
body.replaceText("{{H14}}", values['H14'][0]);
OpenDoc.saveAndClose();
const BLOBPDF = newTempFile.getAs(MimeType.PDF);
const pdfFile = PDF_folder.createFile(BLOBPDF).setName("FLHA");
console.log("The file has been created ");
return pdfFile;
}
Your question was how to loop through an object and replace text
This creates an object from Sheet0:
Sheet0:
one
pattern
two
this is the pattern
three
pattern pattern
four
nothing
five
nothing
Code:
function replacepattern() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const vs = sh.getRange(1,1,sh.getLastRow(), 2).getValues();
//creating object from spreadsheet
let obj = {pA:[]};
vs.forEach(r =>{
obj[r[0]]=r[1];
obj.pA.push(r[0]);
});
Logger.log(JSON.stringify(obj));
let oA = obj.pA.map(p => [obj[p].replace(/pattern/g,'replacement')]);//doing the replacement in an object
sh.getRange(1,sh.getLastColumn() + 1,oA.length, oA[0].length).setValues(oA);//outputting the replaced string in the next column
Logger.log(JSON.stringify(oA));
}
Sheet0 after running once:
one
pattern
replacement
two
this is the pattern
this is the replacement
three
pattern pattern
replacement replacement
four
nothing
nothing
five
nothing
nothing
This is related to my answer here.
The error code Exception: Invalid argument: replacement at Create_PDF(Code:37:8) at After_Submit(Code:13:19) is caused by the null value of values['Timestamp'][0]. If you try to print the data type of values['Timestamp'], it will return a type object, since that object does not have value for index 0 to it will return a null value.
For entries that are type String, if you add [0] to it, it will return only the first element of the string. Example you have "Test" string, adding [0] to it will return "T"
To fix that, just remove the [0] in all of body.replaceText(..., values['...'][0]) entries.
OR
Loop through values object by replacing the body.replaceText entries in your code with this:
for (const key in values) {
body.replaceText("{{"+key+"}}", values[key]);
}
Example usage:
Form inputs:
Output:
Reference:
JavaScript for..in

How do I omit the words "type" and "value" from showing in my google sheet after running google script to get user data from AD?

i am new to Javascript and im currently trying to create a google sheet that lists all the users in the AD group + their phone numbers. however when i run this script below, the cell that should have the phone number in it has, "type=work, value=(000)123-4567 as well. i just want the phone number to be displayed by itself. how would I work around this? I'm sure im missing something simple
function writeToSpreadsheet(){
var values = [];
var users = AdminDirectory.Users.list({domain:'companydomain.com'}).users;
for (var i=0; i<users.length; i++){
values.push([users[i].name.fullName, users[i].phones]);
var spreadsheetUrl = 'https://docs.userinfospreadsheet';
SpreadsheetApp.openByUrl(spreadsheetUrl).getSheets()[0].getRange(1, 1, values.length, values[0].length).setValues(values)
Im using this guide as a reference https://sites.google.com/site/scriptsexamples/home/announcements/listingdomainusernamesinaspreadsheet,
As the documentations states, phones is an array of objects. The simplest way of handling them would be to use a function that converts them into a string:
function generatePhonesCell(phones) {
return phones
.map(phone => {
const value = phone.value
const type = phone.type.replaceAll('_', ' ')
return `${value} (${type})`
})
.join('\n')
}
This will list the phones in the form:
(000)123-4567 (home)
(000)765-4321 (work)
You only need to add them into your existing code:
values.push([users[i].name.fullName, generatePhonesCell(users[i].phones || [])])
I think that user's phones property is not a string but rather an object or list.
In order to get the nice list of the phone numbers you have to replace users[i].phones pushed to values array with function call getPhones(users[i].phones)
And this function should be something like this:
If user phones are array of objects [{type: 'work', value: '(000)123-4567'}]:
function getPhones(arr) {
return arr.map(function(phoneObj) {
return phoneObj.value;
}).join(', ')
}
or if it is simply an object replce users[i].phones with users[i].phones.value

Advanced AngularJS live Search

I have the following data
persons = [
{
"age":20,
"parameter1":94,
"name":"Foobarin"
},
{
"age":33,
"parameter1":49,
"name":"Johan"
}
]
I want to create an advanced live search which recognizes patterns. An examples could be "foo a20 p94" which would get me the first object.
a20 - Search where age is 20
p94 - Search where parameter1 is 94
and then if there is any other text which does not have any set prefix then test that against the name value.
All the values (except name which is case-insensitive) is of type integer. I want to limit the prefixes to predefined such as a, p and not age20.
The data-sets is around 400.
I've created a basic live search which searches all variables in the object, but now I do not know where to continue. Any ideas?
It's not foolproof but as a first-pass this is what I'd start with, I'll try to talk through it in pseudo.
First declare a propertyMatrix, a simple object-map which can point "prefixes" to the actual property names which exist within person. The searchPersons function accepts a single string (query) value and consists of two main parts:
The query string is split on whitespace characters into an array of "tokens". Each token is also an array of exactly 2 length, containing each token name and token value. At this stage it attempts find the predetermined prefix - if no such entry exists the token name: name is assumed.
A filter is then applied to the persons array. For each person we iterate over the tokens array and make an appropriate comparison, if any single check fails we return false (thus excluding the person from the results).
var propertyMatrix = {
'a': 'age',
'p': 'parameter1'
},
searchPersons = function(query){
var tokens = query.split(/\s+/).map(function(t){
t = t.toLowerCase();
var i = t.match(/\d+$/), p;
if(i && i.length) {
p = t.substring(0, t.indexOf(i));
if(p in propertyMatrix)
return [propertyMatrix[p], parseInt(i, 10)];
}
return ['name', t];
}),
result = persons.filter(function(p){
for(var i=0, l=tokens.length; i<l; i++){
var token = tokens[i][0], value = tokens[i][1];
if(!(token in p)) return false;
if(token === 'name'){
if(p.name.toLowerCase().indexOf(value)<0) return false;
} else if(p[token] !== value) return false;
}
return true;
});
return result;
};
fiddle

Categories