Pushing values to getColumn.values for Excel add In - javascript

So I am trying to import and read a json to an excel sheet, using an add-in I'm developing. So I've gotten to a point where I'm getting ColumnA and ColumnB from my new worksheet. Then I'm trying to push the json fields onto the Range.values arrays of the columns. However once I run the program the worksheet is still blank. Here is the code:
function importJson(json, name){
Excel.run(function (context) {
...
var sheetRange = newWorksheet.getRange("A1:B1");
sheetRange.load('values');
var aColumn = sheetRange.getColumn(0);
var bColumn = sheetRange.getColumn(1);
aColumn.load('values');
bColumn.load('values');
return context.sync().then(function () {
printJson(json, aColumn, bColumn);
});
});
printJson(json, aColumn, bColumn)
{
if (json instanceof Object) {
aColumn.values.push(json.display);
if (json.default != null) {
bColumn.values.push(json.default);
}
}
if (json.fields != null) {
for (var i = 0; i < json.fields.length; i++) {
printSchema(json.fields[i], aColumn, bColumn);
}
}
}
Running the debugger I see the values from the json object being pushed onto the arrays but run I still don't see them on the worksheet
Thanks for any help!

So Thanks to a little nudge from #TimWilliams, it was realized that I wasn't updating the worksheets values within my printJson method. So once I pushed all of the values I wanted in Column A and Column B I added this step in my last return sync().then(function(){})....
Excel.run(function (context) {
...
var sheetRange = newWorksheet.getRange("A1:B1");
sheetRange.load('values');
var aColumn = sheetRange.getColumn(0);
var bColumn = sheetRange.getColumn(1);
aColumn.load('values');
bColumn.load('values');
return context.sync().then(function () {
printJson(json, aColumn, bColumn);
****
for (var i = 1; i < aColumn.values.length + 2; i++)
{
var aColumnSheet = newWorksheet.getRange("A" + i);
aColumnSheet.values = aColumn.values[i];
}
for (var i = 1; i < bColumn.values.length + 2; i++) {
var bColumnSheet = newWorksheet.getRange("B" + i);
bColumnSheet.values = bColumn.values[i];
}
*****
});
});
Gives me two beautiful columns of data in Column A and Column B. Thanks again #TimWilliams!

Related

How do I read a cvs file in javascript and store them in map?

say if I have csv file with :
Heading 1 , Heading 2 , Heading 3
Value 1 , Value2 , Value 3
All I want is to create a map that stores Heading 1 as a key and Heading 2 as value;
like map.set(value1 , value2)
How do I do this while I read the file in javascript ?
function processData(allText) {
var allTextLines = allText.split("\r");
for (var i=1; i<allTextLines.length; i++) {
var data = allTextLines[i].split(',');
console.log(data[0]);
map1.set(data[0] , data[1]);
}
}
so far I tried to do this . But it doesn't work. It doesn't read the file at all. Any help is appreciated.
Thanks
If you have a series of items separated by commas (,), the you can iterate the String and explode or split the items. This can be done with Vanilla JavaScript. The magic part is the for() loop; iterating it by 2 instead of by 1, which is most commonly seen.
$(function() {
var myString = "Header 1,Value 1,Header 2,Value 2,Header 3,Value 3";
var parts = myString.split(",");
var myData = {};
for (var i = 0; i < parts.length; i += 2) {
myData[parts[i]] = parts[i + 1];
}
console.log(myData);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
If your file has multiple lines, and the first line is Headers, for example:
Header 1,Header 2,Header 3
Value 1,Value 2,Value 3
Value 4,Value 5,Value 6
You'll have to treat it differently. When it's brought into JS, it will be one big String, and you will have to first split it by End Of Line (EOL). This will create an Array of Strings that must be iterated. You will want to make an Array of Keys and then a Matrix of Values.
Since the file is Local, you will need to first get the File from the User. This is discussed here: How to read data From *.CSV file using javascript? and here: Reading in a local csv file in javascript? You will have to determine the best method for yourself.
One way is to use a File Input. There are drawbacks and caveats due to security and browsers, but it might work.
$(function() {
var fileInput = $("#getFile");
function toObj(keys, vals) {
var obj = {};
for (var i = 0; i < keys.length; i++) {
obj[keys[i]] = vals[i];
}
return obj;
}
function stringToObject(str, header) {
if (header == undefined) {
header = false;
}
var lines = str.split("\n");
var k = [],
m = [];
if (header) {
k = lines.splice(0, 1);
k = k[0].split(",");
}
$.each(lines, function(i, el) {
if (el.length) {
m.push(el.split(","));
}
});
if (k.length) {
var r = [];
$.each(m, function(i, el) {
r.push(toObj(k, el));
});
return r;
} else {
return m;
}
}
function readFile() {
var reader = new FileReader();
reader.onload = function() {
var newData = stringToObject(reader.result, $("#header").prop("checked"));
console.log(newData);
$("#out").html("<pre>" + reader.result + "</pre>");
};
reader.readAsBinaryString(fileInput[0].files[0]);
};
fileInput.change(readFile);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="file input">
<input type="checkbox" id="header" checked="checked"> <label>CSV Header</label><br />
<input type="file" id="getFile" />
</div>
<div id="out"></div>

Is it possible to show interpolated data using dygraphs?

I have been working for the last months with dygraphs. It is a incredible library and I have got great results but I´m having some problems to find the way of interpolating data from different signals to be shown in the same chart.
The data I received from different sensors have not the same timestamp for the different samples, so for the most of the points of the x axe timestamps I have only the value of one signal. The chart is plotted perfectly, but I would like to see the interpolated value of the rest of the signals in that x point I am pointing over. Below I have the chart I get.
Reading on the dygraph documentation I have seen that when you have independent series, it is possible to see at least the value "undefined" for the signals without data in that point of the x axe.
The csv I use to plot the data is shown below. It has the same structure indicated in the dygraph documentation but I don´t get this undefined label neither.
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
Thanks in advance.
This is an approach that does not add any data to your csv data and still provides interpolated values for all the columns as you move your mouse around. It adds a listener to the mousemove event within dygraph and interpolates the closest points for all of the data. At the moment I have simply shown it in an extra DIV that is after the graph but you can display it however you like:
function findNextValueIndex(data, column, start) {
var rows = data.length;
for (var i = start; i < rows; i++) {
if (data[i][column] != null) return (i);
}
return (-1);
}
function findPrevValueIndex(data, column, start) {
for (var i = start; i >= 0; i--) {
if (data[i][column] != null) return (i);
}
return (-1);
}
function interpolate(t0, t1, tmid, v0, v1) {
return (v0 + (tmid - t0) / (t1 - t0) * (v1 - v0));
}
function showValues(headers, colors, vals) {
var el = document.getElementById("info");
var str = "";
for (j = 1; j < headers.length; j++) {
str += '<p style="color:' + colors[j] + '";>' + headers[j] + ": " + vals[j] + "</p>";
}
el.innerHTML = str;
document.getElementById("hiddenDiv").style.display = "none";
}
function movecustom(event, dygraph, point) {
var time = dygraph.lastx_;
var row = dygraph.lastRow_;
var vals = [];
var headers = [];
var colors = [];
var cols = dygraph.rawData_[0].length;
// draw a line on the chart showing the selected location
var canvas = dygraph.canvas_;
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = "rgba(0,200,200,0.1)";
ctx.moveTo( dygraph.selPoints_[0].canvasx, 0);
ctx.lineTo( dygraph.selPoints_[0].canvasx, 1000);
ctx.stroke();
for (var j = 1; j < cols; j++) {
colors[j] = dygraph.colors_[j - 1];
if (dygraph.rawData_[row][j] == null) {
var prev = findPrevValueIndex(dygraph.rawData_, j, row - 1);
var next = findNextValueIndex(dygraph.rawData_, j, row + 1);
if (prev < 0)
vals[j] = dygraph.rawData_[next][j];
else if (next < 0)
vals[j] = dygraph.rawData_[prev][j];
else {
vals[j] = interpolate(dygraph.rawData_[prev][0], dygraph.rawData_[next][0], time, dygraph.rawData_[prev][j], dygraph.rawData_[next][j]);
}
} else {
vals[j] = dygraph.rawData_[row][j];
}
}
headers = Object.keys(dygraph.setIndexByName_);
showValues(headers, colors, vals);
}
window.onload = function() {
new Dygraph(
document.getElementById('graph'), document.getElementById('csvdata').innerHTML, {
connectSeparatedPoints: true,
drawPoints: true,
labelsDiv: "hiddenDiv",
interactionModel: {
'mousemove': movecustom
}
}
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.js"></script>
<div id="graph" style="height:120px;"></div>
<div id="info"></div>
<div id="hiddenDiv" style="display:none"></div>
<pre id="csvdata" style="display:none">
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
</pre>
It seems that the best way to do this is to massage the data before submitting it to the dygraph call. This means the following steps:
1) parse the csv file into an array of arrays.
2) go through each line of the array to find where the holes are
3) interpolate to fill those holes
4) modify the constructed arrays to be displayed by dygraph
5) call dygraph
Not the most attractive code, but seems to work...
function findNextValueIndex(data, column, start) {
var rows = data.length;
for(var i=start;i<rows;i++) {
if(data[i][column].length>0) return(i);
}
return(-1);
}
function interpolate(t0, t1, tmid, v0, v1) {
return((v0 + (tmid-t0)/(t1-t0) * (v1-v0)).toString());
}
function parseCSV(string) {
var data = [];
// first get the number of lines:
var lines = string.split('\n');
// now split the first line to retrieve the headings
var headings = lines[0].split(",");
var cols = headings.length;
// now get the data
var rows=0;
for(var i=1;i<lines.length;i++) {
if(lines[i].length>0) {
data[rows] = lines[i].split(",");
rows++;
}
}
// now, fill in the blanks - start by finding the first value for each column of data
var vals = [];
var times = [];
for(var j=1;j<cols;j++) {
var index = findNextValueIndex(data,j,0);
vals[j] = parseFloat(data[index][j]);
}
// now put those start values at the beginning of the array
// there is no way to calculate the previous value of the sensor missing from the first sample
// so we use the first reading and duplicate it
for(var j=1;j<cols;j++) {
data[0][j] = vals[j].toString();
times[j] = parseInt(data[0][0]);
}
// now step through the rows and interpolate the missing values
for(var i=1;i<rows;i++) {
for(var j=1;j<cols;j++) {
if(data[i][j].length>0) {
vals[j] = parseFloat(data[i][j]);
times[j] = parseInt(data[i][0]);
}
else {
var index = findNextValueIndex(data,j,i);
if(index<0) // no more data in this column
data[i][j] = vals[j].toString();
else
data[i][j] = interpolate(times[j],parseInt(data[index][0]),parseInt(data[i][0]),vals[j],data[index][j]);
}
}
}
// now convert from strings to integers and floats so dygraph can handle it
// I've also changed the time value so that it is relative to the first element
// it will be shown in milliseconds
var time0 = parseInt(data[0][0]);
for(var i=0;i<rows;i++) {
data[i][0] = parseInt(data[i][0]) - time0;
for(var j=1;j<cols;j++) {
data[i][j] = parseFloat(data[i][j]);
}
}
var obj = {
labels: headings,
data: data
}
return(obj);
}
window.onload = function () {
var data_obj = parseCSV(document.getElementById('csvdata').innerHTML);
new Dygraph(
document.getElementById('graph'), data_obj.data,
{
labels: data_obj.labels,
connectSeparatedPoints: true,
drawPoints: true
}
);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.js"></script>
<div id="graph" style="height:200px;"></div>
<pre id="csvdata" style="display:none">
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
</pre>
Does
connectSeparatedPoints: true
Not do what you need?

Getting trouble while trying Dynamic Data in jsPdf AutoTable

Am trying to print the dynamic data into the PDF using jsPdf AutoTable .But am failed to do that. I searched in many site's but no one didn't said about dynamic data into the Row's. So here my question is , Is there any way to get the Dynamic data into the table row's if it so can some one clarify me pls . Note : [ Here am not using HTML to store the Data into the Pdf, i got the data from the js directly ] .
this.print=function(){
{
var mainData =this.printData(); // Here am getting Full Json data Here
var steps = mainData.steps; // From that data am Separating what i need
var criticality = mainData.criticality;
var categories = mainData.categories;
var checkup = mainData.checkup;
// This is For to Take the Steps Data alone
$scope.getSteps = function(steps) {
var data = [];
for (var i = steps.length; i-- > 0;) {
data.push(steps[i].name+"\n"+"\n");
}
return data;
}
// Like wise am getting every single object data's
$scope.getNumbersOfSubSteps = function(steps) {
var data = 0;
for (var i = 0 ; i < steps.length; i++) {
for (var j = 0; j<steps[i].steps.length; j++) {
}
data = j ;
}
return data;
}
// this is for Sub Proceeses
$scope.getSubProcesses = function(steps) {
var data = [];
for (var i = 0 ; i < steps.length; i++) {
for (var j = 0; j<steps[i].steps.length; j++) {
data.push(steps[i].steps[j].name+"\n");
}
}
return data;
}
$scope.getCategories = function(categories) {
var data = [];
for (var i = categories.length; i-- > 0;) {
data.push(categories[i].name+"\n");
}
return data;
}
$scope.getCriticality = function(criticality) {
var data = [];
for (var i = criticality.length; i-- > 0;) {
data.push(criticality[i].name+"\n");
}
return data;
}
// Pdf Print Function Begins
var columns = ["ProcessDescription", "Steps", "#ofSubProcesses", "SubSteps","Category","Criticality","CheckUp"];
var processDescription =mainData.description;
var processes= $scope.getSteps(steps);
var NoOfSubProcess = $scope.getNumbersOfSubSteps(steps);
var subProcesses = $scope.getSubProcesses(steps);
console.log('Subprocsses length',subProcesses);
var categories = $scope.getCategories(categories);
var criticality = $scope.getCriticality(criticality);
// The Problem Begins here , Am struggling to Get the Separate data's here !
var rows = [
[processDescription,processes,NoOfSubProcess,subProcesses,categories,criticality]
];
var pdfsize='a1';
var doc = new jsPDF('p', 'pt',pdfsize);
doc.autoTable(columns, rows, {
theme: 'striped', // 'striped', 'grid' or 'plain'
styles: {
overflow: 'linebreak',
columnWidth: 'wrap'
},
beforePageContent: function(data) {
doc.text("Process Name :"+mainData.name, 40, 30);
},
columnStyles: {
1: {columnWidth: 'auto'}
}
});
doc.save(mainData.name+ pdfsize +".pdf");
}
};
You will need to replace this:
var rows = [
[processDescription,processes,NoOfSubProcess,subProcesses,categories,criticality]
];
with something like this:
var rows = [];
for (var k = 0 ; k < processes.length; k++) {
rows.push([
processDescription,
processes[k],
NoOfSubProcess,
subProcesses[k],
categories[k],
criticality[k]
]);
};
The rows parameter should be an array of arrays. What you are putting in there is basically an array of an array of arrays if I understood correctly.

Push data to different elements, depending on column in google spreadsheet with GAS?

I am working in Google Spreadsheet with GAS, and I am trying to push some data from a spreadsheet to an HTML page, and right now that is working. But I am managing to do is grabbing all the values, and each time it hits a new row, it grabs all the values in that row pushes them into a newly created <div>. But I would like to do is have some column functionality also so that the different columns gets pushed to a different element like an <input> or a <select> element.
I tried out some things where I declared some variables for the desired columns, and trying to pushing them to the HTML one by one, but it didn't work out.
Here is my data:
This is what it looks like in the HTML:
This is what I am going for:
Would it be better to publish this into tables? Because I simply thought of creating divs with classes and set their width and line breaks?
Below is the code I described in the beginning:
Code.gs
var ss = SpreadsheetApp.openById("1c7IwmyBrbNq5xwzo-7EyFewCx31WpfP4EzLpkHawffI");
function doGet(request) {
return HtmlService.createTemplateFromFile('stuff')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function getStitchOrders(){
var ordersName = [];
var sheet = ss.getSheetByName("Cat1");
var subRange = sheet.getRange(2, 1, sheet.getLastRow(), sheet.getLastColumn());
var orders = subRange.getValues();
for (var i = 0; i < orders.length; i++) {
ordersName.push( orders[i] )
}
return ordersName;
}
stuff.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="orders">
//Data is listed here.
</div>
<script>
$(function() {
google.script.run.withSuccessHandler(buildOrderList).getStitchOrders();
});
function buildOrderList(ordersName) {
var rows = $('#orders');
for (var i = 0; i < ordersName.length; i++) {
rows.append('<div name="' + ordersName[i] + '">' + ordersName[i] + '</div>');
}
}
</script>
Any suggestions?
Edit
Code2.gs
var ss = SpreadsheetApp.openById("1c7IwmyBrbNq5xwzo-7EyFewCx31WpfP4EzLpkHawffI");
function doGet(request) {
return HtmlService.createTemplateFromFile('stuff2')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function getStitchOrders(){
var ordersName = [];
var sheet = ss.getSheetByName("Sheet");
var subRange = sheet.getRange(2, 1, sheet.getLastRow(), sheet.getLastColumn());
var orders = subRange.getValues();
for (var i = 0; i < orders.length; i++) {
ordersName.push( {
name: orders[i][0],
status: orders[i][1],
comment: orders[i][2]
} );
}
return JSON.stringify(ordersName);
}
stuff2.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="orders">
</div>
<script>
$(function() {
google.script.run.withSuccessHandler(buildOrderList).getStitchOrders();
});
function buildOrderList(ordersName) {
var arr = JSON.Parse(ordersName);
var rows = $('#orders');
for (var i = 0; i < arr.length; i++) {
rows.append('<div name="' + arr[i].name + '">' + arr[i].name + '</div>');
}
}
</script>
consider returning the data with this type of pattern:
for (var i = 0; i < orders.length; i++) {
ordersName.push( {
name: orders[i][0],
status: orders[i][1],
comment: orders[i][2]
} );
}
return JSON.stringify(ordersName);
then back in the client-side JS we can turn it back into an Array to loop through:
function buildOrderList(ordersName) {
var arr = JSON.parse(ordersName);
var rows = $('#orders');
for (var i = 0; i < arr.length; i++) {
// values can now be referenced via...
// arr[i].name
// arr[i].status;
// arr[i].comment;
rows.append(...);
}
}
how to then style the divs and the elements inside them to align up like a table is more a CSS question.

Paging in slickGrid

I was able to utilize paging in slickGrid however I am new to jquery and slickGrid and can't get to move in between pages. can anyone help me with this? Any help is greatly appreciated. Thanks!
$(document).ready(function() {var columns = [
{id:"counter", name:"#",field:"counter"},
{id:"data1", name:"Data 1",field:"data1"},
{id:"data2", name:"Data 2",field:"data2"},
{id:"data3", name:"Data 3",field:"data3"},
{id:"data4", name:"Data 4",field:"data4"}];
var options = { enableCellNavigation: false,
enableColumnReorder: false};
var FB_C_grid;
var FB_C_data;
var selectedRowIds = [];
var dataView;
$(function() {
FB_C_data = [];
FB_C_data[0]={"id":"0",
"data1":"test1",
"data2":"test1",
"data3":"test1",
"data4":"test1,
"counter":"1"
};
for (var i=1; i<50000; i++) {
var d = (FB_C_data[i] = {});enter code here
d["id"] = "id_" + i;
d["data1"] = "data1_" + i;
d["data2"] = "data2_" + i;
d["data3"] = "data3_" + i;
d["data4"] = "data4_" + i;
d["counter"] = i;
}
dataView = new Slick.Data.DataView();
dataView.setItems(FB_C_data);
dataView.setPagingOptions({pageSize:20});
FB_C_grid= new Slick.Grid($("#FB_C_sheet"),dataView.rows, columns,options);
var pager = new Slick.Controls.Pager(dataView, FB_C_grid, $("#pagerTest"));
dataView.onRowsChanged.subscribe(function(rows) {
FB_C_grid.removeRows(rows);
FB_C_grid.render();
if (selectedRowIds.length > 0)
{
// since how the original data maps onto rows has changed,
// the selected rows in the grid need to be updated
var selRows = [];
for (var i = 0; i < selectedRowIds.length; i++)
{
var idx = dataView.getRowById(selectedRowIds[i]);
if (idx != undefined)
selRows.push(idx);
}
FB_C_grid.setSelectedRows(selRows);
}
});
dataView.onPagingInfoChanged.subscribe(function(pagingInfo) {
var isLastPage = pagingInfo.pageSize*(pagingInfo.pageNum+1)-1 >= pagingInfo.totalRows;
var enableAddRow = isLastPage || pagingInfo.pageSize==0;
var options = FB_C_grid.getOptions();
if (options.enableAddRow != enableAddRow)
FB_C_grid.setOptions({enableAddRow:enableAddRow});
});
dataView.onRowCountChanged.subscribe(function(args) {
FB_C_grid.updateRowCount();
FB_C_grid.render();
});
})
});
I see some of your errors as you are trying to pass a jQuery object into SlickGrid while SlickGrid already uses jQuery in the code behind. When you create your SlickGrid object, you just need to pass the name of your grid and so in your code, you have to replace this $("#pagerTest") without jQuery wrapper becomes this "#pagerTest"
I see you called it the same in 2 different locations, so replace your 2 lines with this:
FB_C_grid= new Slick.Grid("#FB_C_sheet",dataView.rows, columns,options);
var pager = new Slick.Controls.Pager(dataView, FB_C_grid, "#pagerTest");
Hope that helps you make it to work...

Categories

Resources