How to add images in MaterialDatatable? - javascript

I'm using MaterialDatatable in react-app this is working fine but now I want to add country icons with country names so how can I add images with table value?
My Code:-
<MaterialDatatable
columns={headers}
data={items}
options={options}
/>
items is coming from below list:-
export function getHeaders() { return [
{
name: 'Username',
field: 'username',
type: 'string'
},
{
name: 'Country',
field: 'countryName',
type: 'string',
className: 'lftAlign',
},
{
name: 'Name',
field: 'fullName',
type: 'string'
}] }
Package Link:-
https://www.npmjs.com/package/material-datatable
Countries flag images will be come from below array:-
const countries = [
{
value: '1',
title: 'Afghanistan',
icon: '/flags/afghanistan.png'
},
{
value: '2',
title: 'Albania',
icon: '/flags/albania.png'
}
]

You can use customValue for that purpose:
See: https://github.com/Diaver/material-datatable
There is a sandbox example at https://codesandbox.io/s/lp8pvk1zk9?file=/index.js:0-1728:
import React from "react";
import ReactDOM from "react-dom";
import MaterialDatatable from "material-datatable";
class App extends React.Component {
render() {
const columns = [
{ name: "Name", field: "name" },
{ name: "Title", field: "title" },
{ name: "Location", field: "location" },
{ name: "Age", field: "age" },
{ name: "Salary", field: "salary" },
{
name: "Name and Title Custom Column",
field: "salary",
options: {
noHeaderWrap: true,
width: 200,
customBodyRender: (value, tableMeta, updateValue) => {
return `${value.name} (${value.title})`;
}
}
},
{
name: "Custom Render",
field: "salary2",
options: {
noHeaderWrap: true,
width: 200,
customBodyRender: (value, tableMeta, updateValue) => {
return <h4>{value.name}</h4>;
},
customValue: (value, tableMeta, updateValue) => value.name,
customSortValue: (value, tableMeta, updateValue) => value.name
}
}
];
const data = [
{
name: "Name 1",
title: "Title 1",
location: "Location 1",
age: 30,
salary: 10
},
{
name: "Name 2",
title: "Title 2",
location: "Location 2",
age: 31,
salary: 11
}
];
const options = {
filterType: "dropdown",
responsive: "scroll"
};
return (
<MaterialDatatable
title={"ACME Employee list"}
data={data}
columns={columns}
options={options}
/>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
Note that the relevant part is
{
name: "Custom Render",
field: "salary2",
options: {
noHeaderWrap: true,
width: 200,
customBodyRender: (value, tableMeta, updateValue) => {
return <h4>{value.name}</h4>;
},
customValue: (value, tableMeta, updateValue) => value.name,
customSortValue: (value, tableMeta, updateValue) => value.name
}
}
Note that we have a customValue as
customValue: (value, tableMeta, updateValue) => value.name,
You could have something like
customValue: (value, tableMeta, updateValue) => value.icon,
Yes, I know, this only displays the relative path. But, instead of that, you can change this to return something like
`<img src="${value.icon}">`
the above is just a dummy example. You can replace it with a more React-like code and you can even put there some components.

Related

generate tree-like structure using dot-separated string

I struggle with tree structure. :(
I would like to make a tree following the below interface.
export type Tree = Array<TreeNode>;
export interface TreeNode {
label: string;
type: 'folder' | 'file';
children: Array<TreeNode> | string;
}
For example,
I have a JSON file like this
{
"common.header.title": "Header Title",
"common.footer.btn": "Footer button",
"common.footer.btn.submit": "Footer Submit",
"apage.title": "apage Title"
}
My expected output is like this.
const out = [
{
label: 'apage',
type: 'folder',
children: [
{ label: 'title', type: 'file', children: 'apage Title' }
]
}, {
label: 'common',
type: 'folder',
children: [
{
label: 'footer',
type: 'folder',
children: [
{ label: 'btn', type: 'file', children: 'Footer button' },
{
label: 'btn',
type: 'folder',
children: [{ label: 'submit', type: 'file', children: 'Footer Submit' }]
},
]
}, {
label: 'header',
type: 'folder',
children: [{ label: 'title', type: 'file', children: 'Header Title' }]
}
]
}
]
I've seen some similar cases in SO, but I couldn't refer and develop with that cases.
You could search for the wanted labels and check if children is an array, then use this object for searchin in the nested array.
Finally push a new object.
const
data = { "common.header.title": "Header Title", "common.footer.btn": "Footer button", "common.footer.btn.submit": "Footer Submit", "apage.title": "apage Title" },
result = Object
.entries(data)
.sort(([a], [b]) => a.localeCompare(b))
.reduce((r, [path, children]) => {
const
keys = path.split('.'),
label = keys.pop();
keys
.reduce((t, label) => {
let temp = t.find(o => o.label === label && Array.isArray(o.children));
if (!temp) t.push(temp = { label, type: 'folder', children: [] });
return temp.children;
}, r)
.push({ label, type: 'file', children });
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Antd Tree, : how to Disable checking child by default

I working on a react project using Antd and I want to be able to disable cheking childs of my Tree component, so I can check only parent.This is my code
I found that I can add checkable : false to my child but I must create a function that render me a new TreeData that I can use instead of my normal data so I've tried this :
const TreeData = (data) => {
data.map((category) => {
category.children.map((family) => {
family.children.map((table) => {
table.checkable = false;
});
});
});
};
But it return undefined when i'm console.log the data received..
So my question is : how to switch from this :
const treeData = [
{
title: "0-0",
key: "0-0",
children: [
{
title: "0-0-0",
key: "0-0-0",
children: [
{
title: "0-0-0-0",
key: "0-0-0-0"
},
{
title: "0-0-0-1",
key: "0-0-0-1"
},
{
title: "0-0-0-2",
key: "0-0-0-2"
}
]
},
{
title: "0-0-1",
key: "0-0-1",
children: [
{
title: "0-0-1-0",
key: "0-0-1-0"
},
{
title: "0-0-1-1",
key: "0-0-1-1"
},
{
title: "0-0-1-2",
key: "0-0-1-2"
}
]
},
{
title: "0-0-2",
key: "0-0-2"
}
]
},
{
title: "0-1",
key: "0-1",
children: [
{
title: "0-1-0-0",
key: "0-1-0-0"
},
{
title: "0-1-0-1",
key: "0-1-0-1"
},
{
title: "0-1-0-2",
key: "0-1-0-2"
}
]
},
{
title: "0-2",
key: "0-2"
}
];
To this :
const treeData = [
{
title: "0-0",
key: "0-0",
children: [
{
checkable: false,
title: "0-0-0",
key: "0-0-0",
children: [
{
title: "0-0-0-0",
key: "0-0-0-0"
},
{
title: "0-0-0-1",
key: "0-0-0-1"
},
{
title: "0-0-0-2",
key: "0-0-0-2"
}
]
},
{
checkable: false,
title: "0-0-1",
key: "0-0-1",
children: [
{
title: "0-0-1-0",
key: "0-0-1-0"
},
{
title: "0-0-1-1",
key: "0-0-1-1"
},
{
title: "0-0-1-2",
key: "0-0-1-2"
}
]
},
{
checkable: false,
title: "0-0-2",
key: "0-0-2"
}
]
},
{
title: "0-1",
key: "0-1",
children: [
{
checkable: false,
title: "0-1-0-0",
key: "0-1-0-0"
},
{
checkable: false,
title: "0-1-0-1",
key: "0-1-0-1"
},
{
checkable: false,
title: "0-1-0-2",
key: "0-1-0-2"
}
]
},
{
title: "0-2",
key: "0-2"
}
];
Without hardchanging the first data of my Tree.
Thank you
This may be one possible implementation to set checkable as false for the specific nodes described in this question:
const makeUnCheckable = dataArr => (
dataArr.map(
obj => ({
...obj,
children: obj?.children?.map(cObj => ({
...cObj,
checkable: false
}))
})
)
);
return (
<Tree
checkable
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
onCheck={onCheck}
checkedKeys={checkedKeys}
onSelect={onSelect}
selectedKeys={selectedKeys}
treeData={makeUnCheckable(treeData)}
/>
);
This is the result displayed on Codesandbox:
NOTES:
The elements showing as checked are clicked manually.
There is no check option for nodes 0-0-0, 0-0-1, 0-0-2, 0-1-0-0, 0-1-0-1, 0-1-0-2 - which is the expected objective defined in the question under To this
EDITED:
On perusing this previous question it seems like OP requires something like this:
(A tree where leaf nodes are uncheckable)
This may be achieved by a recursive method - something like this:
(Changes are present in: Lines 100 to 106. And line 118.)
EDITED - 2
Update based on comments below.
In order to identify the children for any given parent/key, something like the below may be useful:
Two methods are here. One is findKey which is recursive and gets the object which has a particular key (say 0-0-1). The other is to check if the object with the key has any children and if yes, return the children array.

How to get and link nested value to field passing columns to Material Table

I'm trying to create a table and I have nested data like this:
[{
id: 24,
name: "DANIEL TSUTOMU OBARA",
number: "134",
phone: "11111111111",
rg: "4034092666",
EmployeeStatus: {
createdAt: "2019-08-07T14:38:52.576Z"
description: "Documentos rejeitados"
id: 3
updatedAt: "2019-08-07T14:38:52.576Z"
},
Sector: {
id: 2,
name: "Controladoria"
}
}]
And have this structure columns table:
columns: [
{ title: "Nome", field: "name" },
{ title: "CPF", field: "cpf" },
{ title: "Função", field: "FunctionId", lookup: {} },
{
title: "Setor",
field: "SectorId",
lookup: {}
},
{
title: "Status",
field: "EmployeeStatus", <------- I want to get description here
editable: "never"
}
],
Then, I need to pass these columns into my Material-table like this:
<MaterialTable
columns={state.columns}
data={state.data}
title=""
icons={tableIcons}
editable={{
onRowAdd: newData => createInstructor(newData),
onRowUpdate: async (newData, oldData) =>
updateInstructor(newData, oldData),
onRowDelete: oldData => deleteInstructor(oldData)
}}
/>
So, how I can do that access nested data into column field?
Thanks!
Please find the below solution.
I am expecting the data to have other objects too, so finding the first object with the key available.
let data = [{
id: 24,
name: "DANIEL TSUTOMU OBARA",
number: "134",
phone: "11111111111",
rg: "4034092666",
EmployeeStatus: {
createdAt: "2019-08-07T14:38:52.576Z",
description: "Documentos rejeitados",
id: 3,
updatedAt: "2019-08-07T14:38:52.576Z"
},
Sector: {
id: 2,
name: "Controladoria"
}
}]
let columns = [
{ title: "Nome", field: "name" },
{ title: "CPF", field: "cpf" },
{ title: "Função", field: "FunctionId", lookup: {} },
{
title: "Setor",
field: "SectorId",
lookup: {}
},
{
title: "Status",
field: "EmployeeStatus",
editable: "never"
}
];
let columnToUpdate = columns.find(obj => obj.title==="Status"); //find the column in columns array
let desc = data.find(obj => Object.keys(obj).includes('EmployeeStatus')).EmployeeStatus.description; // get description
columnToUpdate.field = desc; // mutate the object
console.log(columns);
I just decided to use lookup functionality and solve in this way for now.
const [state, setState] = useState({
columns: [
{ title: "ID", field: "id", editable: "never" },
{ title: "Nome", field: "name" },
{ title: "CPF", field: "cpf" },
{ title: "Função", field: "FunctionId", lookup: {} }, // 3
{
title: "Setor",
field: "SectorId",
lookup: {}
}, // 4
{
title: "Status",
field: "EmployeeStatusId",
lookup: {},
editable: "never"
}, // 5
]});
....
await api
.get(`/employee-status`)
.then(result => {
status = formatSectors(state, result, 5);
})
.....
const formatSectors = (state, result, position) => {
let columns = state.columns;
const indexColumnSector = 4;
columns[position].lookup = result.data.rows.reduce(
(accumulator, currentValue) => {
accumulator[currentValue.id] =
position === indexColumnSector
? currentValue.name
: currentValue.description;
return accumulator;
},
{}
);
return columns;
};

Cannot read property 'indexOf' of undefined - react-sortable-hoc

I'm trying to get the structure below.
https://imgur.com/NBRGlhM
Three columns, with titles, and column cards that can be moved within only one column. this.state.item ['lists'] moving to the component SortableList. Then iterates after items.map ((item, index) => and moves to the component SortableItem. Then iterates aftervalue.listItems and wants to display the title of columns and cards in the column. I get the error:
Cannot read property ' indexOf 'of undefined
Demo here: https://stackblitz.com/edit/react-jpszoq
import {SortableContainer, SortableElement} from 'react-sortable-hoc';
import arrayMove from 'array-move';
const SortableItem = SortableElement(({value}) => {
return(
value.listItems.map((it, index) => {
<li>{it.title}</li>
})
)
})
const SortableList = SortableContainer(({items}) => {
console.log(items)
return (
<ul>
{
items.map((item, index) =>
<div>{item.name}
<SortableItem key={`item-${item.id}`} index={index} value={item} />
</div>
)
}
</ul>
);
});
class App extends Component {
constructor() {
super();
this.state = {
item: {
id: "abc123",
name: "AAA",
lists: [
{
id: "def456",
list_id: "654wer",
title: 'List1',
desc: "description",
listItems: [
{
id: "ghj678",
title: "ListItems1",
listItemsId: "88abf1"
},
{
id: "poi098",
title: "ListItems2",
listItemsId: "2a49f25"
}
]
},
{
id: "1ef456",
list_id: "654wer",
title: 'List 2',
desc: "description",
listItems: [
{
id: "1hj678",
title: "ListItems3",
listItemsId: "18abf1"
},
{
id: "1oi098",
title: "ListItems4",
listItemsId: "1a49f25"
}
]
},
{
id: "2ef456",
title: 'List 3',
list_id: "254wer",
desc: "description",
listItems: [
{
id: "2hj678",
title: "ListItems5",
listItemsId: "28abf1"
},
{
id: "2oi098",
title: "ListItems6",
listItemsId: "234a49f25"
}
]
}
]
}
};
}
onSortEnd = ({oldIndex, newIndex}) => {
this.setState(({lists}) => ({
lists: arrayMove(lists, oldIndex, newIndex),
}));
};
render() {
return <SortableList items={this.state.item['lists']} onSortEnd={this.onSortEnd} />;
}
}
you're missing a return on L14 in the function passed to listItems.map. Alternatively, you could remove the braces.

Nativescript RadDataForm convert property not working with json array

I have json array with id and name property after submiting the form I am getting NaN I want to convert converter code from typescript to Javascript
I created a Playground example
file : Data.js
{ id: 123, name: 'Zootopia' },
{ id: 217, name: 'Captain America' },
{ id: 324, name: 'The Jungle Book' }
];
export class MovieConverter {
constructor(_movies) {
this._movies = _movies;
}
convertFrom(id) {
return this._movies.filter((movie) => movie.id === id)[0].name;
}
convertTo(name) {
return this._movies.filter((movie) => movie.name === name)[0].id;
}
}
Test.vue
<template>
<Page>
<ActionBar :title="Simple">
<NavigationButton text="Back" android.systemIcon="ic_menu_back"
#tap="onNavigationButtonTap"></NavigationButton>
</ActionBar>
<StackLayout>
<Button text="Button" #tap="onSubmit" />
<RadDataForm :source="ticket" :metadata="ticketMetadata" />
</StackLayout>
</Page>
</template>
<script>
import Home from "./Home";
import {
Movies,
MovieConverter
} from "../Data";
//const movies = getMovies();
export default {
methods: {
onNavigationButtonTap() {
this.$navigateTo(Home);
}
},
mounted() {
console.log("movies", Movies);
Movies.map(Movie => {
console.log(Movie.name);
});
},
data() {
return {
ticket: {
movie: 123,
date: "2016-04-06",
time: "20:00",
type: "2D",
price: 9.5,
numberOfTickets: 2,
contactName: null,
contactPhone: null,
contactEmail: null,
agreeTerms: false
},
ticketMetadata: {
isReadOnly: false,
commitMode: "Immediate",
validationMode: "Immediate",
propertyAnnotations: [{
name: "movie",
displayName: "Movie Name",
index: 0,
editor: "Picker",
valuesProvider: Movies.map(Movie => Movie.name),
converter: new MovieConverter(Movies)
},
{
name: "date",
displayName: "Date",
index: 1,
editor: "DatePicker",
hintText: "This is a hint for you"
},
{
name: "time",
displayName: "Time",
index: 2,
editor: "TimePicker"
},
{
name: "type",
displayName: "Type",
index: 3,
editor: "SegmentedEditor",
valuesProvider: ["2D", "3D"]
},
{
name: "price",
displayName: "Price",
index: 4,
editor: "Decimal",
readOnly: true
},
{
name: "numberOfTickets",
displayName: "Number Of Tickets",
index: 5,
editor: "Stepper",
editorParams: {
minimum: 0,
maximum: 20,
step: 2
}
},
{
name: "contactName",
displayName: "Contact Name",
index: 6,
editor: "Text"
},
{
name: "contactPhone",
displayName: "Contact Phone",
index: 7,
editor: "Phone"
},
{
name: "contactEmail",
displayName: "Contact Email",
index: 8,
editor: "Email"
},
{
name: "agreeTerms",
displayName: "I Agree with Terms",
index: 9,
editor: "Switch"
}
]
}
};
},
methods: {
onSubmit() {
console.log("submit", this.ticket.movie);
}
}
};
</script>
<style>
</style>
after onSubmit() of the form I should get 'submit' 123
but getting 'submit' NaN.
I check out the documentation of converter it showing a class with 2 methods convertFrom() & convertTo() which I think is proper not understand as all the documentation is in typescript and I am using javascript.

Categories

Resources