i have a question, i want to add this command line:
Cell: ({ row }) => <a href={row.original.lastName}>{row.original.lastName}</a>
into 'lastName',using hook in reactjs, for example:
Before:
const [columns, setColumns] = useState(
[
{
id:'firstName',
Header: 'First Name',
accessor: 'firstName',
},
{
Header: 'Last Name',
accessor: 'lastName',
},
]
);
setColumns(???)
Result:
[
{
id:'firstName',
Header: 'First Name',
accessor: 'firstName',
},
{
Header: 'Last Name',
accessor: 'lastName',
Cell: ({ row }) => <a href={row.original.lastName}>{row.original.lastName}</a>
},
]
Best regards
Giuseppe
Please find a small working solution as below. Please feel free to replace the button click with your side effect which can be an API call or any action side effect. Just for simplicity, I have used a button.
import React, { useState } from "react";
import ReactDOM from "react-dom";
const Row = ({ row }) => (
<a href={row.original.lastName}>{row.original.lastName}</a>
);
function App() {
const [columns, setColumns] = useState([
{
id: "firstName",
Header: "First Name",
accessor: "firstName"
},
{
Header: "Last Name",
accessor: "lastName"
}
]);
const createRowsForLastName = () => {
const replaceColumnForLastName = columns.map(column => {
if (column.accessor === "lastName") {
return {
...column,
Cell: <Row row={{ original: { lastName: "some name" } }} />
};
}
return { ...column };
});
setColumns(replaceColumnForLastName);
};
console.log(columns);
return (
<div className="App">
<button onClick={createRowsForLastName}>Create Row!</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Related
Pretty new with AG Grid library and stuck on updating the cells.
In reality, I need to do the task with dates, but just to keep it simple, I'll explain my problem with simple numbers.
I have
Start, which is 1.
Stop, which is already defined
End
Duration, which is already defined
My goal
Start = Duration + End
End = Start + Stop
Here is what I have so far
Desired result
Sandbox Link and code below
import React from "react";
import { AgGridReact } from "ag-grid-react";
import "./styles.css";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine.css";
function App() {
const start = 1;
const [gridApi, setGridApi] = React.useState(null);
const [gridColumnApi, setGridColumnApi] = React.useState(null);
const columnDefs = [
{
headerName: "Name",
field: "name"
//valueGetter: (params) => console.log(params)
},
{
headerName: "start",
field: "start",
valueGetter: (params) => {
if (params.node.rowIndex !== 0) {
return params.getValue("end") + params.data.duration;
} else {
return start;
}
}
},
{ headerName: "stop", field: "stop" },
{
headerName: "end",
colId: "end",
valueGetter: (params) => {
return params.data.start + params.data.stop;
}
},
{
headerName: "duration",
field: "duration",
colId: "duration"
}
];
const rowData = React.useMemo(
() => [
{
name: "John",
stop: 10
},
{
name: "David",
stop: 15
},
{
name: "Dan",
stop: 20
}
],
[]
);
const durationArray = [5, 8, 6];
const rowDataWithStart = React.useMemo(() => {
if (durationArray) {
return (
rowData &&
rowData.map((row, i) => ({
...row,
start: start,
duration: durationArray[i]
}))
);
}
}, [start, rowData, durationArray]);
const defaultColDef = {
flex: 1,
editable: true
};
const onGridReady = (params) => {
setGridApi(params.api);
setGridColumnApi(params.columnApi);
};
return (
<div className="App">
<h1 align="center">React-App</h1>
<div className="ag-theme-alpine">
<AgGridReact
columnDefs={columnDefs}
rowData={rowDataWithStart}
defaultColDef={defaultColDef}
domLayout={"autoHeight"}
onGridReady={onGridReady}
></AgGridReact>
</div>
</div>
);
}
export default App;
Any help will be appreciated
you can use valueGetter for this. I have modified the valueGetter in you code
const columnDefs = [
{
headerName: "Name",
field: "name"
//valueGetter: (params) => console.log(params)
},
{
field: "start",
valueGetter: ({ data }) => {
const end = data.stop + data.start
return data.duration + end;
}
},
{ field: "stop" },
{
field: "end",
valueGetter: ({ data }) => {
return data.start + data.stop
}
},
{
headerName: "duration",
field: "duration"
}
];
I tried to the material-table the library for basic crud operation. By using onRowAdd, onRowUpdate, onRowDelete, I get the icons for the same but I would like to know that how can I change the color of each of these three icons?
You can see my table has few icons and I am focusing on add, edit, delete icons I want to change color of these icons.
Here is the link to my codesandbox.
App.js file
import React, { useState } from 'react';
import './App.css';
import MaterialTable from 'material-table'
const empList = [
{ id: 1, name: "Neeraj", email: 'neeraj#gmail.com', phone: 9876543210, city: "Bangalore" },
{ id: 2, name: "Raj", email: 'raj#gmail.com', phone: 9812345678, city: "Chennai" },
{ id: 3, name: "David", email: 'david342#gmail.com', phone: 7896536289, city: "Jaipur" },
{ id: 4, name: "Vikas", email: 'vikas75#gmail.com', phone: 9087654321, city: "Hyderabad" },
]
function App() {
const [data, setData] = useState(empList)
const columns = [
{ title: "ID", field: "id", editable: false },
{ title: "Name", field: "name" },
{ title: "Email", field: "email" },
{ title: "Phone Number", field: 'phone', },
{ title: "City", field: "city", }
]
return (
<div className="App">
<h1 align="center">React-App</h1>
<h4 align='center'>Material Table with CRUD operation</h4>
<MaterialTable
title="Employee Data"
data={data}
columns={columns}
editable={{
onRowAdd: (newRow) => new Promise((resolve, reject) => {
const updatedRows = [...data, { id: Math.floor(Math.random() * 100), ...newRow }]
setTimeout(() => {
setData(updatedRows)
resolve()
}, 2000)
}),
onRowDelete: selectedRow => new Promise((resolve, reject) => {
const index = selectedRow.tableData.id;
const updatedRows = [...data]
updatedRows.splice(index, 1)
setTimeout(() => {
setData(updatedRows)
resolve()
}, 2000)
}),
onRowUpdate:(updatedRow,oldRow)=>new Promise((resolve,reject)=>{
const index=oldRow.tableData.id;
const updatedRows=[...data]
updatedRows[index]=updatedRow
setTimeout(() => {
setData(updatedRows)
resolve()
}, 2000)
})
}}
options={{
actionsColumnIndex: -1, addRowPosition: "first"
}}
/>
</div>
);
}
export default App;
You can override the icons and provide custom styles by setting the icons props. It accepts an object where the key is a type of operation (Add, Edit, Delete,...) and the value is an icon component. For reference, see the all-props section here.
<MaterialTable
{...props}
icons={{
Edit: () => <EditIcon style={{ color: "orange" }} />,
Delete: () => <DeleteIcon style={{ color: "red" }} />
}}
>
Live Demo
It's Simple. Inspect on the page and Select the Icon and Copy its style Name in Styles Tab.
Now, Go to App.css file and Create New Style with the icon style name shown on Inspect-styles area and there you can enter your desired color.
It will work.
In your App.css File,
Add below code
.MuiIconButton-colorInherit {
color: red;
}
change to any color
I am working with antd table and antd transfer component and I am facing a small challenge with CSS.
I have created a small example with codesandbox. If I try to expand a row, you will see that other columns try to adjust themselves. Is there a way I could prevent this? I do not want the rows to adjust themselves. The table should feel the same after the expansion as it was before the expansion.
This is code from the sandbox link I shared above that generates the table.
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Transfer, Table, Tag } from "antd";
function difference(listOne, listTwo) {
const set1 = new Set(listOne);
const set2 = new Set(listTwo);
const difference = new Set([...set1].filter(x => !set2.has(x)));
return Array.from(difference);
}
// Customize Table Transfer
const TableTransfer = ({ leftColumns, rightColumns, ...restProps }) => (
<Transfer {...restProps}>
{({
direction,
filteredItems,
onItemSelectAll,
onItemSelect,
selectedKeys: listSelectedKeys,
disabled: listDisabled
}) => {
const columns = direction === "left" ? leftColumns : rightColumns;
const rowSelection = {
getCheckboxProps: item => ({ disabled: listDisabled || item.disabled }),
onSelectAll(selected, selectedRows) {
const treeSelectedKeys = selectedRows
.filter(item => !item.disabled)
.map(({ key }) => key);
const diffKeys = selected
? difference(treeSelectedKeys, listSelectedKeys)
: difference(listSelectedKeys, treeSelectedKeys);
onItemSelectAll(diffKeys, selected);
},
onSelect({ key }, selected) {
onItemSelect(key, selected);
},
selectedRowKeys: listSelectedKeys
};
return (
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={filteredItems}
size="small"
/>
);
}}
</Transfer>
);
const mockTags = ["eg", "gg", "e"];
const mockData = [];
for (let i = 0; i < 20; i++) {
let data = {
key: i.toString(),
title: `eq${i + 1}`,
description: `description of eq${i + 1}`,
disabled: false, //i % 4 === 0,
tag: mockTags[i % 3]
};
if (i % 2 === 0) {
const children = [
{
key: i.toString() + "children",
title: `children-${i + 1}`,
description: `children description-${i + 1}`,
disabled: true,
tag: "tag"
}
];
data["children"] = children;
}
mockData.push(data);
}
const originTargetKeys = mockData
.filter(item => +item.key % 3 > 1)
.map(item => item.key);
const leftTableColumns = [
{
dataIndex: "title",
title: "Name"
},
{
dataIndex: "tag",
title: "Tag",
render: tag => <Tag>{tag}</Tag>
},
{
dataIndex: "description",
title: "Description"
}
];
const rightTableColumns = [
{
dataIndex: "title",
title: "Names"
},
{
dataIndex: "tag",
title: "Tag",
render: tag => <Tag>{tag}</Tag>
},
{
dataIndex: "description",
title: "Description"
}
];
class App extends React.Component {
state = {
targetKeys: originTargetKeys
};
onChange = nextTargetKeys => {
this.setState({ targetKeys: nextTargetKeys });
};
render() {
const { targetKeys, disabled } = this.state;
return (
<div>
<TableTransfer
className="table-transfer"
dataSource={mockData}
titles={[
<div>
<input type="checkbox" checked />
Equipment <input type="checkbox" checked /> Groups
</div>,
<div>
<input type="checkbox" checked />
Equipment <input type="checkbox" checked /> Groups
</div>
]}
targetKeys={targetKeys}
disabled={disabled}
showSearch={true}
onChange={this.onChange}
filterOption={(inputValue, item) =>
item.title.indexOf(inputValue) !== -1 ||
item.tag.indexOf(inputValue) !== -1
}
leftColumns={leftTableColumns}
rightColumns={rightTableColumns}
locale={{
itemUnit: "Equipment",
itemsUnit: "Equipments",
notFoundContent: "The list is empty",
searchPlaceholder: "Search here"
}}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
You want to constraint your columns width, for example, try this on the leftTableColumns and notice the difference with the right one:
const leftTableColumns = [
{
dataIndex: 'title',
title: 'Name',
width: '45%'
},
{
dataIndex: 'tag',
title: 'Tag',
render: tag => <Tag>{tag}</Tag>,
width: '10%'
},
{
dataIndex: 'description',
title: 'Description',
width: '40%'
}
];
Refer to Table Column API.
Fork of your codebox:
I am trying to render some data in a react-table component however the data doesn't load. I have tested out with dummy data of the exact same format and it works fine. However when I make an API call and get data of the same format and push it to the list of data i'm passing to the react-table the table does not render it. Please help me identify the issue. Cheers
Setting up the columns:
columns: [
{
Header: "Employee ID",
accessor: "EmployeeID"
},
{
Header: "First Name",
accessor: "FirstName"
},
{
Header: "Last Name",
accessor: "LastName"
},
{
Header: "Date of Birth",
accessor: "DateOfBirth",
},
{
Header: "Status",
accessor: "Status",
},
{
Header: "Gender",
accessor: "Gender",
},
{
Header: "UpdatedDateUTC",
accessor: "UpdatedDateUTC",
}
]
What the data looks like:
{"EmployeeID":"63c571b3-bff0-4ce1-94f7-255c235580fa","FirstName":"Clive","LastName":"Thomas","Status":"ACTIVE","DateOfBirth":"/Date(697248000000+0000)/","Gender":"M","UpdatedDateUTC":"/Date(1533706298000+0000)/"}
My API call and how I'm saving the data item to state. (I console logged the value of the data I'm getting and it is in the correct format)
fetch('http://localhost:3100/employees')
.then((resp) => {
return resp.json()
})
.then((data) => {
let temp = this.state.posts;
temp.push(data.Employees[1])
this.setState({posts: temp})
console.log(this.state.posts)
})
.catch((error) => {
console.log(error, "catch the hoop")
})
The state and the 'posts' list storing the posts in state at bottom (with dummy data):
state = {
title: "Choose an Endpoint",
activeOrg: "Orginisation",
isExpanded: false,
activeLink: 0,
authLink:'',
response: '',
post: '',
responseToPost: '',
show: false,
modalContent:"",
token:'',
verifier:'',
org:'',
orginisations: [
{ id: 1, name: "ANU"},
{ id: 2, name: "Bar"},
{ id: 3, name: "FANG"},
{ id: 4, name: "Atlassian"}
],
list: [
{ id: 1, name: "Employees" },
{ id: 2, name: "Leave Applications" },
{ id: 3, name: "Pay Items" },
{ id: 4, name: "Payroll Calendars" },
{ id: 5, name: "Pay Runs" },
{ id: 6, name: "Pay Slips" },
{ id: 7, name: "Settings" },
{ id: 8, name: "Superfund Products" },
{ id: 9, name: "Timesheets" }
],
columns: [
{
Header: "Employee ID",
accessor: "EmployeeID"
},
{
Header: "First Name",
accessor: "FirstName"
},
{
Header: "Last Name",
accessor: "LastName"
},
{
Header: "Date of Birth",
accessor: "DateOfBirth",
},
{
Header: "Status",
accessor: "Status",
},
{
Header: "Gender",
accessor: "Gender",
},
{
Header: "UpdatedDateUTC",
accessor: "UpdatedDateUTC",
}
],
posts: [
{"EmployeeID":"63c571b3-bff0-4ce1-94f7-255c235580fa","FirstName":"Clive","LastName":"Thomas","Status":"ACTIVE","DateOfBirth":"/Date(697248000000+0000)/","Gender":"M","UpdatedDateUTC":"/Date(1533706298000+0000)/"}
]
}
Render function:
render() {
let myClass=""
let EndpointList = (
<div>
{this.state.list.map((i) => {
i.id === this.state.activeLink ? myClass="endpoint activeLink" : myClass="endpoint"
return <Endpoint
key={i.id}
name={i.name}
myClass={myClass}
clicked={(event) => this.handleClickEndpoint(i, i.id)}/>
})}
</div>
);
let orgContainer = ""
this.state.isExpanded ? orgContainer="orgItem expanded" : orgContainer="orgItem notExpanded"
let OrgList = (
<div className={orgContainer}>
{this.state.orginisations.map((o) => {
return <Orginisation
key={o.id}
name={o.name}
clicked={(event) => this.handleClickOrg(o,o.id)}
></Orginisation>
})}
</div>
);
var activeContent=<ReactTable columns={this.state.columns} data={this.state.posts} noDataText={"Loading..."}></ReactTable>
// const columns = Object.keys(this.state.data[0]).map((key, id)=>{
// console.log(key)
// return {
// Header: key,
// accessor: key,
// }
// })
return (
<Router>
<Route path='/' exact render={
() => {
return (
<div className='authenticateContainer'>
<a href={this.state.authLink} className='fill-div'>Click to Auntheticate</a>
</div>
)
}
}/>
<Route path='/home' render={
() => {
return (
<div>
<div className='sideBar'>
<div className='logoHolder'>
<img className='logo' alt='Logo' src={'./Assets/logo.png'}></img>
</div>
{EndpointList}
{OrgList}
<div style={{}} className="org button" onClick={this.expandOrg}>
<img className="orgLogo" alt='Logo' src={'./Assets/orgLogo.png'}></img>
{this.state.activeOrg}
</div>
</div>
<div className="container" id={this.state.title}>
{/* <button onClick={() => { this.setCredentials() }}>CLICK ME</button> */}
<div className="contentContainer">
<div className="head">
{this.state.title}
</div>
{activeContent}
</div>
</div>
</div>
)
}
} />
</Router>
);
}
}
Instantiating the react-table (also in render function above):
var activeContent=<ReactTable columns={this.state.columns} data={this.state.posts} noDataText={"Loading..."}></ReactTable>
I have also printed the dummy data that is successfully being inserted into the list as well as the API data which is not. As you can see they are clearly identical:
Not sure if this will resolve your issue, but IMO you should refactor this to be
fetch('http://localhost:3100/employees')
.then((resp) => {
return resp.json()
})
.then((data) => {
let temp = [...this.state.posts]
temp.push(data.Employees[1])
this.setState({
posts: temp,
data: data
})
console.log(this.state.posts) //this will not have the newest values yet, setState is async
})
.catch((error) => {
console.log(error, "catch the hoop")
})
It's not good practice to perform manipulations on react state
Why are you pushing Employees[1]? That would be the second record.
Here is React code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import ReactTable from 'react-table';
import _ from 'lodash';
import './style.css';
class GithubDataTable extends Component {
render() {
const { showData, savedData } = this.props;
let data = null;
if (showData === 'last') {
data = _.last(savedData);
} else {
data = savedData[showData];
}
console.log(data);
return (
<div>
{data && (
<ReactTable
data={data.items}
columns={[
{
Header: 'Data from GitHub',
columns: [
{
Header: 'Id',
id: 'id',
accessor: d => d.id,
},
{
Header: 'Repo Title',
id: 'repoTitle',
accessor: d => d.name,
},
{
Header: 'Owner',
id: 'owner',
accessor: d => d.owner.login,
},
{
Header: 'Link',
id: 'link',
accessor: d => d.html_url, // example data string "https://github.com/Michaelcj10/ReactJS-GitHub-User-Finder-App"
},
{
Header: 'Created at',
id: 'createdAt',
accessor: d => d.created_at.slice(0, 10),
},
{
Header: 'Updated at',
id: 'updatedAt',
accessor: d => d.updated_at.slice(0, 10),
},
{
Header: 'Stars',
id: 'stars',
accessor: d => d.stargazers_count,
},
{
Header: 'Forks',
id: 'forks',
accessor: d => d.forks_count,
},
],
},
]}
defaultPageSize={10}
pageSizeOptions={[5, 10, 15, 20]}
className="-striped -highlight"
/>
)}
</div>
);
}
}
function mapStateToProps(state) {
return {
savedData: state.savedData,
showData: state.showData,
};
}
export default connect(mapStateToProps, null)(GithubDataTable);
And I have problem with that particular element:
{
Header: 'Link',
id: 'link',
accessor: d => d.html_url, // https://github.com/Michaelcj10/ReactJS-GitHub-User-Finder-App
},
Data is shown as text, but how can I add html in that particular situation to this JSX to obtain a link
Not enought text hack:
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters...
Looks like you might be able to use the Cell property to display custom markup:
{
Header: 'Link',
id: 'link',
accessor: d => d.html_url, // https://github.com/Michaelcj10/ReactJS-GitHub-User-Finder-App
Cell: props => <a href={props.value}>{props.value}</a>
},