function myFunction() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('data');
var data = sheet.getDataRange().getValues();
var range = sheet.getRange("A1:L" + data.length);
range.sort(1);
const people = {};
for(var i = 0; i < data.length; i++) {
var name = data[i][0] + data[i][1];
console.log(i);
if (!people.name) {people.name = {rows: [i]};} else {people.name.rows.push(i)}
}
Logger.log(people);
}
What should I be doing differently? At the end, it logs {name={rows=[0.0, 1.0, 2.0, ...]}} instead of having an object for each name...?
In the sheet there's just a first name and last name on columns A and B, for around 80 rows.
Use the bracket syntax if you want to use dynamic names for properties: https://riptutorial.com/javascript/example/2321/dynamic---variable-property-names
In your case:
function myFunction() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('data');
var data = sheet.getDataRange().getValues();
var range = sheet.getRange("A1:L" + data.length);
range.sort(1);
const people = {};
for(var i = 0; i < data.length; i++) {
var name = data[i][0] + data[i][1];
console.log(i);
if (!people[name]) {people[name] = {rows: [i]};} else {people[name].rows.push(i)}
}
Logger.log(people);
}
Related
Just started learning Javascript/Google Apps Script, so please be patient with me.
My goal is to create an automated email script that emails a reminder when the inventory stock has dipped below a certain level.
To start, I have a Google Sheet with 3 tabs: ContactSheet, ReorderSheet, and EmailSheet. These tabs have columns, respectively: person's name and email address; item name, number, manufacturer, current stock, and threshold for reorder; subject line and message.
Code below. No runtime errors, but the emails either do not send or they send out for only the first or last item in the spreadsheet. (Should be sending out exactly 5 emails for 5 different items.) I think the issue is with the if statement --- I'm assuming that the variables are not able to call on their respective indices, if that makes sense. I've tried converting the variables to arrays with no success. This version works best according to the logger, and only breaks down at the last block.
Thanks in advance.
function sendEmail() {
var Spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var ContactSheet = Spreadsheet.getSheetByName('ContactSheet');
var ReorderSheet = Spreadsheet.getSheetByName('ReorderSheet');
var EmailSheet = Spreadsheet.getSheetByName('EmailSheet');
var SubjectLine = EmailSheet.getRange(2,1).getValue();
var Message = EmailSheet.getRange(2,2).getValue();
var N = ReorderSheet.getLastRow();
for(var i = 2; i < N+1; i++) {
var ItemName = ReorderSheet.getRange(i,1).getValue();
var ItemNumber = ReorderSheet.getRange(i,2).getValue();
var ItemManufacturer = ReorderSheet.getRange(i,3).getValue();
var ItemStock = ReorderSheet.getRange(i,4).getValue();
var ItemReorder = ReorderSheet.getRange(i,5).getValue();}
var M = ContactSheet.getLastRow();
for(var j = 2; j < M+1; j++) {
var Name = ContactSheet.getRange(j,1).getValue();
var EmailAddress = ContactSheet.getRange(j,2).getValue();}
if (ItemStock < ItemReorder) {
SubjectLine = SubjectLine.replace("<item>",ItemName);
Message = Message.replace("<name>",Name).replace("<item>",ItemName).replace("<itemnumber>",ItemNumber).replace("<manufacturer>",ItemManufacturer);
MailApp.sendEmail(EmailAddress, SubjectLine, Message);}
}
This for loop does not contain the sendEmail method:
for (var i = 2; i < N + 1; i++) {
var ItemName = rsh.getRange(i, 1).getValue();
var ItemNumber = rsh.getRange(i, 2).getValue();
var ItemManufacturer = rsh.getRange(i, 3).getValue();
var ItemStock = rsh.getRange(i, 4).getValue();
var ItemReorder = rsh.getRange(i, 5).getValue();
}
So your always only dealing with the data on the last row
Same with this one:
for (var j = 2; j < M + 1; j++) {
var Name = csh.getRange(j, 1).getValue();
var EmailAddress = csh.getRange(j, 2).getValue();
}
This structure will send emails to every email address:
function sendEmail() {
var ss = SpreadsheetApp.getActive();
var csh = ss.getSheetByName('ContactSheet');
var rsh = ss.getSheetByName('ReorderSheet');
var esh = ss.getSheetByName('EmailSheet');
var subject = esh.getRange(2, 1).getValue();
var message = esh.getRange(2, 2).getValue();
var N = rsh.getLastRow();
var M = csh.getLastRow();
for (var j = 2; j < M + 1; j++) {
var Name = csh.getRange(j, 1).getValue();
var EmailAddress = csh.getRange(j, 2).getValue();
for (var i = 2; i < N + 1; i++) {
var ItemName = rsh.getRange(i, 1).getValue();
var ItemNumber = rsh.getRange(i, 2).getValue();
var ItemManufacturer = rsh.getRange(i, 3).getValue();
var ItemStock = rsh.getRange(i, 4).getValue();
var ItemReorder = rsh.getRange(i, 5).getValue();
if (ItemStock < ItemReorder) {
subject = subject.replace("<item>", ItemName);
message = message.replace("<name>", Name).replace("<item>", ItemName).replace("<itemnumber>", ItemNumber).replace("<manufacturer>", ItemManufacturer);
MailApp.sendEmail(EmailAddress, subject, message);
}
}
}
}
I am trying to count the number of rows between two rows containing particular words in google sheets. But I am getting the following error:
Cannot convert [object Object] to (class). (line 41, file "Code")
I have written the following code on the google app script:
function search(SPREADSHEET_ID, SHEET_NAME, word) {
var locatedCells = [];
var ss = SpreadsheetApp.openById(SPREADSHEET_ID);
var searchLocation = ss.getSheetByName(SHEET_NAME).getDataRange().getValues();
//Loops to find the search term.
for (var j = 0, jLen = searchLocation.length; j < jLen; j++) {
for (var k = 0, kLen = searchLocation.length; k < kLen; k++) {
var find = word;
if (find == searchLocation[j][k]) {
locatedCells.push({ 'found': (j + 1)});
}
}
}
// Logger.log(locatedCells);
return(locatedCells)
}
function footerlocation(){
var SPREADSHEET_ID = "1nYBEuMMC4j1A4qryzKKq33PsTRH54ADyJLsEoTmbKh4"
var SHEET_NAME = "Bedding"
var word = "Footers"
var footerlocation = search(SPREADSHEET_ID, SHEET_NAME, word)
//Logger.log(footerlocation);
return(footerlocation)
}
function keywordlocation(){
var SPREADSHEET_ID = "1nYBEuMMC4j1A4qryzKKq33PsTRH54ADyJLsEoTmbKh4"
var SHEET_NAME = "Bedding"
var word = "Keyword Page Redirects to Implement"
var keywordlocation = search(SPREADSHEET_ID, SHEET_NAME, word)
//Logger.log(keywordlocation);
return(keywordlocation)
}
function count(){
var sheet= SpreadsheetApp.openById("1nYBEuMMC4j1A4qryzKKq33PsTRH54ADyJLsEoTmbKh4").getSheetByName("Bedding");
var startrow=footerlocation()
var endrow= keywordlocation()
var range = sheet.getRange(startrow,1,endrow-startrow,1);
var datas = range.getValues();
var count = 0;
for (data in datas) {
for (cell in data) {
//Logger.log(typeof cell) //{
count++;
//}
}
}
Logger.log(data)
}
I would appreciate if someone could help me with this.
I was able to figure out the solution, change the count function to the following:
function count(){
var sheet= SpreadsheetApp.openById("1nYBEuMMC4j1A4qryzKKq33PsTRH54ADyJLsEoTmbKh4").getSheetByName("Bedding");
var startrow=footerlocation()[0]['found']
var endrow= keywordlocation()[0]['found']
var range = sheet.getRange(startrow,1,endrow-startrow,1);
var datas = range.getValues();
var count = 0;
for (data in datas) {
for (cell in data) {
//Logger.log(typeof cell) //{
count++;
//}
}
}
Logger.log(data)
}
I'm currently developing a sheet that shows results from a set of data based on some filters but the data loads to slowly when getting the results, I've tried to follow the Best Practices from Google Documentacion with no luck, how can I set an array for the data to load faster?
Below is the code commented with what I've already tried
function realizarBusqueda() {
var inicio = SpreadsheetApp.getActive().getSheetByName("INICIO");
var aux_tags = SpreadsheetApp.getActive().getSheetByName("Aux_Tags");
var data = SpreadsheetApp.getActive().getSheetByName("Data");
var data_lc = data.getLastColumn();
var data_lr = data.getLastRow();
var searchRange = data.getRange(2,1, data_lr, data_lc);
var inicio_lc = inicio.getLastColumn();
inicio.getRange("A8:L1000").clearContent();
inicio.getRange("A8:L1000").clearFormat();
var countRows = inicio.getMaxRows();
inicio.deleteRows(20, (20-countRows)*-1);
if (inicio.getRange("B4").isBlank()) {
inicio.getRange("A8:L1000").clearContent();
inicio.getRange("A8:L1000").clearFormat();
var countRows = inicio.getMaxRows();
inicio.deleteRows(20, (20-countRows)*-1);
SpreadsheetApp.flush();
}
else if ((inicio.getRange("B4").getValue() != "" &&
inicio.getRange("C4").getValue() === "")) {
//filtrado 1
var arrayDatos = searchRange.getValues();
var inicio_fr = 8;
//var row = new Array(11);
for (var j = 2; j <= data_lr; j++) {
//row[j] = new Array(data_lr);
if (aux_tags.getRange("P2").getValue() === arrayDatos[j-2][4]) {
var inicio_fc = 1;
for (var i = 0; i < arrayDatos[j-2].length; i++) {
//row[j][i] = arrayDatos[j-2][i];
var row = arrayDatos[j-2][i];
inicio.getRange(inicio_fr, inicio_fc).setValue(row);
inicio_fc++;
}
inicio_fr++;
}
//inicio.getRange("A8").setValues(row);
}
}
I expect the output to load lots faster, currently what I've tried is commented, the code as-is is working but too slow
I just wanted to update this subject because I figured out myself, see attached the new code with the use of new 2D arrays
...
//filtrado 1
var arrayDatos = searchRange.getValues();
var inicio_fr = 8;
var rows = [];
var row = [];
for (var j = 2; j <= data_lr; j++) {
if (aux_tags.getRange("P2").getValue() === arrayDatos[j-2][4]) {
var inicio_fc = 1;
for (var i = 0; i < arrayDatos[j-2].length; i++) {
row.push(arrayDatos[j-2][i]);
if (i == 11) {
rows.push(row);
row = [];
}
}
}
}
inicio.getRange(8, 1, rows.length, rows[0].length).setValues(rows);
}
Now instead of writing on row at a time, I just write the whole array at once
I would like to know how to save the output of this into a "var a="
navigator.plugins.refresh(false);
var numPlugins = navigator.plugins.length;
for (var i = 0; i < numPlugins; i++){
var plugin = navigator.plugins[i];
if (plugin) {
document.write(plugin.name + plugin.description + plugin.filename)
}
}
Declare a outside of the loop and define it as an empty string, then append results to it as you go:
navigator.plugins.refresh(false);
var numPlugins = navigator.plugins.length;
var a = '';
for (var i = 0; i < numPlugins; i++){
var plugin = navigator.plugins[i];
if (plugin) {
a += plugin.name + plugin.description + plugin.filename;
}
}
You may want to use an array of strings though, since you could have many plugins:
navigator.plugins.refresh(false);
var numPlugins = navigator.plugins.length;
var a = [];
for (var i = 0; i < numPlugins; i++){
var plugin = navigator.plugins[i];
if (plugin) {
a.push(plugin.name + plugin.description + plugin.filename);
}
}
EDIT If you need to hash a into something:
var hash = yourMd5Function(a);
Or for the second example:
var b = a.join(','); // "plugin1,plugin2,..." for example
var hash = yourMd5Function(b);
I've Been using XSLT to display my xml page. I make use of the following to get the data from the xml file:
< xsl:value-of
select="ClinicalDocument/component/structuredBody/component[3]/section/text/table/tbody"/
>
After this, I have the following javascript to clean up the data and do the conversion:
-----------Get Content for Grids----------
//Split Content into array
var purposeArray = document.getElementById('purposeOfVisit').innerHTML.split("\n");
var activeProblemArray = document.getElementById('activeProblems').innerHTML.split("\n");
//------------ Remove All Unwanted Values-----------\\*/
var newDataString ="";
for( var k = 0; k < purposeArray.length; k++ )
{
newDataString += purposeArray[k] + "__";
}
newDataString = newDataString.replace(/ /g,"");
newDataString = newDataString.replace(/__________/g,"__-__");
var newDataArray = newDataString.split("__");
//------------- Save Values in final Array -------------\\*/
var semiFinalArray = new Array();
for( var x=0; x < newDataArray.length; x++)
{
if(newDataArray[x].length != 0)
{
semiFinalArray.push(newDataArray[x]);
}
}
var finalArray = new Array();
var counter = 0;
//------------ Find Number of Columns in row ------------\\*/
var numberOfRows = document.getElementById('numberOfRows').innerHTML;
var numberOfColumns = document.getElementById('numberOfColumns').innerHTML;
var columnsPerRow = parseInt(numberOfColumns) / parseInt(numberOfRows);
//------------------------------Testing ------------------------------//
var dataNamePre = "dataValue";
var temporaryArray = new Array();
var dataName;
//----------- Generate Grid Values -----------//
for( var b=0 ; b < semiFinalArray.length ; b = b + columnsPerRow)
{
var problemComment = "";
counter = 0;
var obj;
for( var a=0 ; a < columnsPerRow ; a++)
{
dataName = dataNamePre + counter.toString() + "";
//-------Generate Grid Titles------//
temporaryArray.push("Title " + (counter+1));
var key = "key"+a;
obj = { values : semiFinalArray[b+a] };
var problemComment = "";
finalArray.push(obj);
counter++;
}
}
//---------------------Generate GridArray---------------------------//
var gridArray = [];
var gridArrayHead = new Array();
counter = 0;
var objectValue = new Array();
for( var x = 0; x < finalArray.length; x++ )
{
objectValue = { head:temporaryArray[x], values: finalArray[x].values }
gridArray.push(objectValue);
}
var provFacilities = [];
for( var x = 0; x < finalArray.length; x++ )
{
provFacilities[x] =
{
head:temporaryArray[x], values: finalArray[x].values
}
}
//alert(gridArray);
$("#grid").kendoGrid(
{
columns:
[{
title:gridArray.head,
template:'#= values #'
}],
dataSource: {
data:finalArray,
pageSize:10
},
scrollable:false,
pageable:true
});
This may be a roundabout method, but I'm still prettry new to this method of coding.
Currently, all the data is being presented in one column, with the last value in my temporaryArray as the title for the column.
Everything works until I try to set the DataSource for the Kendo Grid. When working in the columns property in the grid, I made the following change:
title:gridArray[0].head
When this is done, the title is changed to the first value in the array.
What I want to know is how can I generate columns in the Kendo Grid According to the title? Is there a way to loop through all the values and create the objects from there, seeing that the date that is being sent to the grid are objects in an Array?
What I basically want is something to make this work, without the repitition:
var myGrid = $("#grid").kendoGrid( { columns: [ {
title: temporaryArray[0],
field: finalArray[0].values }, {
title: temporaryArray[1],
field: finalArray[1].values }, {
title: temporaryArray[2],
field: finalArray[2].values }, {
title: temporaryArray[3],
field: finalArray[3].values }, {
title: temporaryArray[4],
field: finalArray[4].values } ]
)};
Any help appreciated, thanks!
This issue has been fixed using the following coding:
var arrayData = [];
for( var x = 0; x < semiFinalArray.length; x=x+5 )
{
var tempArr = new Array();
for( var y = 0; y < 5; y++ )
{
var num = x + y;
tempArr.push(semiFinalArray[num]);
}
arrayData.push(tempArr);
}
var dataTitles = [];
for( var x = 0; x < titleArray.length; x++ )
{
var head = "";
head = titleArray[x];
head = head.replace(/ /g,"");
dataTitles.push(head);
}
var counter = 0;
var columnDefs = [];
for (var i = 0; i < columnsPerRow.length; i++)
{
if (counter == (columnsPerRow - 1))
{
counter = 0;
}
columnDefs.push({ field: dataTitles[counter], template: arrayData[i].values });
counter++;
}
// Create final version of grid array
var gridArray = [];
for (var i = 0; i < arrayData.length; i++)
{
var data = {};
for (var j = 0; j < dataTitles.length; j++)
{
data[dataTitles[j]] = arrayData[i][j];
}
gridArray.push(data);
}
// Now, create the grid using columnDefs as argument
$("#grid").kendoGrid(
{
dataSource:
{
data: gridArray,
pageSize: 10
},
columns: columnDefs,
scrollable: false,
pageable: true
}).data("kendoGrid");
With this, the data is displayed in the DataGrid.