Derive HTML based on value of nested array - ecmascript-6

Looking to group and create relevant html based from an object.
const _ = require('lodash');
const items = [
{
value: 'fruit',
label: 'apple',
},
{
value: 'Mango',
label: 'Mango',
groupBy: 'fruit'
},
{
value: 'Orange',
label: 'Orange',
groupBy: 'fruit'
},
// Will need to group all above by fruit, similarly
{
value: 'vegetable',
label: 'artichoke',
},
{
value: 'aubergine',
label: 'aubergine',
groupBy: 'vegetable'
}
];
_renderItems = () => {
const itemsList = _.chain(items)
.map(item => (
this._renderItem(item)
))
.value()
return '<div class="item-container">'+ itemsList+'</div>'
}
_renderItem = (item = {}) => {
console.log(item)
}
_renderItems()
/*
desired output
<div class="fruit">
Label:Apple
Label:Mango
Label:Orange
</div>
<div class="vegetable">
label:artichoke
label:aubergine
label:broccoli
</div>
*/
Code sample here of progress here https://repl.it/repls/ElectronicUsableTheories . In general, I have trouble adding a wrapping div based on grouped value.
So all fruit should be grouped first key will not have groupBy key but its value will be the key of all next items which needs to be grouped

Group the items by the groupBy or by value if groupBy doesn't exist. Then you can map the groups. The 2nd parameter that map passes to the callback is the key (the groupBy value), that you can use as the class. It addition map the items, take the label, and format. Combine the group's string, and the itemList's string, and return.
const items = [{"value":"fruit","label":"apple"},{"value":"Mango","label":"Mango","groupBy":"fruit"},{"value":"Orange","label":"Orange","groupBy":"fruit"},{"value":"vegetable","label":"artichoke"},{"value":"aubergine","label":"aubergine","groupBy":"vegetable"}];
const _renderItem = ({ label } = {}) => `label: ${label}\n`;
const _renderItems = () =>
_(items)
.groupBy(o => o.groupBy || o.value) // if not groupBy use value
.map((group, key) => {
const itemsList = group.map(_renderItem).join('');
return `<div class="item-container ${key}">\n${itemsList}</div>`;
})
.join('\n');
const result = _renderItems();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Related

when records are grouped by a column, the groups are sorted according to the values of this column in ag-grid

`{
headerName: 'Overdue INR ',
field: 'overduelcy',
type: 'rightAligned',
filter: true,
sort: 'desc',
filterValueGetter: (params: ValueGetterParams) => {
const colId = params.column.getColId();
return this.currencyFormatter(params.data.overduelcy);
},
aggFunc: (params: any) => {
let sum = 0;
params.values.forEach(
(overduelcy: number) => sum += overduelcy);
return sum ? sum : 0 ;
},
valueGetter: (params: any) => {
if (!params.node.group) {
return {
toString: () => (params.data.overduelcy) ? params.data.overduelcy : 0,
}
}
return null;
},
},
`
I want only group column sum sort order desc not all row level data.
ag-grid sort all row level also.
there is sortByGroupSummaryInfo: functionality in devextreme data grid I can manage this problem solution with Devextreme but not with ag-grid.
devextreme example

JSON data calculation and re-formate using Angular

I have a JSON file and I am trying to calculate the JSON file key based on the value and reformating it. My JSON file looks like below:
data=[
{
pet:'Cat',
fruit:'Apple',
fish:'Hilsha'
},
{
pet:'Dog',
fish:'Carp'
},
{
pet:'Cat',
fruit:'Orange',
fish:'Lobster'
}
];
I do like to calculate and formate it like below:
data=[
{
label:'Pet',
total:3,
list:[
{
name:'Cat',
value: 2,
},
{
name:'Dog',
value: 1,
}
]
},
{
label:'Fruit',
total:2,
list:[
{
name:'Apple',
value: 1,
},
{
name:'Orange',
value: 1,
}
]
},
{
label:'Fish',
total:3,
list:[
{
name:'Hilsha',
value: 1,
},
{
name:'Carp',
value: 1,
},
{
name:'Lobster',
value: 1,
}
]
},
];
If anybody can help me, it will be very help for me and will save a day.
I have fixed this task myself. If I have any wrong, you can put your comment fill-free :)
``
ngOnInit(): void {
this.dataService.$data.subscribe(data => {
// Create new object and calculation according to category
let petObj: any = {}
let fruitObj: any = {}
let fishObj: any = {}
data.forEach((el: any) => {
if (el.pet != undefined) {
petObj[el.pet] = (petObj[el.pet] || 0) + 1;
}
if (el.fruit != undefined) {
fruitObj[el.fruit] = (fruitObj[el.fruit] || 0) + 1;
}
if (el.fish != undefined) {
fishObj[el.fish] = (fishObj[el.fish] || 0) + 1;
}
});
// Create list according to category
let pet_list: any = [];
let fruit_list: any = [];
let fish_list: any = [];
for (var key in petObj) {
let pet = {
label: key,
value: petObj[key]
}
pet_list.push(pet)
}
for (var key in fruitObj) {
let fruit = {
label: key,
value: fruitObj[key]
}
fruit_list.push(fruit)
}
for (var key in fishObj) {
let fish = {
label: key,
value: fishObj[key]
}
fish_list.push(fish)
}
// Calculate total sum according to category
var totalPet = pet_list.map((res: any) => res.value).reduce((a: any, b: any) => a + b);
var totalFruit = fruit_list.map((res: any) => res.value).reduce((a: any, b: any) => a + b);
var totalFish = fish_list.map((res: any) => res.value).reduce((a: any, b: any) => a + b);
// Rearrange the JSON
this.rearrangeData = [
{
label: 'Pet',
total: totalPet,
list: pet_list
},
{
label: 'Fruit',
total: totalFruit,
list: fruit_list
},
{
label: 'Fish',
total: totalFish,
list: fish_list
}
]
console.log(this.rearrangeData)
// End rearrange the JSON
});
}
``
You can simplify your function. Take a look this one
group(oldData) {
const data = []; //declare an empty array
oldData.forEach((x) => {
//x will be {pet: 'Cat',fruit: 'Apple',fish: 'Hilsha'},
// {pet: 'Dog',fish: 'Carp'}
// ...
Object.keys(x).forEach((key) => {
//key will be 'pet','fruit',...
const item = data.find((d) => d.label == key); //search in the "data array"
if (item) { //if find it
item.total++; //add 1 to the property total of the element find it
// and search in the item.list the 'Cat'
const list = item.list.find((l) => l.name == x[key]);
//if find it add 1 to the property value of the list
if (list)
list.value++;
else
//if not, add to the list
//an object with property "name" and "value" equal 1
item.list.push({ name: x[key], value: 1 });
} else
//if the element is not in the "array data"
//add an object with properties label, total and list
//see that list is an array with an unique element
data.push({
label: key,
total: 1,
list: [{ name: x[key], value: 1 }],
});
});
});
return data;
}
You can use like
this.dataService.$data.subscribe(data => {
this.rearrangeData=this.group(data)
}
NOTE: this function the labels are 'pet','fruit' and 'fish' not 'Pet', 'Fruit' and 'Fish'
Did you try reading the text leading up to this exercise? That'd be my first approach. After that, I'd use reduce. You can do pretty much anything with reduce.

Javascript (es6) possible to destructure and return on a single line?

I'm curious if it's possible to return a destructured object on the same line it was destructured.
Current (working) examples:
using 2 lines
const itemList = json.map((item) => {
const { id, title } = item;
return { id, title };
});
1 line but not destructured
const itemList = json.map((item) => {
return { id: item.id, title: item.title }; // This also requires repeating the field name twice per instance which feels hacky
});
Is it possible to condense the body down to one line ?
example (doesn't work)
const itemList = json.map((item) => {
return { id, title } = item;
}
Destructure the callback parameters, and return an object:
const itemList = json.map(({ id, title }) => ({ id, title }))

ES6 first order functions: find array index of first object with child array that contains a value

I want to make a cool higher-order function chain for what I could do (perhaps more verbosely) like this:
for (var idx = 0; idx < collecionA.length; idx++) {
for (item in collectionA[idx].children) {
if (item.sku == "someVal") return idx
}
}
Does anyone see a snazzy way to do this with map/find/filter/reduce etc.? I keep wanting to use forEach but then get pwnd when I realize I can't return from it.
Something like:
return collectionA.children.findIndex( (child) => child.children.oneOfThemIncludesAnObjectWithThisProperty("someVal"))
Use Array.findIndex() on the outer collection. For each item, iterate the children with Array.some(), and check if the value of the property (sku) matches the requested value. As soon as a matching value is found, some returns true immediately, and findIndex returns the current index.
const collection = [{"children":[{"sku":"someOtherVal"}]},{"children":[{"sku":"someVal"}]},{"children":[{"sku":"someOtherVal"}]}];
const findIndexWithChildProp = (arr, prop, val) =>
arr.findIndex(({ children }) =>
children.some(({ [prop]: v }) => v === val));
const result = findIndexWithChildProp(collection, 'sku', 'someVal');
console.log(result);
This could be what you are looking for:
function func() {
var index = -1;
collectionA.forEach((p, i) => p.children.forEach(item => {
if (item.sku == "someVal") index = i;
}));
return index;
}
var collectionA = [{
children: [{
sku: "someOtherVal"
}]
}, {
children: [{
sku: "someVal"
}]
}, {
children: [{
sku: "someOtherVal"
}]
}]
console.log(func());

React/JSX - iterating JSON object & nest every X items in .row

There must be an easy answer to this but I can't seem to find one.
JSON: -
{
1: {
'desc' : 'desc1',
'title' : 'title 1',
},
2: {
'desc' : 'desc2',
'title' : 'title 2',
},
3: {
'desc' : 'desc3',
'title' : 'title 3',
},
4: {
'desc' : 'desc4',
'title' : 'title 4',
},
5: {
'desc' : 'desc5',
'title' : 'title 5',
},
6: {
'desc' : 'desc6',
'title' : 'title 6',
},
};
So basically I want to iterate this object and have every 3 items nest in a .row class div like this: -
<div class='row'>
<div>desc1 : title1</div>
<div>desc2 : title2</div>
<div>desc3 : title3</div>
</div>
<div class='row'>
<div>desc4 : title4</div>
<div>desc5 : title5</div>
<div>desc6 : title6</div>
</div>
Now I understand how I can simple render() this in a component: -
{
Object.keys(JSONObject).map(key => <TheComponent key={key} details={JSONObject[key]} />)
}
However, I am stumped as to how I can split this into 2 rows of 3 items and nest each of the 3 items in the .row div.
Any help greatly appreciated. I am relatively new to ES6/ReactJS and eager to get past the teething problems.
One way of looking at this is to split the array up first into chunks, then working with that.
So you could get your initial array;
var ar1 = Object.keys(JSONObject);
Then chunk it up
var ar2 = [];
var i, j, chunk = 3;
for (i = 0, j = ar1.length; i < j; i += chunk) {
ar2.push(ar1.slice(i, i+chunk));
}
This will then give you ar2 which is an array of arrays. You could then either loop through this and output the level one array with the rows, then the level 2 array with the inner html.
See this basic bit of code on jsbin to demo the chunking
let arrTheComponent = [], arrJson = [];
Object.keys(JSONObject).map(key => {
arrJson.push(JSONObject[key]);
if (arrJson.length === 3) {
arrTheComponent.push(<TheComponent json={arrJson} />);
arrJson = [];
}
})
Display the component
export const TheComponentList = () => {
let arrTheComponent = [], arrJson = [];
Object.keys(JSONObject).map(key => {
arrJson.push(JSONObject[key]);
if (arrJson.length === 3) {
arrTheComponent.push(<TheComponent json={arrJson} />);
arrJson = [];
}
})
return (<div>
{arrTheComponent}
</div>);
}
I did something very similar, so here is the code I used:
let rowCount = 0;
let rows = [];
Object.keys(JSONObject).forEach((k, i) => {
// this just makes sure there is always an array initialised
rows[rowCount] = rows[rowCount] || [];
// now we add into the current row a component
rows[rowCount].push(
<TheComponent
key={k}
details={JSONObject[key]}
/>
);
if ((i + 1) % 3 === 0) { // the 3 here is how many items you want per row!!
// if we can perfectly divide the current position by 3
// we have filled a row, so now increment the row
rowCount++;
}
});
This will give you an array of arrays:
[
[ <TheComponent key=1 />, <TheComponent key=2 /> <TheComponent key=3 /> ]
[ <TheComponent key=4 /> ... ]
[ .... ]
]
Then you can render like this:
render() {
const rows = this.groupRows(); // this is the function above
// ar below is a single array of <TheComponent ... /> so looks like:
// [ <TheComponent ... />, ... ]
return (
<div>
{ rows.map((ar, i) => <div className="row"> { ar } </div>) }
</div>
);
}
Addendum
I actually created a component to do this for me, so I could use it like so:
render() {
return (
<Grouper>
{ Object.keys(JSONObject).map(k => <TheComponent key={k} details={ JSONObject[key] } />) }
</Grouper>
);
}
And what the <Grouper /> component did was React.Children.forEach(...) grouping them using the code I have above. Which meant all that component scaffolding code was nicely abstracted away from the business view logic.