Antd tree table grouped by column value - reactjs

I need to implement tree table in my react application. that has grouped by an object property value.
The object is as follows
{
"SP": [
{
"DisplayName": "audi",
"Name": "r8",
"Type": "2012"
},
{
"DisplayName": "audi",
"Name": "rs5",
"Type": "2013"
}
],
"Code": [
{
"DisplayName": "ford",
"Name": "mustang",
"Type": "2012"
},
{
"DisplayName": "ford",
"Name": "fusion",
"Type": "2015"
}
],
"Message": [
{
"DisplayName": "kia",
"Name": "optima",
"Type": "2012"
}
]
}
And my table should be as the following image
I have used antd in my project and I tried to implement this functionality with antd table and could not implement as I want. I need the filter functionality too.
Can anyone suggest a solution

You need to restructure your dataSource witch children prop:
function NestedTables() {
return (
<Flexbox>
<Table
size="small"
indentSize={0}
columns={columns}
dataSource={source}
/>
</Flexbox>
);
}
When your source is:
const source = [
{
key: '1',
Code: 'SP',
children: [
{
key: '11',
Code: '5001',
DisplayName: 'audi',
Name: 'r8',
Type: '2012'
},
{
key: '12',
Code: '313',
DisplayName: 'audi',
Name: 'rs5',
Type: '2013'
}
]
},
{
key: '2',
Code: 'Code',
children: [
{
key: '21',
Code: '243',
DisplayName: 'ford',
Name: 'mustang',
Type: '2012'
},
{
key: '22',
Code: '503431',
DisplayName: 'ford',
Name: 'fusion',
Type: '2015'
}
]
},
{
key: '3',
Code: 'Message',
children: [
{
key: '31',
Code: '4311',
DisplayName: 'kia',
Name: 'optima',
Type: '2012'
}
]
}
];
And defined columns filters:
const columns = [
{
title: 'Code',
dataIndex: 'Code',
key: 'Code',
filters: [
{ text: 'SP', value: 'SP' },
{ text: 'Code', value: 'Code' },
{ text: 'Message', value: 'Message' }
],
onFilter: (value, record) => record.Code.indexOf(value) === 0
},
{
title: 'Display Name',
dataIndex: 'DisplayName',
key: 'DisplayName',
filters: [
{ text: 'audi', value: 'audi' },
{ text: 'ford', value: 'ford' },
{ text: 'kia', value: 'kia' }
],
onFilter: (value, record) =>
record.children.filter(child => child.DisplayName === value).length > 0
},
{ title: 'Name', dataIndex: 'Name', key: 'Name' },
{ title: 'Type', dataIndex: 'Type', key: 'Type' }
];
Demo:

Related

How to return the object if no value found otherwise do some looping with condition and return object using react and typescript?

Hi i have an array of objects like below,
const arr_obj = [
{
id: '1',
jobs: [
{
completed: false,
id: '11',
run: {
id: '6',
type: 'type1',
},
},
{
completed: true,
id: '14',
run: {
id: '17',
type: 'type1',
},
},
{
completed: false,
id: '12',
run: {
id: '7',
type: 'type2',
},
},
],
},
{
id: '2',
jobs: [
{
completed: true,
id: '13',
run: {
id: '8',
type: 'type2',
},
},
{
completed: true,
id: '16',
run: {
id: '9',
type: 'type1',
},
},
{
completed: true,
id: '61',
run: {
id: '19',
type: 'type1',
},
},
],
},
{
id: '3',
jobs: [
{
completed: false,
id:'111',
run: {
id: '62',
type: 'type1',
},
},
],
},
],
Now i have to get ids from arr_obj which matches this arr of ids
const arr_ids = ["1","2"]
and whose runs are of type "type1" and none of the jobs have completed: false
so the expected output is "2"
the below code works,
const filtered_arr_obj = arr_obj.filter(obj => {
if (arr_ids.includes(obj.id)) {
const jobs = obj.jobs.filter(job => job.run.type === "type1");
if (jobs.length > 0) {
return jobs.every(job => job.completed === true);
}
return false;
}
return false;
});
let filtered_ids = filtered_arr_obj.map(obj => obj.id);
console.log("filteredIds", filteredIds) //2
Now the problem is if there are no run and run of type "type" for job then i want to also filter the object which has no job run of type "type1"
so consider below example
const arr_obj = [
{
id: '1',
jobs: [
{
completed: false,
id: '11',
run: {
id: '6',
type: 'type1',
},
},
{
completed: true,
id: '14',
run: {
id: '17',
type: 'type1',
},
},
{
completed: false,
id: '12',
run: {
id: '7',
type: 'type2',
},
},
],
},
{
id: '2',
jobs: [
{
completed: true,
id: '13',
run: {
id: '8',
type: 'type2',
},
},
{
completed: true,
id: '16',
run: {
id: '9',
type: 'type1',
},
},
],
},
{
id: '3',
jobs: [
{
completed: false,
id: '111',
run: {
id: '62',
type: 'type1',
},
},
],
},
{
id: '4',
jobs: [
{
completed: true,
id: '121',
run: {
id: '66',
type: 'type2',
},
},
],
},
],
and
arr_ids = ["1", "2", "4"]
so the expected output is
["2", "4"]
here 4 is also selected because arr_ids has "4" and the object in arr_obj with id "4" has no job run with type "type1".
how can I modify the above code snippet to also include this condition? could someone help me with this? thanks.
I am new to programming and please do answer the question.
It Looks like when the id is present in the arr_ids and if the jobs length is <= 1 then we should filter it , else we are filtering the type1 jobs and checking whether all are completed .
const arr_obj = [
{
id: '1',
jobs: [
{
completed: false,
id: '11',
run: {
id: '6',
type: 'type1',
},
},
{
completed: true,
id: '14',
run: {
id: '17',
type: 'type1',
},
},
{
completed: false,
id: '12',
run: {
id: '7',
type: 'type2',
},
},
],
},
{
id: '2',
jobs: [
{
completed: true,
id: '13',
run: {
id: '8',
type: 'type2',
},
},
{
completed: true,
id: '16',
run: {
id: '9',
type: 'type1',
},
},
{
completed: true,
id: '61',
run: {
id: '19',
type: 'type1',
},
},
],
},
{
id: '3',
jobs: [
{
completed: false,
id:'111',
run: {
id: '62',
type: 'type1',
},
},
],
},
{
id: '4',
jobs: [
{
completed: true,
id: '121',
run: {
id: '66',
type: 'type2',
},
},
],
},
];
const arr_ids = ["1", "2", "4"];
const filtered_arr_obj = arr_obj.filter(obj => {
if (arr_ids.includes(obj.id)) {
if(obj.jobs.length <= 1 ){
return true;
}
else {
const type1jobs = obj.jobs.filter(job => job.run.type === "type1");
return type1jobs.every(job => job.completed );
}
}
return false;
});
let filtered_ids = filtered_arr_obj.map(obj => obj.id);
console.log("filteredIds", filtered_ids)

Access Array from Property in Nested Object

I have the following nested object:
export const mockData = {
sections: [
{
name: 'Client',
subSections: [
{
name: 'Client Detail'
}
]
},
{
name: 'Sales',
subSections: [
{
name: 'Overview',
subSections: [
{
name: 'Overview - A',
fields: [
{
key: 'firmName',
type: 'input',
templateOptions: {
label: 'Firm Name',
required: true
}
},
{
key: 'requestOption',
type: 'select',
templateOptions: {
label: 'Request Option',
required: true,
options: [
{ value: '1', label: '1' },
{ value: '2', label: '2' },
{ value: '3', label: '3' },
{ value: '4', label: '4' }
]
}
},
{
key: 'region',
type: 'select',
templateOptions: {
label: 'Region',
required: true,
options: [
{ value: '1', label: '1' },
{ value: '2', label: '2' },
{ value: '3', label: '3' },
{ value: '4', label: '4' },
{ value: '5', label: '5' }
]
}
}
]
}
]
}
]
}
]
};
and I would like to access the array from the fields property in order to render a form. Right now what I have is overviewA: FormlyFieldConfig[] = mockData.sections[1].subSections[0].subSections[0].fields, but I am facing the error of
Property 'subSections' does not exist on type '{ name: string; }'.
However, this error goes away when do a work-around and I add the property subSections to the nested object like so:
export const mockData = {
sections: [
{
name: 'Client',
subSections: [
{
name: 'Client Detail',
subSections: []
}
]
},
{
name: 'Sales',
subSections: [
{
name: 'Overview',
subSections: [
{
name: 'Overview - A', ...
I was wondering why
I was facing the issue without the work-around, and
How can I access the array from the property fields without the work-around?

How to format a cell in react material-ui DataGrid

I have a react material-ui DataGrid.
One of the cells shows text data representing status, which I want to show in a graphical way - specifically bootstrap badge.
The DataGrid code is:
const ProcessesColumns: ColDef[] = [
{ field: 'id', headerName: 'ID' },
{ field: 'name', headerName: 'Name', width: 300 },
{ field: 'status', headerName: 'Status', width: 130 },
];
const processes = [
{
id: 1,
name: 'aaa',
status: 'Sucess',
},
{
id: 2,
name: 'bbb',
status: 'Fail',
},
{
id: 3,
name: 'ccc',
status: 'Sucess',
},
{
id: 4,
name: 'ddd',
status: 'Success',
},
{
id: 5,
name: 'eee',
status: 'Sucess',
},
{
id: 6,
name: 'fff',
status: 'Fail',
},
]
<DataGrid rows={processes} columns={ProcessesColumns} pageSize={10} />
I think you should check this
You can add a renderCell attribute on your status column definition
I think you can do it with renderCell. Here's an example of something similar, and I hope it helps.
I have a column which cells I want to format to have an icon and a value, and I created that in a format function:
const priorityFormater = (cell) => {
return (
<span>
<GrStatusGoodSmall className={taskPriorityColor(cell)} />
<span className="priority-span">{cell}</span>
</span>
);
};
Column definition:
{
field: "priority",
headerName: "Priority",
flex: 0,
minWidth: 140,
renderCell: (params) => {
return priorityFormater(params.value);
},
},
Result:

Get the array of values from array of objects using lodash

I have this array
this.complementaryFields = [
{
fieldName: 'complementaryLaser',
label: 'Laser Hair Removal'
},
{
fieldName: 'complementarySkin',
label: 'Skin'
},
{
fieldName: 'complementaryInjection',
label: 'Cosmetic Injections'
},
{
fieldName: 'complementaryNotSure',
label: 'Not Sure'
}
];
and I would like to create a new array out of it as below:
this.complementaryFieldNames = [
'complementaryLaser',
'complementarySkin',
'complementaryInjection',
'complementaryNotSure'
];
How would you do it using lodash?
You can simply use lodash _.map to get that result:
const data = [{ fieldName: 'complementaryLaser', label: 'Laser Hair Removal' }, { fieldName: 'complementarySkin', label: 'Skin' }, { fieldName: 'complementaryInjection', label: 'Cosmetic Injections' }, { fieldName: 'complementaryNotSure', label: 'Not Sure' } ];
const result = _.map(data, 'fieldName')
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
With ES6 you can do same with Array.map and destructuring:
const data = [{ fieldName: 'complementaryLaser', label: 'Laser Hair Removal' }, { fieldName: 'complementarySkin', label: 'Skin' }, { fieldName: 'complementaryInjection', label: 'Cosmetic Injections' }, { fieldName: 'complementaryNotSure', label: 'Not Sure' } ];
const result = data.map(({fieldName}) => fieldName)
console.log(result)

Angularjs UI Grid Totals per Row inside the row

{{ HelloWorld }}
I'm trying to access the values from other columns in the same row in angular-ui-grid. I have two question that are related.
How can I add the values from several columns in the same row to get a Total?
How can I use the row index to pass it as a parameter and remove the current row?
As you can see in the above image, the Totals that I'm looking for are only related to the integer values and not the initial string.
Also the Button with an X should delete the row when clicked. The rows are included in the grid dynamically.
I've gone through the UI Grid Tutorial but the examples don't show how to accomplish either of my questions.
My footer is working fine. It's configure to give a total but by column in the entire set of rows:
Here's a little bit of my code with what I've found so far:
var removeTemplate = '<button type="button" class="grid-remove btn btn-default btn-sm"><span class="glyphicon glyphicon-remove" aria-hidden="true" ng-click="removeRow($event, row.entity)"></span></button>';
$scope.gridAccountableHours = {
enableCellEditOnFocus: true,
showColumnFooter: true
};
$scope.gridAccountableHours.columnDefs = [
{ name: "contractCode", displayName: ""},
{ name: "hours1", displayName: "1", type: "number" },
{ name: "hours2", displayName: "2", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours3", displayName: "3", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours4", displayName: "4", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours5", displayName: "5", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours6", displayName: "6", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours7", displayName: "7", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours8", displayName: "8", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours9", displayName: "9", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours10", displayName: "10", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours11", displayName: "11", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours12", displayName: "12", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours13", displayName: "13", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours14", displayName: "14", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours15", displayName: "15", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "total", displayName: "Total" },
{ name: "remove", displayName: "", cellTemplate: removeTemplate }
];
$scope.removeRow = function ($event, entity) {
$event.stopPropagation();
$scope.gridAccountableHours.data.splice($scope.gridAccountableHours.data.indexOf(entity), 1);
};
I appreciate your time.
Totalling across the grid you could do with a function on the gridRow.
$scope.gridAccountableHours.forEach(function(rowEntity) {
rowEntity.total = function() {
var total = 0;
for( var 1 = 1; i++; i<=15 ){
total += this['hours'+i];
}
};
});
Your total column def should automatically bind to this total function. Refer http://ui-grid.info/docs/#/tutorial/106_binding
For the delete button, you're missing the appScope, refer http://ui-grid.info/docs/#/tutorial/305_appScope
Your template ng-click should be:
ng-click="grid.appScope.removeRow($event, row.entity)"

Resources