How to bind list of objects to handsontable? - javascript

I have a json object,which contains following data.
var myData = [{
"sNo": "1.0",
"boqName": "Installation of pole 11 KV",
"unit": "Nos",
"opportunityBoqOverHeadMasterList": [{
"opportunityBoqOverHeadMasterId": 14,
"value": 41.3
},
{
"opportunityBoqOverHeadMasterId": 16,
"value": 41.3
},
{
"opportunityBoqOverHeadMasterId": 24,
"value": 100
}
]
},
{
"sNo": "2.0",
"boqName": "Installation of pole 33 KV",
"unit": "Nos",
"opportunityBoqOverHeadMasterList": [{
"opportunityBoqOverHeadMasterId": 15,
"value": 52.92
},
{
"opportunityBoqOverHeadMasterId": 17,
"value": 52.92
},
{
"opportunityBoqOverHeadMasterId": 25,
"value": 0
}
]
},
];
}
i need to display the value of opportunityBoqOverHeadMasterList next to the unit cell.
Please help me to display data in handsontable. Please refer jsfiddle for working example https://jsfiddle.net/Umanath16/aty5wfg7/22/

You could try processing the data. Notice below that I changed your columns array, create a new myNewData variable and create nested loops to format the data.
var columns = [
{
"data": "sNo"
},
{
"data": "boqName"
},
{
"data": "unit"
},
,
{
"data": "Percentage1"
},
{
"data": "Percentage2"
},
{
"data": "Percentage3"
}
];
Change the data obj...
var myNewData = [];
for (var i = 0; i < myData.length; i++) {
myNewData.push({
sNo: myData[i].sNo,
boqName: myData[i].boqName,
unit: myData[i].unit
});
for (var j = 0; j < myData[i].opportunityBoqOverHeadMasterList.length; j++) {
myNewData[i]["Percentage"+(j+1)] = myData[i].opportunityBoqOverHeadMasterList[j].value;
}
}
hot = new Handsontable(example, {
data: myNewData,
rowHeaders: true,
columns: columns,
rowHeaderWidth: 100,
colWidths: 120,
colHeaders: colHeaders
});
}
This is just one possible solution. Please think about possible improvements. What if the data does not have the same fields? It would need to be dynamic regardless of the field names. Also how would you improve the loops, etc.

Related

How to use find objects in multiple levels of nested arrays

What I want is to find an object in a nested array, and to get it by a pre-known ScheduleId number, and where the Duration property is defined.
We need to find this element which is contained inside of array of "Columns", and "Columns" are contained within "Table" elements.
After finding this object, I want to update ScheduleId = 0 and Duration = 0.
Sample data:
var data = {
"Headers": [
"A",
"B",
"C",
"D"
],
"Table": [
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 12,
},
],
},
{
"Columns": [
{
"Duration": 22,
"ScheduleId": 44,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 1648,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 22,
},
],
},
]
};
Pseudo code:
var requestedScheduleId = 22;
var requestedObj = data.Table.find(x => requestedScheduleId.Equals(x.Columns.ScheduleId) )
requestedObj.ScheduleId = 0;
requestedScheduleId.Duration = 0;
Unsuccessful attempt:
var test = data.Table.map(({ Columns }) => {return Columns = Columns.filter(({ ScheduleId }) => ScheduleId == 22 )});
console.log(test);
I would not use .map or .filter for this. It's a plain and simple nested loop: For each table, for each column, if condition is met, do something.
Either with for loops:
for (table of data.Table) {
for (column of table.Columns) {
if (column.ScheduleId === 22) {
column.ScheduleId = 0;
column.Duration = 0;
}
}
}
or with Array#forEach:
data.Table.forEach(table => {
table.Columns.forEach(column => {
if (column.ScheduleId === 22) {
column.ScheduleId = 0;
column.Duration = 0;
}
});
});
var data = {
"Headers": [
"A",
"B",
"C",
"D"
],
"Table": [
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 12,
},
],
},
{
"Columns": [
{
"Duration": 22,
"ScheduleId": 44,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 1648,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 22,
},
],
},
]
};
var requestedScheduleId = 22;
data.Table.forEach(table => {
table.Columns.forEach(column => {
if (column.ScheduleId === requestedScheduleId) {
column.ScheduleId = 0;
column.Duration = 0;
}
});
});
console.log(data);

Replacing values in array which are received as argument of a method

In this array children array can have more childrens. I have a method in which I will get "lowValue" and "highValue". "Id" will be unique. when my method get called I need to use this unique id and replace old values of "lowValue" and "highValue" with the new ones. How can I do that?
// put your code here
<script>
myData = [{
"data": {
"name": "Applications",
"size": "200mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 1,
"name": "editor.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
}
},
{
"data": {
"id": 2,
"name": "settings.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
"mappedPersonaCount": 0,
}
}
]
},
{
"data": {
"name": "Cloud",
"size": "20mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 5,
"name": "backup-1.zip",
"highValue": 20,
"ratingID": 0,
"lowValue": 10
}
}]
}
]
</script>
Simple
const data = your_original_data
function replacer(lowValue, highValue, id){
for(let i = 0; i < data.length; i++){
for(let j = 0; j < data[i].children.length; j++){
if(data[i].children[j].data.id === id){
data[i].children[j].data.lowValue = lowValue
data[i].children[j].data.highValue = highValue
return
}
}
}
}
const myData = [{
"data": {
"name": "Applications",
"size": "200mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 1,
"name": "editor.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
}
},
{
"data": {
"id": 2,
"name": "settings.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
"mappedPersonaCount": 0,
}
}
]
},
{
"data": {
"name": "Cloud",
"size": "20mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 5,
"name": "backup-1.zip",
"highValue": 20,
"ratingID": 0,
"lowValue": 10
}
}]
}
]
const indexMap = new Map()
const parseDataToMap = (data = []) => {
data.forEach(e => {
if (e.children) {
e.children.forEach(e => {
indexMap.set(e.data.id, e.data)
})
}
})
}
parseDataToMap(myData)
console.log(myData[0].children[0].data)
const o = indexMap.get(1)
o.highValue = 25
o.lowValue = 11
console.log(myData[0].children[0].data)
Given the below-mentioned assumptions:
All children where id matches the supplied value will have the lowValue and highValue replaced.
The supplied id will always be present in the myData array in one or more children.
the following is one possible solution to achieve the desired result:
const replaceValues = (id = 5, lv = 5, hv = 50, arr = myData) => (
arr.reduce((f, i) => [...f, {
...i,
children: i.children.map(
child => ({
...child,
data: {
...child.data,
...(
child.data.id === id ? {
lowValue: lv,
highValue: hv
} : {}
)
}
})
)
}], [])
);
Explanation / Approach
The outer .reduce helps to iterate through the myData array
Each element in this array is placed as-is (using the ... spread operator)
Next, the children prop of each myData element is specified
Within this, i.children array is iterated using map to access each element
Each element here (again) is placed as-is using the ... spread-operator
Next, data is specified
Values for the data object are also spread (as before)
Then, if the data.id matches the parameter id then, lowValue and highValue are updated (using parameters lv and hv, respectively)
The ...( some_condition ? {k: v} : {} ) is one way to update an object's specific prop/s only when some_condition is true
Please use comments below to ask for further clarification/s.
Code Snippet
const myData = [{
"data": {
"name": "Applications",
"size": "200mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 1,
"name": "editor.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
}
},
{
"data": {
"id": 2,
"name": "settings.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
"mappedPersonaCount": 0,
}
}
]
},
{
"data": {
"name": "Cloud",
"size": "20mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 5,
"name": "backup-1.zip",
"highValue": 20,
"ratingID": 0,
"lowValue": 10
}
}]
}
];
const replaceValues = (id = 5, lv = 5, hv = 50, arr = myData) => arr.reduce((f, i) => [...f, {
...i,
children: i.children.map(
child => ({
...child,
data: {
...child.data,
...(
child.data.id === id ? {
lowValue: lv,
highValue: hv
} : {}
)
}
})
)
}], []);
console.log('replace id: 5, low: 5, high: 50', replaceValues());
console.log('replace id: 1, low: 11, high: 21', replaceValues(1, 11, 21));

Chart.js plotting two json datasets on a line chart

I'm trying to work out how to plot labels to the correct places using Chart.js
var json = {
"competition one": [
{
"date": "2015-05-20",
"position": 37
},
{
"date": "2015-05-21",
"position": 22
}
],
"competition two": [
{
"date": "2015-05-20",
"position": 29
},
{
"date": "2015-05-21",
"position": 19
}
]
}
How can I plot the labels to the correct places? With the dates going to the correct labels so it isn't repeated?
Specifically, I'm struggling to get "competition one" into the label of the dataset array (label: "competition one")
I need it to resemble the following data structure that is required by Chart.js?
var data = {
labels: ["2015-05-20", "2015-05-21"],
datasets: [
{
label: "competition one",
data: [37, 22]
},
{
label: "Competition two",
data: [29, 19]
}
]
};
As mentioned in comments you can get the properties names like thus:
var json = {
"competition one": [
{
"date": "2015-05-20",
"position": 37
},
{
"date": "2015-05-21",
"position": 22
}
],
"competition two": [
{
"date": "2015-05-20",
"position": 29
},
{
"date": "2015-05-21",
"position": 19
}
]
}
var keys = Object.keys(json);
for (var i = 0; i < keys.length; i++)
{
var key = keys[i];
//"competition one", "competition two", etc
console.log(key);
}
Fiddle
you then just need to manipulate these values into your desired object structure.
var keys = Object.keys(json);
//set up our object containing an array called datasets
var data = {datasets:[]};
for (var i = 0; i < keys.length; i++)
{
var key = keys[i];
//push the key into the dataset array as an object {}
data.datasets.push({label:key, data:...});
}

Pass Json to javascript in specific format to render the chart

I am working on chart library,
I have json format, which will be coming from server, year and month format
{
"id": 1,
"name": "name1",
"present": "18",
"target": "18",
"status": "yellow"
}
Now I need to pass present and target values in a array format.
the data must be passed or parsed like below.
How to do I do this in javascript and jquery?
I tried all the available solutions, since I am new to the javascript world!
Expected result
var legendsText = [["present name1","target name1"]],
jsonFormat = [[18, 18],[15,18],[36, 18]];
FIDDLE
This is the fiddle our friend Eli Gassert has created, it is the closeset one
http://http://jsfiddle.net/Yq3DW/126/
but it is loading only present values of all 3 months
i want present and target values of each name.
For example
name1 link clicked, chart should load name1 present and target for all 3 months.
name2 link clicked, chart should load name2 present and target for all 3 months.
name3 link clicked, chart should load name3 present and target for all 3 months.
My JSON format which is coming dynamically from server
data={
"perspective": "something",
"year": "2014",
"measures": [
{
"id": 1,
"name": "some name",
"target": "200",
"responsiblePerson": null
},
{
"id": 2,
"name": "some name",
"target": "100",
"responsiblePerson": null
}
],
"values": {
"jan": [
{
"id": 1,
"name": "name1",
"present": "18",
"target": "18",
"status": "yellow"
},
{
"id": 2,
"name": "name2",
"present": "21",
"target": "22",
"status": "red"
},
{
"id": 3,
"name": "name3",
"present": "50",
"target": "50",
"status": "yellow"
}
],
"feb": [
{
"id": 1,
"name": "name1",
"present": "18",
"target": "18",
"status": "yellow"
},
{
"id": 2,
"name": "name2",
"present": "21",
"target": "22",
"status": "red"
},
{
"id": 3,
"name": "name3",
"present": "50",
"target": "50",
"status": "yellow"
}
],
"mar": [
{
"id": 1,
"name": "name1",
"present": "18",
"target": "18",
"status": "yellow"
},
{
"id": 2,
"name": "name2",
"present": "22",
"target": "22",
"status": "yellow"
},
{
"id": 3,
"name": "name3",
"present": "52",
"target": "50",
"status": "yellow"
}
]
}
}
HTML
<div id="chart"></div>
JS
var legendsText = [];
for(var i = 0; i != data.measures.length; ++i)
legendsText.push(data.measures[i].name);
legendsText = [legendsText];
var rows = [];
for(var i in data.values)
{
var row = []
for(var j = 0; j != data.values[i].length; ++j)
{
row.push(data.values[i][j].present);
}
rows.push(row);
}
rows = legendsText.concat(rows.sort(function (a, b) { }));
console.log(rows);
var chart = c3.generate({
bindto: '#chart',
data: {
rows: rows,
type: 'bar',
}
});
Any help is appreciated.
Here's an updated fiddle that transforms your data to the results: http://jsfiddle.net/Yq3DW/119/
Key aspects:
Your Legend Text can be gotten dynamically from your measures data. The format for the legendsText is an "array of arrays" so that's why I wrap it in [...] at the end of the loop.
var legendsText = [];
for(var i = 0; i != data.measures.length; ++i)
legendsText.push(data.measures[i].name);
legendsText = [legendsText];
Your rows can be gotten from your "values" data. But because it's not an array, like measures you need to use a for each loop instead of for loop:
var rows = [];
for(var i in data.values)
{
var row = []
for(var j = 0; j != data.values[i].length; ++j)
{
row.push(data.values[i][j].present);
}
rows.push(row);
}
EDIT: Updated question. To show just one label's worth of data but show both values for that data, and give nice labels: http://jsfiddle.net/Yq3DW/130/
The key here:
Switch to columns instead of rows, allowing one "row" of data to stand-in for the label indexer
Only add the data if the name in the value data matches the name you're searching for (had to update your data JSON so the names matched)
Had to use a 'tick' formatter to format the labels from 1-3 to jan, feb, mar. You can further customize it by using upper case/proper case conversions. That is outside the scope of this question and I'm not including it here. If you need further formatting, search for an answer first and if you can't find it, start a new Q.
Display a dynamic list of links to click that calls your loadData function to change the data in the chart between the various measure names
HTML:
<ul id="links"></ul>
<div id="chart"></div>
JS:
var $links = $('#links');
$links.html('');
for(var i = 0; i != data.measures.length; ++i)
{
(function()
{
var name = data.measures[i].name;
$('<li></li>')
.text(data.measures[i].name)
.click(function() { loadData(name); })
.appendTo($links);
})();
// legendsText.push(data.measures[i].name);
}
function loadData(name)
{
//var legendsText = [ ["present", "target"] ];
var columns = [ ["labels"], [ "present" ], [ "target" ]];
var labels = [];
for(var i in data.values)
{
var row = []
for(var j = 0; j != data.values[i].length; ++j)
{
if(data.values[i][j].name == name)
{
labels.push(i);
columns[0].push(labels.length);
columns[1].push(data.values[i][j].present);
columns[2].push(data.values[i][j].target);
}
}
//rows.push(row);
}
console.log(columns);
//rows = legendsText.concat(rows.sort(function (a, b) { }));
var chart = c3.generate({
bindto: '#chart',
data: {
x: 'labels',
columns: columns,
type: 'bar',
},
axis: {
x: {
tick: {
format: function(index) { return labels[index-1]; }
}
}
}
});
}

How can I use nested Json to populate Kendo UI grid?

How can I populate Kendo UI grid with nested JSON.
I mean my JSON is like
var myJson:
[{"oneType":[
{"id":1,"name":"John Doe"},
{"id":2,"name":"Don Joeh"}
]},
{"othertype":"working"},
{"otherstuff":"xyz"}]
}];
and I want Kendo UI Grid with columns as Id, Name, OtherType and OtherStuff.
Thanks in advance.!
For complex JSON structures, you might use schema.parse
var grid = $("#grid").kendoGrid({
dataSource : {
data : [
{
"oneType": [
{"id": 1, "name": "John Doe"},
{"id": 2, "name": "Don Joeh"}
]
},
{"othertype": "working"},
{"otherstuff": "xyz"}
],
pageSize: 10,
schema : {
parse : function(d) {
for (var i = 0; i < d.length; i++) {
if (d[i].oneType) {
return d[i].oneType;
}
}
return [];
}
}
}
}).data("kendoGrid");
If you slightly change your JSON to:
{
"oneType" : [
{"id": 1, "name": "John Doe"},
{"id": 2, "name": "Don Joeh"}
],
"othertype" : "working",
"otherstuff": "xyz"
}
then you can use:
var grid = $("#grid").kendoGrid({
dataSource: {
data : {
"oneType" : [
{"id": 1, "name": "John Doe"},
{"id": 2, "name": "Don Joeh"}
],
"othertype" : "working",
"otherstuff": "xyz"
},
pageSize: 10,
schema : {
data: "oneType"
}
}
}).data("kendoGrid");
I just wanted to submit another answer based on OnaBai's.
http://jsfiddle.net/L6LwW/17/
The HTML:
<script id="message-template" type="text/x-kendo-template">
#for (var i = 0; i
< ddl.length; i++) {# <li><span>#=ddl[i].value#</li>
#}#
</script>
<div id="grid"></div>
The JS:
var grid = $("#grid").kendoGrid({
dataSource: {
data: [
[{
"id": 1,
"name": "John Doe",
"ddl": [{
"key": 1,
"value": "hello"
}, {
"key": 1,
"value": "hello"
}]
}, {
"id": 2,
"name": "Don Joeh",
"ddl": [{
"key": 1,
"value": "hello"
}, {
"key": 1,
"value": "hello"
}]
}]
],
pageSize: 10,
schema: {
parse: function(d) {
for (var i = 0; i < d.length; i++) {
if (d[i]) {
return d[i];
}
}
return [];
}
}
},
columns: [{
field: "id",
title: "ID"
}, {
field: "name",
title: "Name"
}, {
field: "ddl",
title: "DDL",
width: "180px",
template: kendo.template($("#message-template").html())
} //template: "#=ddl.value#" }
]
}).data("kendoGrid");

Categories