How can I group rows in react-data-table-component? - reactjs

I am facing a problem when I need to group rows in a table using react-data-table-component.
My dataset:
const cars = [{
"brand": "audi",
"model": "a4",
"hp": "200",
},
{
"brand": "audi",
"model": "a5",
"hp": "300",
},
{
"brand": "audi",
"model": "rs6",
"hp": "500",
},
{
"brand": "tesla",
"model": "model 3",
"hp": "200",
},
{
"brand": "tesla",
"model": "model x",
"hp": "450",
}
];
The table should be structured like this:
How can I achieve this?
I am using hook-like style.
One can use cell property to render. So I create some index to track which brand has already been rendered and if a brand is already on the table it just returns an empty cell.
The code I am using:
const [brandIndex, setBrandIndex] = useState<(string | undefined)[]>([]);
const renderBrand = useCallback((row: CarDto) => {
const alreadyRendered = brandIndex.some(b => b === row.brand);
if (alreadyRendered) {
return null;
} else {
setBrandIndex(brandIndex.concat(row.brand));
return <span>{row.brand}</span>;
}
},[setBrandIndex, brandIndex])
//...
{
id: "brand",
name: "Brand",
selector: (row) => row.brand || "",
cell: renderBrand,
sortable: true,
resizable: true,
width: "200px",
},
Unfortunately this code is not working, all brands in my table are empty after rendering. The table renders a lot of times, so I assume that index contains all brands. The last rendering returns null in the first column.

Related

Angular *ngFor: Display only unique property "category" value and lowest price in each "category"

I have an array with objects having "category" & "price" properties among others, in the Angular application I need to display only unique values of "category" property (Example: Economy, Premium & Deluxe) along with the lowest price in that category. I tried filtering it but was unable to achieve it. So can you please help how this can be achieved in Angular? Thank you.
In this example, I need to show:
Economy - Starts from 250USD
Premium - Starts from 400USD
Deluxe - Starts from 600USD
"hotelRooms": [
{
"price": {
"total": 250,
"currency": "USD"
},
"category": "Economy",
"subcategory": "single",
},
{
"price": {
"total": 350,
"currency": "USD"
},
"category": "Economy",
"subcategory": "double",
},
{
"price": {
"total": 450,
"currency": "USD"
},
"category": "Economy",
"subcategory": "family",
},
{
"price": {
"total": 400,
"currency": "USD"
},
"category": "Premium",
"subcategory": "single",
},
{
"price": {
"total": 500,
"currency": "USD"
},
"category": "Premium",
"subcategory": "double",
},
{
"price": {
"total": 600,
"currency": "USD"
},
"category": "Deluxe",
"subcategory": "single",
},
{
"price": {
"total": 700,
"currency": "USD"
},
"category": "Deluxe",
"subcategory": "double",
}
]
And in Angular:
<div *ngFor="let room of hotelRooms">
<span class="bold">{{ room.category }}</span> - Starts from {{ room.price.total}}{{ room.price.currency}}
</div>
From what I understand on this question, you need to group by category and next get the lowest price.amount for each category.
Concept (TL;DR)
Group By Category
1.1 Create an array for each category if the category array does not exist. Else reuse the created category array.
1.2 From each category array, find the lowest record based on price.amount.
1.3 If the result (from 1.2) return no value (undefined), first reset category array to empty array and add the current record to the category array. This ensures that each category will only have 1 record with the lowest price. Else just ignore it.
Data Transformation
2.1 Get the item from each category via iterate with key. It will return arrays.
2.2 Concat multiple arrays (from 2.1) into one array.
let groupByCategories = [];
groupByCategories = this.hotelRooms.reduce(function (previous, current) {
previous[current.category] = previous[current.category] || [];
let lowest = previous[current.category].find(
(x) =>
x.price.total < current.price.total
);
if (!lowest) {
previous[current.category] = [];
previous[current.category].push(current);
}
return previous;
}, Object.create(null));
this.hotelRooms = [].concat(
...Object.keys(groupByCategories).map((key) => {
return groupByCategories[key];
})
);
Sample Demo on StackBlitz

Groupby array of object multiple times

considering the following data
let dataset =
[
{
"Category": "Auto",
"Parent": "Automotive",
"name": "Auto - Multi Purpose Vehicles",
"High": "10",
"Low": "15",
"Medium": "5"
},
{
"Category": "Auto",
"Parent": "Automotive",
"name": "Auto - Off road",
"High": "1",
"Low": "2",
"Medium": "3"
},
{
"Category": "Auto",
"Parent": "Ecology & Environment",
"name": "Vegetarian",
"High": "5",
"Low": "5",
"Medium": "10"
},
{
"Category": "Home",
"Parent": "Ecology & Environment",
"name": "Weather",
"High": "10",
"Low": "15",
"Medium": "5"
}]
I want to group data in the following way
[{
name: "Auto",
data: [{
name: "Automotive",
data: [{
name: "Auto - Multi Purpose Vehicles",
value: 30
High: 10,
Low: 15,
Medium: 5
},
{
name: "Auto - Off road",
value: 6
High: 1,
Low: 2,
Medium: 3
}]
}, {
name: 'Ecology & Environment',
data: [{
name: "Vegetarian",
value: 20
High: 5,
Low: 5,
Medium: 10
}]
}],
name: "Home",
data: [{
name: "Ecology & Environment",
data: [{
name: "Weather",
value: 30
High: 10,
Low: 15,
Medium: 5
}]
}]
}]
What I've tried so far never land me to the desired output.
here is where I'm stacked.
let cat = []
dataset.forEach((d) => {
const { Category, Parent, name, High, Medium, Low, value } = d;
let category = cat.find((item) => item.Category === Category);
let parent = cat.find((item) => item.data.Parent === Parent);
if (!category) {
cat.push({
Category,
data: []
})
} else if (!parent ) {
cat.forEach(i => {
i.data.push({
Parent,
High,
Medium,
Low
})
})
}
})
I've tried several ways with different results but I'm not able to figure out how to handle it
I'm not an expert in javascript. I'm trying to learn by doing but sometimes i get stack
Many thanks for any help
P.
In order to get the answer you want, follow this code.
step 1:
fire get the unique category from the dataset
step 2:
after getting a unique category, look for the particular category into a dataset, and when a category is found push it into the array
follow below code snippet
let dataset = [
{
Category: "Auto",
Parent: "Automotive",
name: "Auto - Multi Purpose Vehicles",
High: "10",
Low: "15",
Medium: "5",
},
{
Category: "Auto",
Parent: "Automotive",
name: "Auto - Off road",
High: "1",
Low: "2",
Medium: "3",
},
{
Category: "Auto",
Parent: "Ecology & Environment",
name: "Vegetarian",
High: "5",
Low: "5",
Medium: "10",
},
{
Category: "Home",
Parent: "Ecology & Environment",
name: "Weather",
High: "10",
Low: "15",
Medium: "5",
},
];
/* map function help us to get non unique
categoty like => [ 'Auto', 'Auto', 'Auto', 'Home' ]
`New Set()` object gave us unique array then
we create new array using spread oprator */
let uniqueCategory = [...new Set(dataset.map((data) => data.Category))];
let uniqueParent = [...new Set(dataset.map((data) => data.Parent))];
// create new array for storing final output
let cat = [];
// loop over unique category
uniqueCategory.forEach((Category) => {
// create new object for perticular category
let obj = {
name: Category,
data: [],
};
uniqueParent.forEach((parent) => {
let isDataEmpty = true;
let parentObj = {
name: parent,
data: [],
};
// loop over dataset
dataset.map((data) => {
/* if we fount category same as unique category we have
to push that data into particular category object */
if (data.Category === Category && data.Parent === parent) {
// delete category ket/value from object
isDataEmpty = false;
delete data.Category;
parentObj.data.push(data);
}
});
if (!isDataEmpty) obj.data.push(parentObj);
});
cat.push(obj);
});
console.log(cat);

Combining Column charts and line charts with the same same data in the same container(Highcharts)

I want to build a combination chart with a column chart with multiple series and a line chart. Problem is that I am getting High charts data from nested JSON response. For that I initialized array and that array is giving in series in plotoptions highcharts as you can see in the below code.
My code is like this:
var crime_data=[];
for(var i=0;i<result.themes.length;i++){
var crime={};
var test2 = result.themes[i];
var test = test2[Object.keys(test2)];
crime.name = Object.keys(result.themes[i]);
crime.data = [];
for(var k=0;k<test.yearTheme.length;k++){
var test3=test.yearTheme[k];
var test5=test3.individualValueVariable;
for(var j=0;j<test5.length;j++){
crime.data.push(test5[j].count);
};
};
crime_data.push(crime);
};
var crimeChart = new Highcharts.Chart({
chart: {
renderTo: 'container1',
type:'column'
},
title: {
text: 'Crime'
},
xAxis: {
categories: month,
crosshair: true
},
yAxis: {
min: 0,
title: {
text: 'Count'
}
},
credits: {
enabled: false
},
tooltip: {
shared: true,
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0,
depth: 25,
allowPointSelect: true,
cursor: 'pointer',
point: {
},
}
},
series: crime_data
});
This is Column chart I am getting when i write chart type column.
This is my Line Chart I am getting when i changed type column to spline in chart in highcharts.
And this is my JSON data(Highcharts data):
{
"boundaries": {
"boundary": [
{
"boundaryId": "55083021003",
"boundaryType": "USA_CITY",
"boundaryRef": "C1"
}
]
},
"themes": [
{
"AssaultCrimeTheme": {
"boundaryRef": "C1",
"individualValueVariable": [
{
"name": "2013 Assault Crime",
"description": "Assault Crime for 2013",
"count": 18901
},
{
"name": "2014 Assault Crime",
"description": "Assault Crime for 2014",
"count": 17707
}
]
}
},
{
"BurglaryCrimeTheme": {
"boundaryRef": "C1",
"individualValueVariable": [
{
"name": "2013 Burglary Crime",
"description": "Burglary Crime for 2013",
"count": 17743
},
{
"name": "2014 Burglary Crime",
"description": "Burglary Crime for 2014",
"count": 14242
}
]
}
}
]
}
I want to combine both of them in the same container with same data.The problem is in how to tell highcharts multiple series should be represented with line and with column type with same data.For this when i write series:[{ data: crime_data ,type: spline }] instead of series:crime_data In that case I am not getting Highcharts data. Can anyone Please help me how should i do this.Please suggest me.
Pass your data, like below format. add type of chart in each data series;
Here i replaced type value but with same data.
[{
type: 'line',
name: 'AssaultCrimeTheme',
data: [3, 2, 1, 3, 4]
}, {
type: 'line',
name: 'BurglaryCrimeTheme',
data: [2, 3, 5, 7, 6]
}, {
type: 'column',
name: 'AssaultCrimeTheme',
data: [3, 2, 1, 3, 4]
}, {
type: 'column',
name: 'BurglaryCrimeTheme',
data: [2, 3, 5, 7, 6]
},]
Here is fiddle for more details.
Here is a complete example using your data.
const json = {
"boundaries": {
"boundary": [{
"boundaryId": "55083021003",
"boundaryType": "USA_CITY",
"boundaryRef": "C1"
}]
},
"themes": [{
"AssaultCrimeTheme": {
"boundaryRef": "C1",
"individualValueVariable": [{
"name": "2013 Assault Crime",
"description": "Assault Crime for 2013",
"count": 18901
}, {
"name": "2014 Assault Crime",
"description": "Assault Crime for 2014",
"count": 17707
}]
}
}, {
"BurglaryCrimeTheme": {
"boundaryRef": "C1",
"individualValueVariable": [{
"name": "2013 Burglary Crime",
"description": "Burglary Crime for 2013",
"count": 17743
}, {
"name": "2014 Burglary Crime",
"description": "Burglary Crime for 2014",
"count": 14242
}]
}
}]
}
// Create categories object in order filter duplicates
const cats = {}
const series = json.themes.map((o) => {
const key = Object.keys(o)[0]
return {
name: key,
data: o[key].individualValueVariable.map((o) => {
cats[o.name] = 1
return { category: o.name, y: o.count }
})
}
})
// Convert categories object to array
const categories = Object.keys(cats)
// Chart options
const options = {
chart: {type: 'column'},
xAxis: {categories: categories},
series: series
}
// Create chart
const chart = Highcharts.chart('container', options)
console.log(series, categories)
Live example: https://jsfiddle.net/Lo323gq3/
Output below:

How can I change the attribute in dataset of Fusionchart?

Hi I am implementing a chart in my Angularjs Application, You can see this plunker http://jsfiddle.net/fusioncharts/73xgmacm/ The thing which I want to achieve is to change the value attribute to profit. How can I do this ? I want to display profit not values.
Regards
After 2 days I finally find out the answer. The thing is You cannot change the Fusionchart attribute value but you can change the attribute of your API once you fetched. I used a loop after I fetched the API and replace the 'profit' attribute with value in this way I made the chart. Yes The thing which i had been ignoring was the use of 'variable' instead of scope. If you see this example you would understand Example Here. I am sharing my code May be it helps someone else too.
Give below is my json array which i called tps.json
[
{
"index": "1",
"variantoption": "fan-green",
"company": "sk fans",
"quantity": "650",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "2",
"variantoption": "fan-white",
"company": "al ahmed fans",
"quantity": "450",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "3",
"variantoption": "fan-purple",
"company": "asia fans",
"quantity": "350",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "4",
"variantoption": "fan-yellow",
"company": "falcon fans",
"quantity": "250",
"profit": "78296",
"loss": "8457",
"year": "2016"
}
]
and here is my controller
$http.get('js/tps.json').success(function (data) {
var chartdata = data;
var arrLength = chartdata.length;
console.log(arrLength);
for (var i = 0; i < arrLength; i++) {
if (chartdata[i]['profit'] && chartdata[i]['index']) {
chartdata[i].value = chartdata[i].profit;
delete chartdata[i].profit;
chartdata[i].label = chartdata[i].index;
delete chartdata[i].index;
console.log(chartdata);
}
}
console.log(chartdata);
FusionCharts.ready(function () {
var tps = new FusionCharts({
type: 'column2d',
renderAt: 'chart-container',
width: '500',
height: '300',
dataFormat: 'json',
dataSource: {
"chart": {
"caption": "Monthly",
"xaxisname": "Month",
"yaxisname": "Revenue",
"numberprefix": "$",
"showvalues": "1",
"animation": "1"
},
"data" : chartdata
}
});
tps.render();
});
}
);
}
-Stay foolish stay hungry

Add optgroups to angular-selectize asynchronously

I am using angular-selectize directive in my project. For this, I need to load optgroups asynchronously. So far I have tried multiple approaches but none of them works. The problem is, you cannot use the data returned by a promise synchronously. On the flip side, I have also been unable to initialize selectize from inside a promise callback. Given below is the code I currently have. Note that it is only to be used to get the idea of the data I'm playing with, not to present it as something you can consider right.
app.js
$http
.get('/get-categories')
.then(getCategoriesSCB, getCategoriesFCB);
function getCategoriesSCB(response) {
if(typeof(response.data) === 'object') {
posControl.menuCategories = response.data[0];
posControl.menuCategoryGroups = response.data[1];
}
else {
getCategoriesFCB(response);
}
}
function getCategoriesFCB(response) {
console.log(response);
}
posControl.menuConfig = {
valueField: 'id',
labelField: 'title',
placeholder: 'Select Category',
optgroupField: 'class',
optgroupLabelField: 'label',
optgroupValueField: 'value',
optgroups: posControl.menuCategoryGroups,
maxItems: 1,
searchField: ['title', 'category'],
onInitialize: function(selectize) {
console.log('selectize is here');
},
}
index.html
<selectize config="POSCtrl.menuConfig" options="POSCtrl.menuCategories" ng-model="POSCtrl.menuModel"></selectize>
data returned by ajax call
[
// this array has to be used for options.
[{
"class": "57b83830babb9",
"category": "Food Menu",
"id": "57b83855b23f9",
"title": "Beverages"
}, {
"class": "57b83830babb9",
"category": "Food Menu",
"id": "57b83855c05de",
"title": "Cuisines"
}, {
"class": "57b83830babb9",
"category": "Food Menu",
"id": "57b83855cdcb4",
"title": "Steaks"
}, {
"class": "57b83830d0899",
"category": "Wholesale Coffee",
"id": "57b83830d0899",
"title": "Wholesale Coffee"
}],
// this array has to be used for optgroups
[{
"value": "57b83830babb9",
"label": "Food Menu"
}, {
"value": "57b83830d0899",
"label": "Wholesale Coffee"
}]
]
You should be able to load a selectize asynchronously by setting the values directly on the posControl.menuConfig:
function getCategoriesSCB(response) {
if (typeof(response.data) === 'object') {
posControl.menuConfig.options = response.data[0];
posControl.menuConfig.optgroups = response.data[1];
}
}

Resources