This pertains within a BPM application called ProcessMaker but the logic and syntax should relatively be the same. I'm trying to
populate a grid (basically a table) from another serialized grid where the data has been passed to a hidden field.
The data passed to the hidden field is formatted as follows:
Ex:
{"1":{"id":"4332","product":"ball","price":"$5.00",”ordered":"On"}
The javascript example below found on processmaker's wiki unserializes the hidden field as an object and uses its information to populate a new grid named whatever it is. The example on processmaker's wiki uses the eval function but how would you convert this using the json.parse() function?
function populateGrid() {
var grd = getObject("newAccountsGrid");
//remove all existing rows in the grid (except the first one):
var i = Number_Rows_Grid("newAccountsGrid", "accId");
for (; i > 1; i--)
grd.deleteGridRow(i, true);
//The first row can't be deleted, so clear the fields in the first row:
for (i = 0; i < grd.aFields.length; i++)
getGridField("contactsGrid", 1, grd.aFields[i].sFieldName).value = "";
//unserialize the hidden field as an object:
var oAccounts = eval('(' + getField("sAccounts").value + ')');
if (typeof oAccounts == 'object') {
for (var rowNo in oAccounts) {
if (rowNo != 1)
grd.addGridRow();
getGridField('newAccountsGrid', rowNo, 'accId').href = oAccounts[rowNo]["accountId"];
getGridField('newAccountsGrid', rowNo, 'accName').href = oAccounts[rowNo]["accountName"];
getGridField('newAccountsGrid', rowNo, 'createDate').href = oAccounts[rowNo]["created"];
}
}
}
populateGrid(); //execute when the DynaForm loads
It would be as simple as:
var oAccounts = JSON.parse(getField("sAccounts").value);
eval("("+something+")") ⇒ JSON.parse(something)
Just a few lines above this example (ProcessMaker wiki), is a note where recommend using JSON.parse ().
Using your example, your code should be as follows:
function populateGrid() {
var grd = getObject("newAccountsGrid");
//remove all existing rows in the grid (except the first one):
var i = Number_Rows_Grid("newAccountsGrid", "accId");
for (; i > 1; i--)
grd.deleteGridRow(i, true);
//The first row can't be deleted, so clear the fields in the first row:
for (i = 0; i < grd.aFields.length; i++)
getGridField("contactsGrid", 1, grd.aFields[i].sFieldName).value = "";
//unserialize the hidden field as an object:
var oAccounts = JSON.parse(getField("sAccounts").value);
if (typeof oAccounts == 'object') {
for (var rowNo in oAccounts) {
if (rowNo != 1)
grd.addGridRow();
getGridField('newAccountsGrid', rowNo, 'accId').href = oAccounts[rowNo]["accountId"];
getGridField('newAccountsGrid', rowNo, 'accName').href = oAccounts[rowNo]["accountName"];
getGridField('newAccountsGrid', rowNo, 'createDate').href = oAccounts[rowNo]["created"];
}
}
}
populateGrid(); //execute when the DynaForm loads
Related
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>
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!
I have an object "Driver" defined at the beginning of my script as such:
function Driver(draw, name) {
this.draw = draw;
this.name = name;
}
I'm using this bit of JQuery to create new drivers:
var main = function () {
// add driver to table
$('#button').click(function ( ) {
var name = $('input[name=name]').val();
var draw = $('input[name=draw]').val();
var draw2 = "#"+draw;
var name2 = "driver"+draw
console.log(draw2);
console.log(name2);
if($(name2).text().length > 0){
alert("That number has already been selected");}
else{$(name2).text(name);
var name2 = new Driver(draw, name);}
});
That part is working great. However, when I try later on to access those drivers, the console returns that it is undefined:
$('.print').click(function ( ) {
for(var i=1; i<60; i++){
var driverList = "driver"+i;
if($(driverList.draw>0)){
console.log(driverList);
console.log(driverList.name);
}
If you're interested, I've uploaded the entire project I'm working on to this site:
http://precisioncomputerservices.com/slideways/index.html
Basically, the bottom bit of code is just to try to see if I'm accessing the drivers in the correct manner (which, I'm obviously not). Once I know how to access them, I'm going to save them to a file to be used on a different page.
Also a problem is the If Statement in the last bit of code. I'm trying to get it to print only drivers that have actually been inputed into the form. I have a space for 60 drivers, but not all of them will be used, and the ones that are used won't be consecutive.
Thanks for helping out the new guy.
You can't use a variable to refer to a variable as you have done.
In your case one option is to use an key/value based object like
var drivers = {};
var main = function () {
// add driver to table
$('#button').click(function () {
var name = $('input[name=name]').val();
var draw = $('input[name=draw]').val();
var draw2 = "#" + draw;
var name2 = "driver" + draw
console.log(draw2);
console.log(name2);
if ($(name2).text().length > 0) {
alert("That number has already been selected");
} else {
$(name2).text(name);
drivers[name2] = new Driver(draw, name);
}
});
$('.print').click(function () {
for (var i = 1; i < 60; i++) {
var name2 = "driver" + i;
var driver = drivers[name2];
if (driver.draw > 0) {
console.log(driver);
console.log(driver.name);
}
Let's say I have few rows of data populated with numbers. I want to select multiple cells and then on click on a button outside the grid change their values to some other number, let's say '8'. See the sample.
The guys at Telerik gave me this solution:
$(".change").click(function () {
var grid = $("#Grid").data("kendoGrid");
var cellsToChange = grid.select();
for (var i = 0; i < cellsToChange.length; i++) {
var item = grid.dataItem($(cellsToChange[i]).closest("tr"));
item.ProductName = "new value";
}
grid.refresh();
});
But the problem is that I don't know which cells will be selected, so I can't work with item.ProductName, for example. Is there a way to set the value of all selected cells directly, something like cellsToChange[i].value?
You can either get the column name from grid.columns or from the corresponding th element. use the grid.cellIndex method to select the correct column:
$("#change").click(function() {
var selected = grid.select();
var header = grid.thead;
for (var i = 0, max = selected.length ; i < max ; i++) {
var index = grid.cellIndex(selected[i]);
var th = $(header).find("th").eq(index);
// could also use grid.columns[index].field
// (not sure if this gets reordered on column reorder though)
var field = $(th).data("field");
var item = grid.dataItem($(selected[i]).closest("tr"));
item[field] = "new value";
}
grid.refresh();
});
Regarding your comment:
dataItem.set() causes the <tr> elements to get removed from their context (because grid.refresh() will create new rows for the view), and because of that, grid.dataItem() won't give you the expected result with the old DOM elements you still have a reference to.
If you want to use dataItem.set(), you can try something like this as a work-around:
$("#change").click(function () {
var selected = grid.select(),
header = grid.thead,
dataItem,
index,
field,
value,
th;
for (var i = 0, max = selected.length; i < max; i++) {
dataItem = grid.dataItem($(selected[i]).closest("tr"));
index = $(selected[i]).index();
th = $(header).find("th").eq(index);
field = $(th).data("field");
value = "new value " + i;
setTimeout(function (dataItem, field, value) {
return function () {
dataItem.set(field, value);
}
}(dataItem, field, value), 5);
}
});
(demo)
You have to retrieve the ColumnList of your grid first and then loop through it
$(".change").click(function () {
var grid = $("#Grid").data("kendoGrid");
var columnsListOfView = grid.columns;
var cellsToChange = grid.select();
for (var j = 0; i < cellsToChange.length; i++) {
var item = grid.dataItem($(cellsToChange[i]).closest("tr"));
for (var j = 0; j < columnsListOfView.length; j++) {
//Here columnsListOfView[j].field will give you the different names that you need
var field=columnsListOfView[j].field;
item[field] = "new value";
}
}
grid.refresh();
});
I am using the following method to read header names in a table and put in excel. Could anyone let me know how to modify this to support multiple tables with header info and data.
i.e. how to modify to pass table id. "headers" is the id for "th" tag in code.
function write_headers_to_excel()
{
str="";
var myTableHead = document.getElementById('headers');
var rowCount = myTableHead.rows.length;
var colCount = myTableHead.getElementsByTagName("tr")[0].getElementsByTagName("th").length;
var ExcelApp = new ActiveXObject("Excel.Application");
var ExcelSheet = new ActiveXObject("Excel.Sheet");
ExcelSheet.Application.Visible = true;
for(var i=0; i<rowCount; i++)
{
for(var j=0; j<colCount; j++)
{
str= myTableHead.getElementsByTagName("tr")[i].getElementsByTagName("th") [j].innerHTML;
ExcelSheet.ActiveSheet.Cells(i+1,j+1).Value = str;
}
}
Your question is a bit vague, so I'm guessing at what you want. Assuming your current function works as is, you can just take out the hard-coding of the table's ID and pass it in as a parameter:
function write_headers_to_excel(tableID) {
var myTableHead = document.getElementById(tableID);
// rest of your function as is
}
Then call it once for each table, though that will create a new ExcelSheet for each table.
If the idea is for all of the tables to be added to the same ExcelSheet you can pass an array of table IDs to the function something like the following. I've kept the basic structure of your function but moved the variable declarations out of the loops (since that what JavaScript does behind the scenes anyway), deleted your ExcellApp variable since it wasn't used, and moved the getElementsByTagName call out of the inner loop.
write_headers_to_excel(["headers1","headers3","headers7","etc"]);
function write_headers_to_excel(tableIDs) {
var myTableHead,
rowCount,
cols,
t,
i,
j,
rowOffset = 1,
ExcelSheet = new ActiveXObject("Excel.Sheet");
ExcelSheet.Application.Visible = true;
for (t=0; t < tableIDs.length; t++) {
myTableHead = document.getElementById(tableIDs[t]);
rowCount = myTableHead.rows.length;
for(i=0; i<rowCount; i++) {
cols = myTableHead.rows[i].getElementsByTagName("th");
for(j=0; j < cols.length; j++) {
ExcelSheet.ActiveSheet.Cells(i+rowOffset,j+1).Value = cols[j].innerHTML;
}
}
rowOffset += rowCount;
}
}
(No, I haven't tested it.)
You can get all tr elements by tag name
var rows = document.getElementsByTagName('tr');// get all rows of all tables
var table=0, TableRow=0;
for (i = 0; i < rows.length; i++) {
row = rows[i];
if (row.parentNode.tagName != 'THEAD' && row.parentNode.tagName != 'thead') {
table=table+1;
// do something here for headers
} else if (row.parentNode.tagName != 'TBODY' && row.parentNode.tagName != 'tbody')
{
TableRow=TableRow+1;
//do something here for rows
}
}