how to create dynamic table in react - javascript

I have started with reacr-redux. in that I have got some json data to populate as table structure. for that I have data like this
[
{
"year": 2016,
"mix": [{
"name": "A",
"volume": 0.55,
},
{
"name": "B",
"volume": 0.2,
},
{
"name": "C",
"volume": 0.0,
},
{
"name": "D",
"volume": 0.0,
}],
},
{
"year": 2017,
"mix": [{
"name": "A",
"volume": 0.55,
},
{
"name": "B",
"volume": 0.2,
},
{
"name": "C",
"volume": 0.0,
},
{
"name": "D",
"volume": 0.0,
}],
},
{
"year": 2018,
"mix": [{
"name": "A",
"volume": 0.55,
},
{
"name": "B",
"volume": 0.2,
},
{
"name": "C",
"volume": 0.0,
},
{
"name": "D",
"volume": 0.0,
}],
},
{
"year": 2015,
"mix" :[{
"name": "A",
"volume": 0.55,
},
{
"name": "B",
"volume": 0.2,
},
{
"name": "C",
"volume": 0.0,
},
{
"name": "D",
"volume": 0.0,
}]
},
{
"year": 2019,
"mix": [
{
"name": "A",
"volume": 0.55,
},
{
"name": "B",
"volume": 0.2,
},
{
"name": "C",
"volume": 0.0,
},
{
"name": "D",
"volume": 0.0,
}
],
}
]
and I want my table structure like this. basically it extracts year and of that year all the mix. so final table structure should look like this
2015 2016 2017 2018
A 0.55 0.55 0.55 0.55
B 0.2 0.2 0.2 0.2
C 0 0 0 0
D 0 0 0 0
for that I have written code like this
<table className="table table-bordered">
<thead>
<tr>
<th></th>
{this.props.allYear.map((data) =>(
<th>{data.year.toString().substr(0,4)}</th>
))}
</tr>
</thead>
<tbody>
{this.props.allYear.map((data) =>(
data.mix.map((Data1) => (
<tr>
{Data1.name}
</tr>
))
))}
<td></td>
{this.props.allYear.map((data) =>(
<td>
{data.mix.map((Data1) => {
return(
<tr>
{Data1.volume}
</tr>
)
})}
</td>
))}
</tbody>
</table>
but my all the data went 1 tr down because of the tr I have written so table looks like this
2015 2016 2017 2018
A
B
C
D
0.55 0.55 0.55 0.55
0.2 0.2 0.2 0.2
0 0 0 0
0 0 0 0.
Please let me know how to fix this

I figured out a way to keep your original data structure:
var sorted = this.props.allYear.sort((a, b) => a.year - b.year);
// create rows object, letters as keys, each value an array of volumes
var rows = {};
sorted.forEach(function (year) {
year.mix.forEach((data) => {
if (!rows[data.name]) rows[data.name] = [];
rows[data.name].push(data.volume);
});
});
return (
<table className="table table-bordered">
<thead>
<tr>
<th></th>
{sorted.map((data, i) => <th key={i}>{data.year}</th>)}
</tr>
</thead>
<tbody>
{Object.keys(rows).map((letter) =>
<tr>
<td>{letter}</td>
{rows[letter].map((data) => <td>{data}</td>)}
</tr>
)}
</tbody>
</table>
);
However this assumes that there are no "holes" in the data.

Your table structure is all kinds of wrong. What you are doing is creating 4 <tr> and then a bunch of random <td>. Basic table structure is table -> tbody -> tr -> td. You need to create two map functions. Like Chris G mentioned in a comment, your data structure is not setup to make this easy. It actually makes what you want to do a lot harder. I would suggest changing your data structure to something more like this:
[
A: [{
year: 2015,
volume: 0.0
},{
year: 2016,
volume: 0.0
},{
year: 2017,
volume: 0.0
}],
B: [{
year: 2015,
volume: 0.0
},{
year: 2016,
volume: 0.0
},{
year: 2017,
volume: 0.0
}],
C: ...
]

Related

how to transform a key property from an object type into an array type

I have a array of two objects.
I would like to transforming each object's key, allocation, from a object type into array type
From allocation: {} into allocation:[]
They content of the array of allocation would be the children of customAllocations
May I ask how to achieve that?
Original array
[
{
"allocation": {
"name": "custom",
"customAllocations": [
{
"name": "Developed",
"weight": 0.75
},
{
"name": "Diversified",
"weight": 0.1
},
{
"name": "Global",
"weight": 0.15
}
]
}
},
{
"allocation": {
"name": "custom",
"customAllocations": [
{
"name": "Developed",
"weight": 0.35
},
{
"name": "Conservative",
"weight": 0.1
},
{
"name": "Global",
"weight": 0.55
}
]
}
}
]
Expected array
[
{
"allocation": [
{
"name": "Developed",
"weight": 0.75
},
{
"name": "Diversified",
"weight": 0.1
},
{
"name": "Global",
"weight": 0.15
}
]
},
{
"allocation": [
{
"name": "Developed",
"weight": 0.35
},
{
"name": "Conservative",
"weight": 0.1
},
{
"name": "Global",
"weight": 0.55
}
]
}
]
Edit:
Please be aware of modifying the actual object. It may have some problem. So may I know how to have a better approach...That's why I found this problem may have more than it to be.
You can map the properties like so. However this will mutate the original obj. You can use for example use _.deepClone(data) from loadash to make a copy of the inital obj.
const data = [{
"allocation": {
"name": "custom",
"customAllocations": [{
"name": "Developed",
"weight": 0.75
},
{
"name": "Diversified",
"weight": 0.1
},
{
"name": "Global",
"weight": 0.15
}
]
}
},
{
"allocation": {
"name": "custom",
"customAllocations": [{
"name": "Developed",
"weight": 0.35
},
{
"name": "Conservative",
"weight": 0.1
},
{
"name": "Global",
"weight": 0.55
}
]
}
}
];
// this will mutate the actualy obj
console.log(data.map(alloc => {
alloc.allocation = alloc.allocation.customAllocations
return alloc
}))
// this will also display the changed result
console.log(data)
I guess it meets your needs. Just a little playing on the object and returning your expected data form.
const data = [
{
"allocation": {
"name": "custom",
"customAllocations": [
{
"name": "Developed",
"weight": 0.75
},
{
"name": "Diversified",
"weight": 0.1
},
{
"name": "Global",
"weight": 0.15
}
]
}
},
{
"allocation": {
"name": "custom",
"customAllocations": [
{
"name": "Developed",
"weight": 0.35
},
{
"name": "Conservative",
"weight": 0.1
},
{
"name": "Global",
"weight": 0.55
}
]
}
}
]
const newData = []
data.forEach(elem => {
newData.push({'allocation' : elem.allocation.customAllocations})
})
console.log(newData)

Append data to table from json when headers are a mix of the keys and values

I have an array of objects, I want to add that data to an HTML table but I am having trouble appending it to the table as my table structure is slightly unique.
My headers are a mix of the keys and values and I want to be able to get their corresponding value to populate my cells.
My code:
let data = [{Date:"2021-03-22",device:"Phone",vendor:"Apple",value:11},{Date:"2021-03-22",device:"Phone",vendor:"Google",value:10},{Date:"2021-03-22",device:"Tablet",vendor:"Apple",value:45},{Date:"2021-03-22",device:"Tablet",vendor:"Google",value:57},{Date:"2021-03-22",device:"iOT",vendor:"Apple",value:33},{Date:"2021-03-22",device:"iOT",vendor:"Google",value:11},{Date:"2021-03-22",device:"Smart Watch",vendor:"Apple",value:17},{Date:"2021-03-22",device:"Smart Watch",vendor:"Google",value:25},{Date:"2021-03-29",device:"Phone",vendor:"Apple",value:9},{Date:"2021-03-29",device:"Phone",vendor:"Google",value:20},{Date:"2021-03-29",device:"Tablet",vendor:"Apple",value:23},{Date:"2021-03-29",device:"Tablet",vendor:"Google",value:15},{Date:"2021-03-29",device:"iOT",vendor:"Apple",value:11},{Date:"2021-03-29",device:"iOT",vendor:"Google",value:77},{Date:"2021-03-29",device:"Smart Watch",vendor:"Apple",value:38},{Date:"2021-03-29",device:"Smart Watch",vendor:"Google",value:80}];
let ths = ['device', 'vendor', '2021-03-22', '2021-03-29'];
ths.forEach(d => $(`#ths`).append(`<th id='${d}'>${d}</th>`));
data.forEach(d => {
$(`#table_body`).append(`<tr class='my_rows'></tr>`);
['device', 'vendor'].forEach(x => $(`#table_body > tr:last`).append(`<td>${d[x]}</td>`));
['value'].forEach(y => {
$(`.my_rows:last`).append(`<td>${d[y]}</td>`);
});
});
table,
td,
th {
border: 1px solid black;
}
#mytable {
width: 100%;
border-collapse: collapse;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id='mytable'>
<thead>
<tr id='ths'></tr>
</thead>
<tbody id='table_body'></tbody>
</table>
As you can see, my table is populating vertically and adding any data to 2021-03-29 and instead of adding all the data to the first date column.
How do I make my data look like:
device
vendor
2021-03-22
2021-03-29
Phone
Apple
11
10
Phone
Google
45
57
Tablet
Apple
33
11
Tablet
Google
17
25
iOt
Apple
9
20
iOt
Google
23
15
Smart Watch
Apple
11
77
Smart Watch
Google
38
80
well, basically what I would do is transform the data that you have to a something simplier, so we can move from:
[
{
"Date": "2021-03-22",
"device": "Phone",
"vendor": "Apple",
"value": 11
},
{
"Date": "2021-03-29",
"device": "Phone",
"vendor": "Apple",
"value": 9
},
....
]
to something like this:
[
{
"2021-03-22": "11",
"2021-03-29": "9",
"device": "Phone",
"vendor": "Apple",
"value": 11
}
....
]
this can be achieved using reduce and convert it into and object and the with Object.values() we can get the array transformed.
here you have the working solution using the same renderer of the table.
notice that I merged both items into one, using the date as a key and the value will be the value of that date.
let data = [{
"Date": "2021-03-22",
"device": "Phone",
"vendor": "Apple",
"value": 11
},
{
"Date": "2021-03-22",
"device": "Phone",
"vendor": "Google",
"value": 10
},
{
"Date": "2021-03-22",
"device": "Tablet",
"vendor": "Apple",
"value": 45
},
{
"Date": "2021-03-22",
"device": "Tablet",
"vendor": "Google",
"value": 57
},
{
"Date": "2021-03-22",
"device": "iOT",
"vendor": "Apple",
"value": 33
},
{
"Date": "2021-03-22",
"device": "iOT",
"vendor": "Google",
"value": 11
},
{
"Date": "2021-03-22",
"device": "Smart Watch",
"vendor": "Apple",
"value": 17
},
{
"Date": "2021-03-22",
"device": "Smart Watch",
"vendor": "Google",
"value": 25
},
{
"Date": "2021-03-29",
"device": "Phone",
"vendor": "Apple",
"value": 9
},
{
"Date": "2021-03-29",
"device": "Phone",
"vendor": "Google",
"value": 20
},
{
"Date": "2021-03-29",
"device": "Tablet",
"vendor": "Apple",
"value": 23
},
{
"Date": "2021-03-29",
"device": "Tablet",
"vendor": "Google",
"value": 15
},
{
"Date": "2021-03-29",
"device": "iOT",
"vendor": "Apple",
"value": 11
},
{
"Date": "2021-03-29",
"device": "iOT",
"vendor": "Google",
"value": 77
},
{
"Date": "2021-03-29",
"device": "Smart Watch",
"vendor": "Apple",
"value": 38
},
{
"Date": "2021-03-29",
"device": "Smart Watch",
"vendor": "Google",
"value": 80
}
];
let ths = ['device', 'vendor', '2021-03-22', '2021-03-29'];
ths.forEach(d => $(`#ths`).append(`<th id='${d}'>${d}</th>`));
const reducer = (accum, cv) => {
const key = cv.vendor + cv.device;
// if there isnt an entry we create a new one.
if (!accum[key]) {
accum[key] = {
device: cv.device,
vendor: cv.vendor,
[cv.Date]: cv.value
};
} else {
// we have an entry we just add the value for the date.
accum[key][cv.Date] = cv.value
}
return accum;
}
const obj = data.reduce(reducer, {});
const newForm = Object.values(obj);
newForm.forEach(d => {
$(`#table_body`).append(`<tr class='my_rows'></tr>`);
['device', 'vendor'].forEach(x => $(`#table_body > tr:last`).append(`<td>${d[x]}</td>`));
['2021-03-22', '2021-03-29'].forEach(y => {
$(`.my_rows:last`).append(`<td>${d[y]}</td>`);
});
})
table,
td,
th {
border: 1px solid black;
}
#mytable {
width: 100%;
border-collapse: collapse;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id='mytable'>
<thead>
<tr id='ths'></tr>
</thead>
<tbody id='table_body'></tbody>
</table>

Javascript: rearrage json output in a specific array format

Another dumb moment for me. Spent hours through for loops, maps, reduce, dictionaries but just can't seem to figure it out. I have a json data that look like this
{
"timeline": [
{
"series": "series1",
"data": [
{
"date": "20200713T120000Z",
"value": 0
},
{
"date": "20200714T120000Z",
"value": 8
},
{
"date": "20200715T120000Z",
"value": 0
}
]
},
{
"series": "series2",
"data": [
{
"date": "20200713T120000Z",
"value": 0
},
{
"date": "20200714T120000Z",
"value": 0
}
]
},
{
"series": "series3",
"data": [
{
"date": "20200713T120000Z",
"value": 1
},
{
"date": "20200714T120000Z",
"value": 0
}
]
},
{
"series": "series4",
"data": [
{
"date": "20200713T120000Z",
"value": 2
},
{
"date": "20200714T120000Z",
"value": 4
}
]
}
]
}
I need it in this format
[
{
date: "20200713T120000Z",
series1: 0,
series2: 0,
series3: 1,
series4: 2
},
{
date: "20200714T120000Z",
series1: 8,
series2: 0,
series3: 0,
series4: 4
}
]
Need to do this in JavaScript. Any help/ pointers will be much appreciated.
You could take an object forgrouping and an array for storing all keys for getting an ordered result with all same keys.
This approach filters all zero values from the result set.
const
data = { timeline: [{ series: "series1", data: [{ date: "20200713T120000Z", value: 0 }, { date: "20200714T120000Z", value: 8 }, { date: "20200715T120000Z", value: 0 }] }, { series: "series2", data: [{ date: "20200713T120000Z", value: 0 }, { date: "20200714T120000Z", value: 0 }] }, { series: "series3", data: [{ date: "20200713T120000Z", value: 1 }, { date: "20200714T120000Z", value: 0 }] }, { series: "series4", data: [{ date: "20200713T120000Z", value: 2 }, { date: "20200714T120000Z", value: 4 }] }] },
keys = ['date'],
result = Object
.values(data.timeline.reduce((r, { series, data }) => {
keys.push(series);
data.forEach(({ date, value }) => {
if (!value) return;
if (!r[date]) r[date] = { date };
r[date][series] = value;
});
return r;
}, {}))
.map(o => ({ ...Object.fromEntries(keys.map(k => [k, 0])), ...o }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is temporary solution for this, you can try this. I'm using lodash, so please install it.
var _ = require('lodash')
const data = {"timeline": [ { "series": "series1", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 8 },{ "date": "20200715T120000Z", "value": 0 }] },{ "series": "series2", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series3", "data": [ { "date": "20200713T120000Z", "value": 1 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series4", "data": [ { "date": "20200713T120000Z", "value": 2 },{ "date": "20200714T120000Z", "value": 4 }] }] }
const t = _.flattenDeep(data.timeline.map(i => i.data.map(d => ({...d, series: i.series}))))
const result = t.reduce((acc, i) => {
const index = acc.findIndex(a => a.date === i.date)
if(index !== -1){
acc[index] = {
...acc[index],
[i.series]: i.value
}
}else {
acc.push({
date: i.date,
[i.series]: i.value
})
}
return acc
}, [])
console.log(result)
Use multiple forEach loops and build an object to track. Then get Object.values
const convert = (arr) => {
const res = {};
arr.forEach(({ series, data }) =>
data.forEach(
({ date, value }) =>
(res[date] = { ...(res[date] ?? { date }), [series]: value })
)
);
return Object.values(res);
};
obj = {"timeline": [ { "series": "series1", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 8 },{ "date": "20200715T120000Z", "value": 0 }] },{ "series": "series2", "data": [ { "date": "20200713T120000Z", "value": 0 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series3", "data": [ { "date": "20200713T120000Z", "value": 1 },{ "date": "20200714T120000Z", "value": 0 }] },{ "series": "series4", "data": [ { "date": "20200713T120000Z", "value": 2 },{ "date": "20200714T120000Z", "value": 4 }] }] }
const res = convert(obj.timeline);
console.log(res)

Convert sequence of Array in own sequence

Convert Array of List into my Own Order
Current Output:
[
{ "key": "DG Power Output", "value": "6.00", "unit": "kWh", },
{ "key": "DG Run Time", "value": "5999999952", "unit": "minutes", },
{ "key": "Fuel Level (Before)", "value": "8.00", "unit": "liters", }
]
Convert this into
[
{ "key": "Fuel Level (Before)", "value": "8.00", "unit": "liters", },
{ "key": "DG Run Time", "value": "5999999952", "unit": "minutes", },
{ "key": "DG Power Output", "value": "6.00", "unit": "kWh", }
]
You could take an object for getting th right order and sort by the property which describes the order.
var data = [{ key: "DG Power Output", value: "6.00", unit: "kWh" }, { key: "DG Run Time", value: "5999999952", unit: "minutes" }, { key: "Fuel Level (Before)", value: "8.00", unit: "liters" }],
order = { "Fuel Level (Before)": 1, "DG Run Time": 2, "DG Power Output": 3 };
data.sort(({ key: a }, { key: b }) => order[a] - order[b]);
console.log(data);
The most basic I would go would be by accessing the index, let's say
var a = [
{ "key": "DG Power Output", "value": "6.00", "unit": "kWh", },
{ "key": "DG Run Time", "value": "5999999952", "unit": "minutes", },
{ "key": "Fuel Level (Before)", "value": "8.00", "unit": "liters", }
]
Then,
var b = [a[2], a[1], a[0]];
This would give the output you want but it's very risky and error-prone.
I'm not entirely sure what criteria you want to use to sort this array, but the general approach is to write a function that compares two elements and returns a number less than 0 for the first element to come first, 0 if they are equal, and a number greater than 0 for the second element to come first. You can then pass this function to Array.prototype.sort like this for descending order:
const sorter = (a, b) => {
if (a.key == b.key) return 0; // leave elements in place
if (a.key > b.key) return -1; // a should come before b for descending order
return 1; // b should come before a for descending order
};
const arr = [
{ "key": "DG Power Output", "value": "6.00", "unit": "kWh", },
{ "key": "DG Run Time", "value": "5999999952", "unit": "minutes", },
{ "key": "Fuel Level (Before)", "value": "8.00", "unit": "liters", }
];
console.log(arr.sort(sorter));

Strange values with bar stack Open Flash Chart

I'm trying to use the bar stack graph with Open Flash Chart. The JSON object I generate is containing correct values and when the chart is loaded the first part of the bar stack is correct but the ones after have gotten way of values.
The JSON object:
{
"title": {
"text": "Aktiviteter",
"style": "{font-size: 15px; text-align: center;}"
},
"elements": [
{
"type": "bar_stack",
"colours": [
"#b727e3",
"#f55225",
"#16196e",
"#b3ac3",
"#f01673"
],
"keys": [
{
"colour": "#b727e3",
"text": "Utst\u00e4llningar",
"font-size": 13
},
{
"colour": "#f55225",
"text": "Kurser",
"font-size": 13
},
{
"colour": "#16196e",
"text": "Resor",
"font-size": 13
},
{
"colour": "#b3ac3",
"text": "Kulturarrangemang",
"font-size": 13
},
{
"colour": "#f01673",
"text": "F\u00f6rel\u00e4sningar",
"font-size": 13
}
],
"values": [
[
{
"val": "205",
"tip": "Utst\u00e4llningar 2013<br>Antal #val#"
},
{
"val": "52",
"tip": "Kurser 2013<br>Antal #val#"
},
{
"val": "161",
"tip": "Resor 2013<br>Antal #val#"
},
{
"val": "123",
"tip": "Kulturarrangemang 2013<br>Antal #val#"
},
{
"val": "123",
"tip": "F\u00f6rel\u00e4sningar 2013<br>Antal #val#"
}
]
],
"on-show": {
"type": "pop",
"cascade": 1,
"delay": 0.5
}
}
],
"x_axis": {
"labels": {
"rotate": 20,
"labels": [
"2013"
]
}
},
"y_axis": {
"min": 0,
"steps": 66,
"max": 830
},
"tooltip": {
"mouse": 2
},
"bg_colour": "#FFFFFF"
}
Item #2:
{
"val": "52",
"tip": "Kurser 2013<br>Antal #val#"
},
, when displayed, got a value of 20 347 instead of 52 and therefore doesnt fit into the y-axis. (image http://s8.postimg.org/jfeh9u2d1/Namnlo_st.png)
I load the Chart by
<script type="text/javascript" src="js/js/swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF(
"open-flash-chart.swf", "my_chart", "550", "200",
"9.0.0", "expressInstall.swf",
{"data-file":"get_stats2.php?action=activities%26type=total%26limit=1"}
);
Any suggestions?

Categories

Resources