I'm quite confused how to calculate data json that i have. I have data json
"id" : "001","item" : "samsung","quantity" : 2, "price" : $300. first i want to calculate subtotal = quantity*price. and that works. but i dont have idea how to calculate total. anybody can help?
this is js that hold data json
export function DataBarang () {
return [{
"id" : "001",
"item" : "samsung",
"quantity" : 1,
"price" : 300,
},
{
"id" : "002",
"item" : "iphone",
"quantity" : 2,
"price" : 450,
}];
}
and than this is table that display data
import React, { Component } from 'react';
import { DataBarang } from './Barang';
class cart extends Component{
constructor(props) {
super(props)
this.state = {
json: []
}
}
componentDidMount() {
this.setState((prevState) => {
return {
json: DataBarang()
}
})
}
render (){
return (
<table id="cart" className="table table-hover table-condensed">
<thead>
<tr>
<th styles="width:50%" className="text-center">Item</th>
<th styles="width:10%" className="text-center">Price</th>
<th styles="width:8%" className="text-center">Quantity</th>
<th styles="width:22%" className="text-center">Subtotal</th>
<th styles="width:10%" className="text-center">Action</th>
</tr>
</thead>
<tbody>
{this.state.json.map((data, i) => {
var subtotal = data.price*data.quantity;
var total = total+subtotal;
return (
<tr key={i}>
<td data-th="Product">
<div className="row">
<img src={} alt="..." className="img-responsive"/>
<div className="col-sm-10">
<h4 className="nomargin">{data.item}</h4>
</div>
</div>
</td>
<td data-th="Price">Rp.{data.price}</td>
<td data-th="Quantity">
<input type="number" className="form-control" value={data.quantity}/>
</td>
<td data-th="Subtotal" className="text-center">Rp.{subtotal}</td>
<td className="actions" data-th="">
<button className="button is-danger"><i className="fa fa-trash-o"></i></button>
</td>
</tr>);
})}
</tbody>
<tfoot>
<tr>
<td><Link to ="/" className="button is-warning"><i className="fa fa-angle-left"></i> Lanjut Berbelanja</Link></td>
<td colspan="2" className="hidden-xs"></td>
<td className="hidden-xs text-center"><strong>Total Rp. {}</strong></td>
<td>Checkout <i className="fa fa-angle-right"></i></td>
</tr>)
</tfoot>
</table>
);
}
}
export default cart;
and tell me how to delete data using button () onClick
If you're just looking to sum up the entire JSON you receive of quantity * price, then you can do it as a separate calculation.
const json = [{
"id" : "001",
"item" : "samsung",
"quantity" : 1,
"price" : 300,
},
{
"id" : "002",
"item" : "iphone",
"quantity" : 2,
"price" : 450,
}];
const total = json.map(({quantity, price}) => quantity * price)
.reduce((a, b) => a + b)
console.log(total)
In order to handle a delete, make a new function that accepts the id of the element that uses filter to remove it from your this.state.json. Here is a barebones example.
handleDelete(id) {
const filteredJSON = this.state.json.filter(item => {
return item.id !== id
})
this.setState({json: filteredJSON})
}
render() {
return (
<div>
{this.state.json.map((data, i) => {
const id = data.id
return (
<div>
{data.item}
<button onClick={() => this.handleDelete(id)}>
{'delete'}
</button>
</div>
)
})}
</div>
)
}
Related
export const COLUMNS = [
{
Header : 'Total Cases',
accessor : 'totalcases',
},
{
Header : 'Active Cases',
accessor : 'activecases',
},
{
Header : 'Total Recovery',
accessor : 'recovery',
},
{
Header : 'Total Death',
accessor : 'deaths',
},
{
Header : 'New Cases',
accessor : 'newcases',
},
]
function Table({countryData}) {
const columns = useMemo(()=> COLUMNS, []);
const data = useMemo(()=> countryData, []);
const {
....
setGlobalFilter,
} = useTable({
columns,
data
}, useGlobalFilter, useSortBy);
const{globalFilter} = state;
return (
<>
<GlobalFilter filter={globalFilter} setFilter={setGlobalFilter}/>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
</>
)
}
export default Table
here I want to sort the entire table by default on the basis of new cases column and want toggle sort only on active cases and recovery. as Im new to react i dont know how to provide custom sort..............................................................................................................................................................................................................................................................
you can use :
columns.sort((a, b) => (a.accessor > b.accessor ) ? 1 : -1) More informision at this link: https://flaviocopes.com/how-to-sort-array-of-objects-by-property-javascript/
I want to implement highly dynamic table with column level filters applied to it and editable rows with validation applied to each cell of table.
I have implemented Dynamic table display with editable rows and dynamic validations. But struggling with Column level filters.
My Problem statement:
UI will receive table headers to display and corrosponding table rows data.
e.g. headers = ['name','age'] and data [{name:'abc',age:'xyz'},{name:'pqr',age:'xyz'}, ..]
with above setup I have implemented reactive form using formArray.
sample setup is created in stackblitz
here is my form :
<form [formGroup]="data_form">
<table class="table table-border">
<thead>
<tr>
<th>
name
</th>
<th>
age
</th>
<th><button class="btn btn-primary ">Save</button></th>
</tr>
<tr>
<th *ngFor="let th of rowKeys">
<ng-container *ngIf="th !=='isEditable'">
<input type="text" formControlName="{{th}}" />
</ng-container>
</th>
<th></th>
</tr>
</thead>
<tbody formArrayName="persons">
<ng-container *ngFor="let item of persons.controls;let j = index">
<tr [formGroupName]="j">
<ng-container *ngIf="!item.value.isEditable; else editable">
<td>{{ item.value.name }}</td>
<td>{{ item.value.age }}</td>
</ng-container>
<ng-template #editable>
<td><input formControlName="name" /></td>
<td><input formControlName="age" /></td>
</ng-template>
<td>
<button (click)="toggleEdit(j)">
{{ !item.value.isEditable ? "Edit": "Cancel"}}
</button>
</td>
</tr>
</ng-container>
</tbody>
</table>
</form>
<h2>
{{data_form.status}}
</h2>
and ts:
import { Component } from "#angular/core";
import {
FormArray,
FormBuilder,
FormControl,
FormGroup,
Validators
} from "#angular/forms";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
name = "Angular";
constructor(private fb: FormBuilder) {}
patterns = [
/^[.\d]+$/,
/^(yes|no)$/i,
/^[a-zA-Z0-9 _/]+$/,
/^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/
];
data = [
{
name: "Sachin",
age: 27,
isEditable: false
},
{
name: "Gopal",
age: 27,
isEditable: false
},
{
name: "Pankaj",
age: 24,
isEditable: false
}
];
rowKeys = Object.keys(this.data[0]);
keys = [...new Set(this.data.map(item => Object.keys(item)).flat())];
keyPattern = this.keys.map(item => ({
key: item,
pattern: this.patterns.find(pattern =>
this.data.every(i => pattern.test(i[item]))
)
}));
data_form = this.fb.group({
persons: this.fb.array(
this.data.map(item =>
this.fb.group(
this.keyPattern.reduce(
(prev, { key, pattern }) => ({
...prev,
[key]: [
item[key],
[Validators.required, Validators.pattern(pattern)]
]
}),
{}
)
)
)
)
});
get persons(): FormArray {
return this.data_form.get("persons") as FormArray;
}
toggleEdit(j) {
const currentEditStatus = this.persons.controls[j].get("isEditable").value;
this.persons.controls[j].get("isEditable").setValue(!currentEditStatus);
}
ngOnInit(){
this.rowKeys.forEach((num) => {
if (num == "isEditable") return;
const fc = new FormControl('');
this.data_form.addControl(num, fc)
});
/**
* How to filter formsArray ?
*/
// this.data_form.get('cuisp').valueChanges.pipe(
// debounceTime(100),
// distinctUntilChanged(),
// ).subscribe(val => {
// console.log(val)
// const result = this.persons.value.filter(res => {
// if (res['cuisp'] === val) {
// return res
// }
// });
// this.persons.patchValue(result)
// console.log(result)
// });
}
}
How to implement column level search so then when I search in Name column then respective name should get displayed.
Consider below approach using reactive programing.
The Steps are as below
Convert all your inputs to observables
Set up a Subject to use as a trigger for filtering
Combine the data and the subject using the combineLatest([...]) operator from rxjs
Below is a working code, See this demo on stackblitz
constructor(private fb: FormBuilder) {}
patterns = [
/^[.\d]+$/,
/^(yes|no)$/i,
/^[a-zA-Z0-9 _/]+$/,
/^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/
];
data$ = of([
{
name: "Sachin",
age: 27,
isEditable: false
},
{
name: "Gopal",
age: 27,
isEditable: false
},
{
name: "Pankaj",
age: 24,
isEditable: false
}
]);
filterStringSubject$ = new BehaviorSubject({});
filterStringAction$ = this.filterStringSubject$.asObservable();
filterString$ = this.filterStringAction$.pipe(
map(stringObject =>
Object.entries(stringObject).map(item => ({
key: item[0],
value: item[1]
}))
)
);
rowKeys$ = this.data$.pipe(
map(data => Object.keys(data[0])),
tap(rowKeys => {
rowKeys.forEach(num => {
if (num == "isEditable") return;
this.filterStringSubject$.next({
...this.filterStringSubject$.value,
[num]: ""
});
});
})
);
keys$ = this.data$.pipe(
map(data => [...new Set(data.map(item => Object.keys(item)).flat())])
);
keyPattern$ = combineLatest(this.keys$, this.data$).pipe(
map(([keys, data]) => {
return keys.map(item => ({
key: item,
pattern: this.patterns.find(pattern =>
data.every(i => pattern.test(i[item]))
)
}));
})
);
data_form: FormGroup;
dataFiltered$ = combineLatest([this.data$, this.filterString$]).pipe(
map(([data, filterString]) =>
this.persons?.value.filter(item =>
filterString.every(a => `${item[a.key]}`.includes(`${a.value}`))
)
)
);
dataForm$ = combineLatest([ this.data$,
this.keyPattern$]).pipe(
tap(([data, keyPattern]) => {
this.data_form = this.fb.group({
persons: this.fb.array(
data.map(item =>
this.fb.group(
keyPattern.reduce(
(prev, { key, pattern }) => ({
...prev,
[key]: [
item[key],
[Validators.required, Validators.pattern(pattern)]
]
}),
{}
)
)
)
)
});
}),
)
v$ = combineLatest([
this.dataForm$,
this.rowKeys$,
this.filterString$,
this.dataFiltered$
]).pipe(
map(([, rowKeys, filterString, dataFiltered]) => ({
rowKeys,
filterString,
dataFiltered
}))
);
get persons(): FormArray {
return this.data_form?.get("persons") as FormArray;
}
toggleEdit(j) {
const currentEditStatus = this.persons.controls[j].get("isEditable").value;
this.persons.controls[j].get("isEditable").setValue(!currentEditStatus);
}
filterBy(item, value) {
this.filterStringSubject$.next({
...this.filterStringSubject$.value,
[item]: value
});
}
ngOnInit() { }
In your HTML
<form [formGroup]="data_form" *ngIf='v$ | async as v'>
<table class="table table-border">
<thead>
<tr>
<th>
name
</th>
<th>
age
</th>
<th><button class="btn btn-primary ">Save</button></th>
</tr>
<tr>
<td *ngFor="let item of v.rowKeys">
<input *ngIf='item != "isEditable"' type="text"
(input)="filterBy(item, $event.target.value)" />
</td>
<th></th>
</tr>
</thead>
<tbody formArrayName="persons">
<ng-container *ngFor="let item of v.dataFiltered;let j = index">
<tr [formGroupName]="j">
<ng-container *ngIf="!persons.controls[j]?.get('isEditable').value; else editable">
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
</ng-container>
<ng-template #editable>
<td><input formControlName="name" /></td>
<td><input formControlName="age" /></td>
</ng-template>
<td>
<button (click)="toggleEdit(j)">
{{ !persons.controls[j]?.get('isEditable').value ? "Edit": "Cancel"}}
</button>
</td>
</tr>
</ng-container>
</tbody>
</table>
</form>
<h2>
{{data_form?.status}}
</h2>
This question already has answers here:
When should I use a return statement in ES6 arrow functions
(6 answers)
Why does JavaScript map function return undefined?
(13 answers)
Closed 24 days ago.
i have objects like this
let data = [
{ id: 1, name: "Manikanta", age: 20, Gender: "male"},
{ id: 2, name: "Varsha", age: 85, Gender: "female"},
{ id: 3, name: "Sai", age: 18, Gender: "male"},
{ id: 4, name: "John", age: 24, Gender: "female"},
];
let settings = [
{id :1 ,class :"col1",expandable:true},
{id :2,class :"col2",expandable:true},
{id :3,class :"col3",expandable:true},
{id :4,class :"col4",expandable:true}
]
let expandabaledata =[
{id:1 , content : "I am content 1" },
{id:2 , content : "I am content 2"},
{id:3 , content : "I am content 3" },
{id:4 , content : "I am content 4" }
]
where it is sent as props to another component and the receiving component will take those props and does some action on that objects to retrieve data and display as a table with collapse feature.
I am attaching a part of the code where i will do a map inside map and return a table row and i performed some checks with console logs where i could get the desired data after the if condition
{props.data.map((data) => {
props.settings.map((settings) => {
if(settings.id === data.id)
{ console.log(settings)
console.log(data);
return (
<tbody key={data.id}>
<tr
className="accordion-toggle collapsed"
data-toggle="collapse"
data-target={settings.expandable ? "#".concat(settings.class) : ""}
>
{settings.expandable ? (
<td className="expand-button"></td>
) : (
<td></td>
)}
<td>{data.id}</td>
<td>{data.name}</td>
<td>{data.Gender}</td>
</tr>
{props.expanddata.map((exdata) => {
if (exdata.id === data.id) {
return (
<tr key={exdata.id} className="hide-table-padding">
<td colSpan={parseInt("5")}>
<div
className="collapse in hdelm p-1"
id={settings.class}
>
<div className="row-3">{exdata.content}</div>
</div>
</td>
</tr>
);
}
})}
</tbody>
);}
}
I dont have any error but the table rows are not returning by those 2 map functions
You don't return anything from the first map function. Either add a return statement
{props.data.map((data) => {
return props.settings.map((settings) => {
if(settings.id === data.id)
{ console.log(settings)
console.log(data);
return (
<tbody key={data.id}>
<tr
className="accordion-toggle collapsed"
data-toggle="collapse"
data-target={settings.expandable ? "#".concat(settings.class) : ""}
>
{settings.expandable ? (
<td className="expand-button"></td>
) : (
<td></td>
)}
<td>{data.id}</td>
<td>{data.name}</td>
<td>{data.Gender}</td>
</tr>
{props.expanddata.map((exdata) => {
if (exdata.id === data.id) {
return (
<tr key={exdata.id} className="hide-table-padding">
<td colSpan={parseInt("5")}>
<div
className="collapse in hdelm p-1"
id={settings.class}
>
<div className="row-3">{exdata.content}</div>
</div>
</td>
</tr>
);
}
})}
</tbody>
);}
}
or you can remove the squigly brace. For one statement function bodies not having any brace or () around it then that statement result is automatically returned
{props.data.map((data) =>
props.settings.map((settings) => {
if(settings.id === data.id)
{ console.log(settings)
console.log(data);
return (
<tbody key={data.id}>
<tr
className="accordion-toggle collapsed"
data-toggle="collapse"
data-target={settings.expandable ? "#".concat(settings.class) : ""}
>
{settings.expandable ? (
<td className="expand-button"></td>
) : (
<td></td>
)}
<td>{data.id}</td>
<td>{data.name}</td>
<td>{data.Gender}</td>
</tr>
{props.expanddata.map((exdata) => {
if (exdata.id === data.id) {
return (
<tr key={exdata.id} className="hide-table-padding">
<td colSpan={parseInt("5")}>
<div
className="collapse in hdelm p-1"
id={settings.class}
>
<div className="row-3">{exdata.content}</div>
</div>
</td>
</tr>
);
}
})}
</tbody>
);}
I created the table I mentioned below using React js. When I click on the button below the table, I want to add a new row to the table. I have listed the react code I wrote below. how can I do that?
My React Code
const PPP13 = (props) => {
return (
<Jumbotron>
<p className="btn-group">13- List all owners of 20% or more of the equity of the Applicant</p>
<Table striped bordered hover>
<thead>
<tr>
<th>Owner Name</th>
<th>Title</th>
<th>Ownership %</th>
<th>TIN (EIN, SSN)</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<FormControl aria-label="DDD"/>
</td>
<td>
<FormControl aria-label="DDD"/>
</td>
<td>
<FormControl aria-label="DDD"/>
</td>
<td>
<FormControl aria-label="DDD"/>
</td>
<td>
<FormControl aria-label="DDD"/>
</td>
</tr>
</tbody>
</Table>
<Button className="btn-group" name="add" value="No">
Add more owners
</Button>
</Jumbotron>
)
}
Here is what you can do. Lets say you have a Main component which will get all details.
class Products extends React.Component {
constructor(props) {
super(props);
// this.state.products = [];
this.state = {};
this.state.filterText = "";
this.state.products = [
{
id: 1,
category: 'Sporting Goods',
price: '49.99',
qty: 12,
name: 'football'
}, {
id: 2,
category: 'Sporting Goods',
price: '9.99',
qty: 15,
name: 'baseball'
}, {
id: 3,
category: 'Sporting Goods',
price: '29.99',
qty: 14,
name: 'basketball'
}, {
id: 4,
category: 'Electronics',
price: '99.99',
qty: 34,
name: 'iPod Touch'
}, {
id: 5,
category: 'Electronics',
price: '399.99',
qty: 12,
name: 'iPhone 5'
}, {
id: 6,
category: 'Electronics',
price: '199.99',
qty: 23,
name: 'nexus 7'
}
];
}
handleAddEvent(evt) {
var id = (+ new Date() + Math.floor(Math.random() * 999999)).toString(36);
var product = {
id: id,
name: "empty row",
price: "mpty row",
category: "mpty row",
qty: 0
}
this.state.products.push(product);
this.setState(this.state.products);
}
handleProductTable(evt) {
var item = {
id: evt.target.id,
name: evt.target.name,
value: evt.target.value
};
var products = this.state.products.slice();
var newProducts = products.map(function(product) {
for (var key in product) {
if (key == item.name && product.id == item.id) {
product[key] = item.value;
}
}
return product;
});
this.setState({products:newProducts});
};
render() {
return (
<div>
<ProductTable onProductTableUpdate={this.handleProductTable.bind(this)} onRowAdd={this.handleAddEvent.bind(this)} products={this.state.products} />
</div>
);
}
}
This contains the code for adding row.Then for the table do something like this.
class ProductTable extends React.Component {
render() {
var onProductTableUpdate = this.props.onProductTableUpdate;
var product = this.props.products.map(function(product) {
return (<ProductRow onProductTableUpdate={onProductTableUpdate} product={product} key={product.id}/>)
});
return (
<div>
<button type="button" onClick={this.props.onRowAdd} className="btn btn-success pull-right">Add</button>
<table className="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>price</th>
<th>quantity</th>
<th>category</th>
</tr>
</thead>
<tbody>
{product}
</tbody>
</table>
</div>
);
}
}
Now for the row Comoponent:
class ProductRow extends React.Component {
render() {
return (
<tr className="eachRow">
<td>
{this.props.product.id}
</td>
<td>
{this.props.product.price}
</td>
<td>
{this.props.product.qty}
</td>
<td>
{this.props.product.category}
</td>
</tr>
);
}
}
Working Example:
https://jsfiddle.net/mrAhmedkhan/nvgozjhy/
Ok here's my plan:
First we create a state to hold all the data for the table. I've used an object instead of an array as it's much easier to do the change handling. With arrays you always end up doing all this awkward splicing. You can always parse the object out into an array when you're ready to use it elsewhere.
Then we render out each row of the table by mapping over the entries in our table state. Note we also write the change handler inside the map, meaning we can easily use the rowId (tableData key) to set our new state when a change comes in.
Finally we plop in a button to add more rows. This has a click handler associated with it (handleAddRowClick) which counts the number of rows we have and uses this to generate a new rowId. We use the new rowId to expand the tableData state to include a new defaultRow. I defined defaultRow outside of the function, this prevents it from being redeclared on every render.
import React, { useState } from 'react'
import { Table, Input, Button } from 'reactstrap'
const defautRow = { colA: '', colB: '' }
const IncreasableTable = props => {
const [tableData, setTableData] = useState({
row1: { colA: '', colB: '' }
})
const handleAddRowClick = () => {
const extantRowsCount = Object.keys(tableData).length
setTableData(s => ({
...s,
[`row${extantRowsCount}`]: defautRow
}))
}
return (
<>
<Table>
{
Object.entries(tableData).map(([rowId, data]) => {
const handleChange = ({ target: { name, value } }) => {
setTableData(s => ({
...s,
[rowId]: {
...s[rowId],
[name]: value
}
}))
}
return (
<tr key={rowId}>
<td>
<Input name="colA" value={data.colA} onChange={handleChange}/>
<Input name="colB" value={data.colB} onChange={handleChange}/>
</td>
</tr>
)
})
}
</Table>
<Button onClick={handleAddRowClick}>Click me to add more rows</Button>
</>
)
}
export default IncreasableTable
I am using redux and I am working on receiving data about membership information from action and processing it from components.
And try to process the data to a table.
I took data from user action and created a table through map functions... The incoming data contains
Data received as action ....
[{create_date : "2020-02-16T03:00:00Z", id:"test"},
{create_date : "2020-02-16T01:00:00Z", id:"test1"},
{create_date : "2020-02-14T03:00:00Z", id:"test2"},
{create_date : "2020-02-14T01:00:00Z", id:"test3"},
{create_date : "2020-02-14T00:00:01Z", id:"test4"},
{create_date : "2020-02-13T03:00:00Z", id:"test5"},
...]
As you can see, only create_date id is included.
I would like to order them by date and number them in order by next day after day.
For example, would like to print like this.
index create_date id
2 2020-02-16T03:00:00Z test
1 2020-02-16T01:00:00Z test1
3 2020-02-14T03:00:00Z test2
2 2020-02-14T01:00:00Z test3
1 2020-02-14T00:00:01Z test4
1 2020-02-13T03:00:00Z test5
How to insert index using if statement when using map function in react??
Mycode
render() {
const {user_list} = this.props;
console.log(user_list);
return (
<div className="animated fadeIn">
<Row>
<Col xl={12}>
<Card>
<CardHeader>
<i className="fa fa-align-justify"></i>userlist
</CardHeader>
<CardBody>
<Search searchUser={this.searchUser}/>
<Table responsive hover>
<thead>
<tr><th scope="col">Index</th>
<th scope="col">create_time</th>
<th scope="col">id/name</th>
</tr>
</thead>
<tbody>
{user_list.length > 0 && user_list.map((item, index) => (
<tr key={item.id.toString()}>
<td>{index}</td> //<<Does this change by date index.. if statement?
<td className={'datetime'}>
{item.hasOwnProperty('create_date') &&
<div>
{moment(item.create_date).format('YYYY-MM-DD')}<br/>
{moment(item.create_date).format('HH:mm')}
</div>
}
</td>
<td scope="row">
{item.displayName}
</td>
</tr>
))}
</tbody>
</Table>
</CardBody>
</Card>
</Col>
</Row>
</div>
)
}
....
Elaborate on comments of #James. I just changed a little bit.
You can group them first by date. And then flat it to a list you want. Plain javascirpt version:
let data = [{create_date : "2020-02-16T03:00:00Z", id:"test"},
{create_date : "2020-02-16T01:00:00Z", id:"test1"},
{create_date : "2020-02-14T03:00:00Z", id:"test2"},
{create_date : "2020-02-14T01:00:00Z", id:"test3"},
{create_date : "2020-02-14T00:00:01Z", id:"test4"},
{create_date : "2020-02-13T03:00:00Z", id:"test5"},
]
let groups = {}
for (let e of data.reverse()) {
let date = e.create_date.slice(0, 10)
if (groups[date]) {
let group = groups[date];
group.push({ index: group.length + 1, ...e });
} else {
groups[date] = [{ index: 1, ...e }]
}
}
const dates = Object.keys(groups).reverse()
const flatten = []
for (let date of dates) {
flatten.push(...(groups[date].reverse()))
}
console.log(flatten)
flatten should be logged as:
[ { index: 2, create_date: '2020-02-16T03:00:00Z', id: 'test' },
{ index: 1, create_date: '2020-02-16T01:00:00Z', id: 'test1' },
{ index: 3, create_date: '2020-02-14T03:00:00Z', id: 'test2' },
{ index: 2, create_date: '2020-02-14T01:00:00Z', id: 'test3' },
{ index: 1, create_date: '2020-02-14T00:00:01Z', id: 'test4' },
{ index: 1, create_date: '2020-02-13T03:00:00Z', id: 'test5' } ]
You should be able to render that directly in a map. Though I think it's better to store the flatten list as state or in redux store so that it won't do the transformation on every rerender.
Here's a minimal verifiable complete working demo (https://codepen.io/Alexander9111/pen/rNVeyyY), taking part of the excellent grouping and flattening function from #bedew and then sorting it into date and "index" to give the following output (in React CodePen):
JS:
const action_data = [
{create_date : "2020-02-16T03:00:00Z", id:"test"},
{create_date : "2020-02-16T01:00:00Z", id:"test1"},
{create_date : "2020-02-14T03:00:00Z", id:"test2"},
{create_date : "2020-02-14T01:00:00Z", id:"test3"},
{create_date : "2020-02-14T00:00:01Z", id:"test4"},
{create_date : "2020-02-13T03:00:00Z", id:"test5"}
];
const Demo = (props) => {
console.log(props.action)
let groups = {}
for (let e of props.action.reverse()) {
let date = e.create_date.slice(0, 10)
if (groups[date]) {
let group = groups[date];
group.push({ index: group.length + 1, ...e });
} else {
groups[date] = [{ index: 1, ...e }]
}
}
const dates = Object.keys(groups).reverse()
const flatten = []
for (let date of dates) {
flatten.push(...(groups[date].reverse()))
}
const user_list = flatten.sort((a,b) => {
if (moment(b.create_date).diff(moment(a.create_date), 'days') == 0){
return (b.index - a.index);
} else {
return 0;
}
});
console.log(user_list);
return(
<div>
<table>
<thead>
<tr>
<th scope="col">Index</th>
<th scope="col">create_time</th>
<th scope="col">id/name</th>
</tr>
</thead>
<tbody>
{user_list.length > 0 && user_list.map((item, index) => (
<tr key={item.id.toString()}>
<td>{item.index}</td>
<td className={'datetime'}>
{item.hasOwnProperty('create_date') &&
<div>
{moment(item.create_date).format('YYYY-MM-DD') + " "+ moment(item.create_date).format('HH:mm')}
</div>
}
</td>
<td scope="row">
{item.id}
</td>
</tr>
))}
</tbody>
</table>
</div>
)
}
ReactDOM.render(
<Demo action={action_data}/>,
document.getElementById('root')
);
Important is the sort function:
const user_list = flatten.sort((a,b) => {
if (moment(b.create_date).diff(moment(a.create_date), 'days') == 0){
return (b.index - a.index);
} else {
return 0;
}
});
If the dates are not the same day, then don't sort, but if they are the same day then sort on the "index" created in the flatten array earlier.
Again demo here: https://codepen.io/Alexander9111/pen/rNVeyyY