How can I place my data fields beneath my row field in my PivotTable (Aspose Cells)? - pivot-table

I have a PivotTable created with Excel Interop that places the data field values beneath the row field values, like so:
When I create the PivotTable with Aspose Cells, the data fields are 1:08 PM 11/18/2016in a column to the right, rather than in the same column and beneath the row values:
Here is the code I'm using to generate the PivotTable in Aspose Cells:
private void PopulatePivotTableSheet()
{
int DESCRIPTION_COLUMN = 1;
int MONTHYR_COLUMN = 3;
int TOTALQTY_COLUMN = 4;
int TOTALPRICE_COLUMN = 5;
int PERCENTOFTOTAL_COLUMN = 7;
int AVGPRICE_COLUMN = 10;
int COLUMNS_IN_DATA_SHEET = 11;
AddSheetHeadingSectionToPivotTableSheet();
Aspose.Cells.Pivot.PivotTableCollection pivotTables = pivotTableSheet.PivotTables;
int colcount = COLUMNS_IN_DATA_SHEET;
string lastColAsStr = ReportRunnerConstsAndUtils.GetExcelColumnName(colcount);
int rowcount = sourceDataSheet.Cells.Rows.Count;
string sourceDataArg = string.Format("sourceDataSheet!A1:{0}{1}", lastColAsStr, rowcount);
int index = pivotTableSheet.PivotTables.Add(sourceDataArg, "A6", "PivotTableSheet");
Aspose.Cells.Pivot.PivotTable pivotTable = pivotTables[index];
pivotTable.DisplayNullString = true;
pivotTable.NullString = "0";
// Dragging the first field to the row area.
pivotTable.AddFieldToArea(Aspose.Cells.Pivot.PivotFieldType.Row, DESCRIPTION_COLUMN);
pivotTable.RowHeaderCaption = "Description";
// Dragging the second field to the column area.
pivotTable.AddFieldToArea(Aspose.Cells.Pivot.PivotFieldType.Column, MONTHYR_COLUMN);
pivotTable.ColumnHeaderCaption = "Months";
// Dragging the third field to the data area.
pivotTable.AddFieldToArea(Aspose.Cells.Pivot.PivotFieldType.Data, TOTALQTY_COLUMN);
pivotTable.AddFieldToArea(Aspose.Cells.Pivot.PivotFieldType.Data, TOTALPRICE_COLUMN);
pivotTable.AddFieldToArea(Aspose.Cells.Pivot.PivotFieldType.Data, AVGPRICE_COLUMN);
pivotTable.AddFieldToArea(Aspose.Cells.Pivot.PivotFieldType.Data, PERCENTOFTOTAL_COLUMN);
}
Here is the code I'm using to generate the PivotTable in Excel Interop:
private void PopulatePivotTableSheet()
{
var pch = _xlBook.PivotCaches();
int pivotDataRowsUsed = _xlBook.Worksheets["PivotData"].UsedRange.Rows.Count;
int pivotDataColsUsed = _xlBook.Worksheets["PivotData"].UsedRange.Columns.Count;
string lastColWrittenAsAlpha = ReportRunnerConstsAndUtils.GetExcelColumnName(pivotDataColsUsed);
string endRange = string.Format("{0}{1}", lastColWrittenAsAlpha, pivotDataRowsUsed);
Range sourceData = _xlBook.Worksheets["PivotData"].Range[string.Format("A1:{0}", endRange)];
PivotCache pc = pch.Create(XlPivotTableSourceType.xlDatabase, sourceData);
PivotTable pvt = pc.CreatePivotTable(_xlPivotTableSheet.Range["A6"], "PivotTable");
pvt.MergeLabels = true; // The only thing I noticed this doing was centering the heading labels
// Although somewhat confusing, these "error" settings actually prevent the "#DIV/0!" from displaying
pvt.ErrorString = "";
pvt.DisplayErrorString = true;
// This one converts what would otherwise be blank into "0" for ints and "$0" for decimal vals
pvt.NullString = "-";
var descField = pvt.PivotFields("Description");
descField.Orientation = XlPivotFieldOrientation.xlRowField;
var monthField = pvt.PivotFields("MonthYr");
monthField.Orientation = XlPivotFieldOrientation.xlColumnField;
monthField.NumberFormat = "MMM yy";
// This changes the label from "Column Labels"
pvt.CompactLayoutColumnHeader = "Months";
// This changes the label from "Row Labels"
pvt.CompactLayoutRowHeader = "Description";
pvt.AddDataField(pvt.PivotFields("TotalQty"), "Total Packages", XlConsolidationFunction.xlSum).NumberFormat = "###,##0";
pvt.AddDataField(pvt.PivotFields("TotalPrice"), "Total Purchases", XlConsolidationFunction.xlSum).NumberFormat = "$#,##0.00";
PivotField avg = pvt.CalculatedFields().Add("Average Price", "=TotalPrice/TotalQty", true);
avg.Orientation = XlPivotFieldOrientation.xlDataField;
avg.NumberFormat = "$###0.00";
// This looks wrong, but the value is calculated below
pvt.CalculatedFields()._Add("PercentOfTotal", "=TotalPrice");
pvt.AddDataField(pvt.PivotFields("PercentOfTotal"), "Percentage of Total", Type.Missing).NumberFormat = "###.##";
// These two lines don't seem that they would do so, but they do result in the items
// being sorted by (grand) total purchases descending
var fld = ((PivotField)pvt.PivotFields("Description"));
fld.AutoSort(2, "Total Purchases");
// This gets the Pivot Table to what it should be, appearance-wise...
pvt.DataPivotField.Orientation = XlPivotFieldOrientation.xlRowField;
// Add calculations to Percentage cells
int pivotDataSheetRowsUsed = _xlBook.Worksheets["PivotTable"].UsedRange.Rows.Count;
int pivotDataSheetColsUsed = _grandTotalsColumnPivotTable;
int FIRST_PERCENTAGE_ROW = 12;
int FIRST_PERCENTAGE_COL = 2;
int ROWS_BETWEEN_PERCENTAGES = 5;
int currentPercentageRow = FIRST_PERCENTAGE_ROW;
while (currentPercentageRow < pivotDataSheetRowsUsed)
{
for (int columnLoop = FIRST_PERCENTAGE_COL; columnLoop <= pivotDataSheetColsUsed; columnLoop++)
{
var prcntgCell = (Range)_xlPivotTableSheet.Cells[currentPercentageRow, columnLoop];
prcntgCell.NumberFormat = "##.#0%";
if (null == prcntgCell.Value2)
{
prcntgCell.Value2 = 0.0;
}
else
{
prcntgCell.PivotField.Calculation = XlPivotFieldCalculation.xlPercentOfColumn;
}
}
currentPercentageRow = currentPercentageRow + ROWS_BETWEEN_PERCENTAGES;
}
FormatPivotTable();
}
What do I need to change in my Aspose Cells code to shift the data fields (sans "Data" label) left and down? If this is the code in Excel Interop that does that:
pvt.DataPivotField.Orientation = XlPivotFieldOrientation.xlRowField;
...what is the Aspose Cells equivalent?

Please try one of these three things and see which one of it works for you.
//Your pivot table
PivotTable pt = .....
First
//To show pivot table in compact form
pt.ShowInCompactForm();
pt.RefreshData();
pt.CalculateData();
Second
//To show pivot table in outline form
pt.ShowInOutlineForm();
pt.RefreshData();
pt.CalculateData();
Third
//To show pivot table in tabular form
pt.ShowInTabularForm();
pt.RefreshData();
pt.CalculateData();
Note: I am working as Developer Evangelist at Aspose

Related

Loop through array and get row number for each element

I am quite new to Google Script, I'm learning on the job.
I have a range of data as a variable. It's only one column, column F in this case, but there are empty cells between values. I have a working script (got it from here earlier), which only loops through the cells with values in them. So lets say value1 is in F5, value2 is in F13, it's all random and always changing.
I'm trying to get the row number for these values, so that script should give back "5" for value1 and "13" for value2, ideally together with the value itself.
So far, that's what I have and I can not seem to progress further.
var sourceID = "sourceID";
var main = SpreadsheetApp.openById("mainID");
var mainsheet = main.getSheetByName("Lab Data");
var sourcesheet = source.getSheetByName("sheet name");
var dataRange = sourcesheet.getDataRange(); // range full sheet
var values = dataRange.getValues(); // values full sheet
var SWrowss = findCellForSW(); // getting start row from another function
var CQrowss = findCellForCQ(); // getting last row from another function
var noRows = CQrowss - SWrowss; // gets number of rows in range
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues(); // range we need, column F
// get rid of empty cells from range - copied script from stack overflow
var cResult = colss.reduce(function(ar, e) {
if (e[0]) ar.push(e[0])
return ar;
}, []);
Logger.log("cResult: " + cResult); // cResult contains all sub headers - no empty cells
// gets element's position in array
for(var b = 0; b < cResult.length; b++){
var position = b+1;
Logger.log("pos " + position);
} // end for
If you want to know the row number, I would propose you a different approach
Just loop through your values and retrieve the position of the ones that are not empty:
...
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rows = [];
var calues = [];
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
var row = SWrowss+b+1;
rows.push(row);
var value = colss[b][0];
values.push(value);
}
}
...
With the other solution you can build a single object that can do the conversion for you very quickly.
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rvObj={};
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
rvObj[colss[b][0]]=SWrowss+b+1;
}
}
With rvObj now you can get any row with var row = rvObj[value];

Google Sheet Script Help - Store/write sheet ID, sheet name, cell location for a combined range

I have created a script to combine information from several tabs to a "master elements" tab. The script pull in rows tagged with the "MS" designation and it works great. However, I also want to pull in the Sheetname, Sheet IT, and possiby a link to the source tab for each row with "MS". That information is currently not stored in any of the source tabs. Is that possible to do in script?
function combineData() {
var destination = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Masterelements');
// TO CLEAR DESTINATION TAB BEFORE REPOPULATION
destination.getRange('A2:g1000').clearContent();
//VARIABLE TO CYCLE THROUGH SPECIFIC SHEETS
var tabs = [
'A-000',
'B-123',
];
var ss = SpreadsheetApp.getActiveSpreadsheet();
for (var s = 0; s < tabs.length; s++) {
var sheet = ss.getSheetByName(tabs[s]);
Logger.log(sheet.getLastRow());
var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());
var destination = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Masterelements');
var values = range.getValues();
//Destination parameters - equivalent to destination.getRange();
var numberOfColumns = 7;
var numberOfRows = 1;
var startColumn = 1;
var startRow = 2;
var count = 0
// IDENTIFY THE FIRST ROW TO CONSOLIDATE ITEMS
var destRow = destination.getLastRow() + 1
for (var i = 0; i < values.length; i++) {
Logger.log("i is now: " + i);
Logger.log("Current row value: " + values[i][0])
if (values[i][0] == 'MS') {
Logger.log("*** Value found in cloumn: " + values[i][0] + "**** \n Count: " + i);
count++;
var rangeToCopy = sheet.getRange((i + 1), 1, numberOfRows, numberOfColumns);
var destinationRange = destination.getRange(destRow, startColumn, numberOfRows, numberOfColumns);
destRow++;
Logger.log("Next Destination row: " + destRow);
rangeToCopy.copyTo(destinationRange, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
}
}
}
}
The OP supplied working code that copies rows, from two specific sheets, with a value of "MS" in Column A. However the OP also wanted:
Sheetname
Sheet ID
possiby a link to the source tab for each row with "MS"
These are fairly easy to produce, but require too much information to explain in a comment.
I've taken the OP original code. I moved and/or edited some lines to make the code slightly more efficient. I've also added some lines of code to insert the Sheet name in Masterelements:Column H, the sheet ID in Masterelements:Column I and a link to the relevant sheet in Masterelements:Column J.
I think there is scope to make the code more efficient (specifically within the loops), but this is something that the OP can consider if the "real data" execution time is unreasonable.
function so54432164() {
// setup the spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get the spreadsheet URL - required for the hyperlink
var ssurl = ss.getUrl();
//Logger.log("DEBUG: The url for this spreadsheet is "+ssurl);//DEBUG
var destination = ss.getSheetByName('Masterelements');
// CLEAR DESTINATION TAB BEFORE REPOPULATION
// clear the entire destination sheet; this is more efficient that just clearing a nominated range
destination.clearContents();
// IDENTIFY THE first ROW TO CONSOLIDATE ITEMS
var destRow = destination.getLastRow() + 1
//VARIABLE TO CYCLE THROUGH SPECIFIC SHEETS
// note: no comma after the second tab name
var tabs = [
'A-000',
'B-123'
];
//Destination parameters
// note: brought this out of the "for" loop since only need to be declared once.
var numberOfColumns = 7;
var numberOfRows = 1;
var startColumn = 1;
var startRow = 2;
// used for destination.getRange();
// Loop through the sheets
for (var s = 0; s < tabs.length; s++) {
var sheet = ss.getSheetByName(tabs[s]);
// create variables to get the Sheet Name and the sheetID
var sheetname = sheet.getSheetName();
var sheetID = sheet.getSheetId();
//Logger.log("DEBUG: sheet: "+sheetname+", SheetID: "+sheetID);//DEBUG
// get the data: the var 'range' was never used, so we can just call the values direct to 'values'.
var values = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
//LOOP through the rows in the target sheet
for (var i = 0; i < values.length; i++) {
//Logger.log("DEBUG: row = " + i+", and Column A value: " + values[i][0]);//DEBUG
// test for "MS" in Column A
if (values[i][0] == 'MS') {
//Logger.log("DEBUG: Found MS, Count: " + i);//DEBUG
// define the range to copy
var rangeToCopy = sheet.getRange((i + 1), 1, numberOfRows, numberOfColumns);
// Logger.log("DEBUG: the rangetocopy is "+rangeToCopy.getA1Notation()); //DEBUG
// Define the destination range
var destinationRange = destination.getRange(destRow, startColumn, numberOfRows, numberOfColumns);
//Logger.log("DEBUG: the destination range "+destinationRange.getA1Notation());//DEBUG
// copy the source to the target
rangeToCopy.copyTo(destinationRange, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
// create a variable for the hyperlink formula
var formula = '=HYPERLINK("' + ssurl + '#gid=' + sheetID + '")';
// Logger.log("DEBUG: the formula = "+formula);//DEBUG
// create a variable for the extra data: Sheet name, Sheet ID, and the hyperlink to the sheet.
var extradata = [
[sheetname, sheetID, formula]
];
//define the destination range and set the values
destination.getRange(destRow, numberOfColumns + 1, numberOfRows, 3).setValues(extradata);
// increment the destination row
destRow++;
}
}
}
}

Cannot call method "push" of undefined

I'm trying to make a spreadsheet to upload products in Prestashop by .csv. Everything works like a charm, but now I need to be able to make some changes in already entered products with the same spreadsheet. The only thing I came up with is to manipulate text strings from a cell into a variable array (after that I'll find a way to go forward).
Firstly I managed to combine about ~100 cells into one cell (which I accomplished with a complicated formula) but now I need the text from this cell to be separated and temporarily stored in an array variable.
This is the formula. It's joining columns in rows with a : separator and then joins those rows with a ; separator and in the end I just needed a number:
=regexreplace(regexreplace(regexreplace(concatenate(arrayformula(if($A$13:$A$50="","",if($C$13:$C$50="","",$A$13:$A$50&":"&$C$13:$C$50&if($D$13:$D$50="","",$D$13:$D$50)&":"&(ROW($A$13:$A$50)-12)&";"))))," :",":"),": ",":"),"\+","-")
This resulted in this text:
Producător:GARMIN:1;Tip:Ceas inteligent:3;Model:Vivomove HR
Premium:4;Culoare:Gold:5;Culoare curea:Light
brown:6;Greutate:56.5g:8;Rezolutie display:64x128:9;Tip
ecran:OLED:10;GPS:Da:15;Bluetooth:Da:16;Durata in regim de asteptare
(ore):168:24;Sensori:Heart RATE, Activity Tracker, Barometric
altimeter, Accelerometer, Smart notifications, Weather, Step counter,
Move bar, Calories burned, Floors climbed, Analog
hands:26;Garanție:24luni:38;
Now I need to separate everything back as it was, but by a code in Apps Script, so that I will be able to manipulate the values separately, but they would still be in a structured form.
It should be something like this (inside a two dimensional variable):
[0][0]Producător [0][1]GARMIN
[1][0]Tip [1][1]Ceas inteligent
[2][0]Model [2][1]Vivomove HR Premium
[3][0]Culoare [3][1]Gold
[4][0]Culoare curea [4][1]Light brown
[5][0]Greutate [5][1]56.5g
[6][0]Rezolutie display [6][1]64x128
[7][0]Tip ecran [7][1]OLED
[8][0]GPS [8][1]Da
[9][0]Bluetooth [9][1]Da
[10][0]Durata in regim de asteptare (ore) [10][1]168
[11][0]Sensori [11][1]Heart RATE, Activity Tracker, Barometric altimeter, Accelerometer, Smart notifications, Weather, Step counter, Move bar, Calories burned, Floors climbed, Analog hands
[12][0]Garanție [12][1]24luni
And now the main part... The next code is breaking with the error Cannot call method "push" of undefined
//var ss = SpreadsheetApp.getActiveSpreadsheet();
//var activeSheet = ss.getActiveSheet();
//var idSpreadsheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1zRsGMoXJzG9oht_pr3Rr24ksPqBzTZIvNcYPUKfphNI/edit#gid=1264546658").getSheetByName("RO").getDataRange().getValues();
//var idToChange = activeSheet.getRange("A12").getValue();
var row = 0;
//var userID = Session.getActiveUser();
var bufferFeatures = [{}];
bufferFeatures = idSpreadsheet[10][29];
var bufferImages = idSpreadsheet[row][27];
//var productRows = bufferFeatures.indexOf(";",0);
var testColumn = [];
var pos = 0; //here is where we start the text string
var del = 0; //here is where we find the ";" delimiter and stop slicing text string
// THIS FOR LOOP WORKS FINE
for (pos = 0; pos < bufferFeatures.length; pos = del) {
del = bufferFeatures.indexOf(";", pos);
testColumn.push(bufferFeatures.slice(pos, del));
del++;
};
var rownr = 0; //current row number.. not really using this variable
var pos1 = 0; //here is where we start the text string
var del1 = 0; //here is where we find the ":" delimiter and stop slicing text string
var columnsAndRows = [];
columnsAndRows.push([]);
var j = 0;
//THIS FOR LOOP GIVES ME TROUBLE
for (var x = 0; x <= testColumn.length; x++) {
for (pos1 = 0; pos1 + 1 < testColumn[x].length; pos1 = pos1) {
del1 = testColumn[j].indexOf(":", del1);
var theSlice = testColumn[j].slice(pos1, del1);
var theStop = testColumn[j].length;
//for some reason, I can't get this code to "push" j=2)
Logger.log("Adding " + theSlice);
columnsAndRows[j].push(theSlice);
del1++;
pos1 = del1;
Logger.log("Added")
}
Logger.log("Next row");
del1 = 0
j++;
//rownr++;
};
You need to declare columnsAndRows[j] as a array too.
columnsAndRows[j] = [];
Using split() would be much easier:
function strToArr(string) {
if (!string) {
var string = "Producător:GARMIN:1;Tip:Ceas inteligent:3;Model:Vivomove HR Premium:4;Culoare:Gold:5;Culoare curea:Light brown:6;Greutate:56.5g:8;Rezolutie display:64x128:9;Tip ecran:OLED:10;GPS:Da:15;Bluetooth:Da:16;Durata in regim de asteptare (ore):168:24;Sensori:Heart RATE, Activity Tracker, Barometric altimeter, Accelerometer, Smart notifications, Weather, Step counter, Move bar, Calories burned, Floors climbed, Analog hands:26;Garanție:24luni:38; "
}
var arr1 = string.substr(0, string.lastIndexOf(";")).split(';'); //split by ;
var arr2 = arr1.map(function(e) { return e.split(':').slice(0,2)}); //split each element of arr1 by : and return only the first two elements
Logger.log(arr2);
return arr2;
}

Append row based on value in another cell

Using a Google App Script I'm looking to find any ID's from Sheet2 which exist in Sheet1 and append the comment field within Sheet1 with what is listed in the Comment field in Sheet2.
Sheet1: Holds all data based on ID
Sheet2: Holds comments relating to some ID's in Sheet1
Sheet1 Example
ID Type In Stock Comment
1 Apple Yes
2 Banana No
3 Orange Yes
Sheet2 Example
ID Comment
1 Text
2 Text
Code
This is code I've been using for something else which loops through my source data to identify a variable called "Yes", obviously this won't work for this case as the ID is the variable we need to find which is dynamic.
I'm just a bit lost on how to modify this code so that it will loop through Sheet2, get all the IDs, check those IDs against Sheet1. If those IDs exist in Sheet1 update the comment of Sheet1 with the comment already listed in Sheet2
function setComment(){
var outputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var lastRow = outputSheet.getLastRow();
var lastCol = outputSheet.getLastColumn();
var targetValues = [];
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var lastSourceRow = sourceSheet.getLastRow();
var lastSourceCol = sourceSheet.getLastColumn();
var sourceRange = sourceSheet.getRange(1, 1, lastSourceRow, lastSourceCol);
var sourceData = sourceRange.getValues();
{
//Loop through every retrieved row from the Source
for (row in sourceData) {
//IF Column I in this row has 'Yes', then work on it.
if (sourceData[row][1] === 'Yes') {
//Save it ta a temporary variable
var tempvalue = [sourceData[row][0], sourceData[row][7]];
//then push that into the variables which holds all the new values to be returned
targetValues.push(tempvalue);
}
}
//Save the new range to the appropriate sheet starting at the last empty row
outputSheet.getRange(lastRow + 1, 1 , targetValues.length, 2).setValues(targetValues);
}
}
Yes you need to loop through one group of IDs. In that loop you need to nest a loop that goes through the other group of IDs.
Code
function setComments() {
var ss = SpreadsheetApp.getActive(),
compare1 = "", compare2 = "",
outputSheet = ss.getSheetByName("Sheet1"),
sourceSheet = ss.getSheetByName("Sheet2"),
range1 = outputSheet.getDataRange(),
range2 = sourceSheet.getDataRange(),
lastCol1 = range1.getNumColumns(),
lastCol2 = range2.getNumColumns(),
values1 = range1.getValues(),
values2 = range2.getValues(),
// get the range of the titles
titleSection1 = outputSheet.getRange(1,1,1, lastCol1),
titleSection2 = sourceSheet.getRange(1,1,1, lastCol2),
// get the values from the titles
titles1 = titleSection1.getValues(),
titles2 = titleSection2.getValues(),
// get the column # for "ID" and "comment"
idCol1 = titles1[0].indexOf("ID"),
idCol2 = titles2[0].indexOf("ID"),
commentsCol1 = titles1[0].indexOf("comment"),
commentsCol2 = titles2[0].indexOf("comment");
// get the IDs from range1
for (i = 1; i < values1.length; i++) {
compare1 = values1[i][idCol1];
// get the IDs from range2
for (j = 1; j< values2.length; j++){
compare2 = values2[j][idCol2];
// if same ID, change the values array
if (compare1 == compare2) {
values1[i][commentsCol1] = values2[j][commentsCol2];
}
}
}
// set values based on the values array
range1.setValues(values1);
}

for loop not iterating over last element of 2D array in google app script (GAS)

I am working on a script that, in part, takes an array of names, compares each name to column A in a sheet, and returns with a row matched value in column B. (Like the vLookup command in sheets)
The setup
var ss = SpreadsheetApp.getActiveSpreadsheet();
var clientsSheet = ss.getSheetByName("Clients");
var cRow = clientsSheet.getLastRow();
var cColumn=clientsSheet.getLastColumn();
var cData=clientsSheet.getRange(1,1,cRow,cColumn).getValues(); //create array of client data
The trouble code
//put each client on their own row and add hour
for(i=0; i < client.length; ++i){
var cl = client[i]
//iterate over array of clients (column A) and hours (Column B) to find match and log the number in column B
for(j=0;j<cData.length;++j){
if (cData[j][0]==cl){
var hour = cData[j][1];
}
}
//return the matched values
Logger.log(cl+" - "+hour);
}
The var 'client' is an array that was split from a list of names in a single cell that are separated by commas (see whole code below)
At the moment it works great except that it misses the last element in the array.
for example:
if I have a sheet with two columns and three rows like so:
A 1
B 2
C 3
I would get back
A-1
B-2
C-
It is missing that last piece on the last element - it should be
A-1
B-2
C-3
I am stumped, and I know that it must be some simple little thing.
Any help would be amazing
Thanks!
The Code:
function logClients()
/*
Take data from a google form check box submissions. Check box submissions put all checked answers into a single cell separated by a comma. The function first takes the most recently submitted row, removes unneeded spaces, and splits each element into its own part of an array.
Then, the function compares each clients name in the array to a sheet with other info, such as the default number of hours we meet. It takes the clients name, the date of submission, and the hours, and logs them on a new row in two different sheets, the Hours sheet and the Trans Log sheet.
*/
var ss = SpreadsheetApp.getActiveSpreadsheet();
var logSheet = ss.getSheetByName("Log"); //Raw data from the Google form
var hourSheet = ss.getSheetByName("Hours"); //logged data for my records, separated into individual clients
var transLog = ss.getSheetByName("Trans Log"); // logged data minus "other" catagory
var clientsSheet = ss.getSheetByName("Clients"); //sheet containing all clients names and the typical hours we meet
var lRow = logSheet.getLastRow();
var hRow = hourSheet.getLastRow();
var tRow = transLog.getLastRow();
var cRow = clientsSheet.getLastRow();
var cColumn = clientsSheet.getLastColumn();
var cData = clientsSheet.getRange(1, 1, cRow, cColumn).getValues();
//get list of clients from cell and split it into an array
var Client = logSheet.getRange(lRow, 2).getValue().replace(", ", ","); //remove all spaces after a comma
var client = Client.split(",");
//get "other" information and do the same
var Other = logSheet.getRange(lRow, 5).getValue().replace(", ", ",");
var other = Other.split(",");
//check the date and set to today if nothing else has been entered
var dcell = logSheet.getRange(lRow, 4).getValue();
var date = new Date()
if (dcell == "") {} else if (dcell == "Yesterday") {
date = new Date(date.getTime() - 1 * (24 * 3600 * 1000));
} else {
date = dcell
}
var date = Utilities.formatDate(date, "GMT-8", "MM/dd/yy"); //format date
//put each client on their own row
for (i = 0; i < client.length; ++i) {
var cl = client[i]
var hour = logSheet.getRange(lRow, 3).getValue(); //hours
if (hour == !"") {
break;
}
for (j = 0; j < cData.length; ++j) {
if (cData[j][0] == cl) {
var hour = cData[j][1];
}
}
Logger.log(date + " - " + cl + " - " + hour);
hourSheet.appendRow([date,cl, hour]);
transLog.appendRow([date, cl, hour]);
}
//put each client on their own row
for (i = 0; i < other.length; i++) {
hourSheet.appendRow([date, other[i], getHour(client[i])]);
}
} //end of function
``
This is a code that I have been working on to teach myself Java and Apps-script
Yup, simple mistake.
Not all of the spaces before each name were being removed from the array, so the if statement would skip right over them because they were not a true match

Resources