New to React and using a simple table. I'm just testing to change an input text value when I select a button on the same row.
The code below is where I'm stuck. I'm trying to figure out how to change the state value "users" for this row when I click on the button. I'm trying to set the first_name to "Testing".
const [users, setUsers] = React.useState(null);
let usersList =
businessUsersState.data.length > 0 &&
businessUsersState.data.map((item: any, key: number) => {
return (
<tr key={key} data-account={item.account_id}>
<td>
<Form.Control name="first-name" type="input" placeholder="First Name" defaultValue={item.first_name} />
</td>
<td>
<Button variant="primary" type="button" onClick={() => {
debugger;
const row = businessUsersState.data.map((item: any) => ({...item}));
row[key].first_name = 'Testing';
const row1 = usersList[key];
//setUserRow(row);
//setUsers(row);
}}>
</Button>
</td>
</tr>
);
});
setUsers(usersList);
I was reading the following link but I cant seem to get it to work. Any help is appreciated.
Following React docs example of object and array in state
const uniqueId = () => {
// always start with a letter (for DOM friendliness)
let idstr = String.fromCharCode(Math.floor(Math.random() * 25 + 65));
do {
const ascicodeChar = Math.floor(Math.random() * 25 + 65);
idstr += String.fromCharCode(ascicodeChar);
idstr += Math.floor(Math.random() * 99);
} while (idstr.length < 8);
return idstr.toLowerCase();
};
const fakeData = [
{ id: uniqueId(), company: 'abc', contact: 'a#gmail.com', country: 'China' },
{ id: uniqueId(), company: 'def', contact: 'b#gmail.com', country: 'Japan' },
{
id: uniqueId(),
company: 'ghj',
contact: 'c#gmail.com',
country: 'Singapore',
},
{
id: uniqueId(),
company: 'ikl',
contact: 'd#gmail.com',
country: 'Indonesia',
},
{
id: uniqueId(),
company: 'mno',
contact: 'e#gmail.com',
country: 'Thailand',
},
];
export default function App() {
const [data, setData] = React.useState(fakeData);
const handleEdit = (id) => {
setData(
data.map((t) => {
// find item matched given id and mutate that item
if (t.id === id) {
return {
id,
company: `test${id}`,
contact: `test${id}#gmail.com`,
country: `test${id}`,
};
} else {
return t;
}
})
);
};
return (
<div>
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
<th>edit</th>
</tr>
{(() => {
if (!data.length) {
return <p>No data available</p>;
}
return data.map((i, index) => {
return (
<tr key={i.id}>
<td>{i.company}</td>
<td>{i.contact}</td>
<td>{i.country}</td>
<td>
{/* pass an id of row to edit fnc */}
<button onClick={() => handleEdit(i.id)}>edit</button>
</td>
</tr>
);
});
})()}
</table>
</div>
);
}
You could try to do the same above example.
Related
I have created a react table with select rows following this example.
I'm trying to modify it so that when the data loads, the corresponding checkbox is either checked or unchecked based on the row data's included value. The value doesn't seem to be recognized and when I check/uncheck a row the onChange console.log event isn't being fired. What am I doing wrong.
Heres my Sandbox Example
DATA
[
{
systemId: 13,
deqId: "25007",
facilityId: 6487,
sourceId: "WS002",
sourceName: "GROVE SPRING",
flowRate: 461,
flowUom: "GPM ",
included: true
},
{
systemId: 13,
deqId: "25007",
facilityId: 4742,
sourceId: "WS004",
sourceName: "WELL #1",
flowRate: 1100,
flowUom: "GPM ",
included: true
},
{
systemId: 13,
deqId: "25007",
facilityId: 4743,
sourceId: "WS005",
sourceName: "100 W (WELL #2) ",
flowRate: 800,
flowUom: "GPM ",
included: true
},
{
systemId: 13,
deqId: "25007",
facilityId: 4744,
sourceId: "WS007",
sourceName: "NORTH (WELL #3) ",
flowRate: 900,
flowUom: "GPM ",
included: true
}
];
INDETERMINATE CHECKBOX
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, checked, name, ...rest }, ref) => {
const defaultRef = React.useRef(checked);
const resolvedRef = ref || defaultRef;
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate;
resolvedRef.current.checked = checked;
}, [resolvedRef, indeterminate, checked]);
return (
<>
<input
type="checkbox"
ref={resolvedRef}
checked={checked}
name={name}
id={name}
{...rest}
/>
</>
);
}
);
REACT TABLE
function ReactTable({
columns,
data,
handleCheckboxSelection,
handleCheckboxStateChange
}) {
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
footerGroups,
rows,
prepareRow,
selectedFlatRows
} = useTable(
{
columns,
data
},
useRowSelect,
(hooks) => {
hooks.visibleColumns.push((columns) => [
// Let's make a column for selection
{
id: "selection",
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: (
{ getToggleAllRowsSelectedProps },
handleCheckboxStateChange
) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox
name={row.original.sourceId}
onChange={(row) => console.log(row.original)} //not firing
checked={row.original.included}
{...row.getToggleRowSelectedProps()}
/>
</div>
)
},
...columns
]);
}
);
// Render the UI for your table
return (
<>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()}>{column.render("Header")}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.slice(0, 10).map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>{cell.render("Cell")}</td>
);
})}
</tr>
);
})}
</tbody>
<tfoot>
{footerGroups.map((group) => (
<tr {...group.getFooterGroupProps()}>
{group.headers.map((column) => (
<td {...column.getFooterProps()}>
<b>{column.render("Footer")}</b>
</td>
))}
</tr>
))}
</tfoot>
</table>
<button onClick={() => handleCheckboxSelection(selectedFlatRows)}>
Save
</button>
</>
);
}
TABLE IMPLEMENTATION
const MyDataTable = ({
data
}) => {
const handleCheckboxSelection = (array) => {
console.log(array.map((d) => d.original));
};
const columns = React.useMemo(
() => [
{
Header: "Source ID",
accessor: "sourceId"
},
{
Header: "Source Name",
accessor: "sourceName"
},
{
Header: "Flow Rate (GPM)",
accessor: (d) => {
return d.flowRate ? numberWithCommas(d.flowRate) : "";
}
}
],
[]
);
return (
<ReactTable
columns={columns}
data={data}
handleCheckboxSelection={handleCheckboxSelection}
/>
);
};
The props you added to IndeterminateCheckbox are being overwritten. row.getToggleRowSelectedProps() returns an object:
{
onChange: function,
checked: Boolean,
title: String,
indeterminate: Boolean,
style: Object
}
which overwrites your properties.
The correct way to do what you want to do would be to use
initialState.selectedRowIds property from the useRowSelect API.
Map your data to their included values, then add that array to the initialState as selectedRowIds. In ReactTable.js:
const selectedRowIds = data.map((d, ind) => d.included)
const {
// etc
} = useTable(
{
columns,
data,
initialState: {selectedRowIds}
},
//etc
...columns
}
);
you have to refresh your Table.
you can use useState.
example : you can add onClick={this.mychange} to your save Button.
mychange = async () => {
this.setState({
List: //the new List Data
})
}
and dont forget the Constructor.
constructor() {
super();
this.state = {
List: anyList,
};
}
const students = [
{ _id: 1, name: "Ahmed Ali" },
{ _id: 2, name: "John Doe" },
{ _id: 3, name: "Jane Doe" },
{ _id: 4, name: "Farah Gedi" },
{ _id: 5, name: "Mustafa Jama" }
]
const attendCheck = ({ target: { name, value, id } }) => {
// logics will go here...
}
I returned this table with students data
<table className='table table-sm hover bordered striped'>
<thead>
<tr>
<th>STD ID</th>
<th>NAME</th>
<th> </th>
</tr>
</thead>
<tbody>
{students &&
students.map((std) => (
<tr key={std._id}>
<td>{std.name}</td>
<td>
<input
className='form-check-input me-1'
type='checkbox'
id={`${std._id}`}
name={`${std.name}`}
onChange={(e) => attendCheck(e)}
value={std._id}
/>
</td>
</tr>
))}
</tbody>
</table>
As you see above it has checkboxes input. I want to store all checked data in a new array, how do I do that?.
NB. students data it's not real data, I'm fetching the data from server so it can be any length.
If you want store only id student, you can add a state is array to store selected id student:
const [selected, setSelected] = useState([]);
const attendCheck = ({ target: { name, value, id } }) => {
if (!selected.includes(id)) {
setSelected((prevSelected) => [...prevSelected, id]);
} else {
setSelected((prevSelected) =>
prevSelected.filter((stdId) => stdId!== id)
);
}
}
I have been trying without any luck, my implementation inside the Update method is not updating the state of products. Please assist with what am I doing wrong. I am using Functional Components with Hooks.
function MyTable() {
const initState = [
{ id: 1, name: "bread", quantitiy: 50, location: "cupboard" },
{ id: 2, name: "milk", quantitiy: 20, location: "fridge" },
{ id: 3, name: "water", quantitiy: 10, location: "fridge" }
];
const [state, setState] = React.useState(initState);
const handleUpdateQuantity = (productId: any, value: any) => {
let newData = data;
var index: number = newData.findIndex(
(product: any) => product.id === productId
)
if (index !== -1) {
newData[index].quantity = value
setData(newData)
} else {
console.log("Product not existing on table data...")
}
}
return (
<table>
<tr key={"header"}>
{Object.keys(state[0]).map((key) => (
<th>{key}</th>
))}
</tr>
{state.map((item) => (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.location}</td>
<TextField
type="number"
defaultValue={1}
onChange={(event) =>
handleUpdateQuantity(item.id, event.target.value)
}
/>
<td>{item.quantitiy}</td>
</tr>
))}
</table>
);
}
ReactDOM.render(<MyTable />, document.getElementById("target"));
You can use a functional update(as the new state depends on the previous state):
const handleUpdateQuantity = (productId: any, value: any) => {
setData(prevData => prevData.map(el => {
if(el.id === productId) {
return {...el, quantity: value};
}
return el;
}))
}
Also, quantitiys in the initial state has a typo.
and in the JSX, add value prop to the text field:
<TextField
type="number"
defaultValue={1}
value={item.quantity}
onChange={(event) =>
handleUpdateQuantity(item.id, event.target.value)
}
/>
I have my ReactApp created and would like to display a table with data from AWS dynamodb.
I successfully got data from dynamodb transferred to ReactApp with json, through map() in render() of ReactApp, I displayed the table as below:
How it looks now
So now i need to make the table like re-distributed as below:
How i want it to display
So I plan to render the table with if-else statement accordingly:
but once i put in if-else clause in the function, it didn't work and nothing displayed. So would like to seek advices from experts in stackoverflow :) many thanks in advance
Here is my code, the part I'm stuck is in the return section in render():
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
};
}
render() {
const { hits, isLoading, error } = this.state;
if (error) {
return <p>{error.message}</p>;
}
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<form>
<div className="container border border-secondary rounded center">
<div className="row">
<div className="col-12">
{' '}
<h4>
<b>Class Mapping</b>
</h4>{' '}
</div>
</div>
<div className=".col-xs-12 center text-center">
<Table responsive striped bordered hover>
<tr>
<th>Class 1</th>
<th>Class 2</th>
<th>Class 3</th>
<th>Class 4</th>
<th>Class 5</th>
</tr>
<tbody>
{hits.map((hit) => {
if (hit.class === 'Class 1') {
<tr>
<td>{hit.name}}</td> <td></td> <td></td> <td></td> <td></td>{' '}
</tr>;
} else if (hit.class === 'Class 2') {
<tr>
<td></td>
<td>{hit.name}}</td> <td></td> <td></td> <td></td>{' '}
</tr>;
}
})}
</tbody>
</Table>
</div>
</div>
</form>
);
}
async componentDidMount() {
this.setState({ isLoading: true });
const response = await fetch('https://xxxxxxx');
const body = await response.json();
this.setState({ hits: body, isLoading: false, error: null });
}
}
export default App;
So you want to take an array that looks like this:
const hits = [
{ name: 'Tammy', class: 'Class 1' },
{ name: 'Sarah', class: 'Class 2' },
{ name: 'Roland', class: 'Class 3' },
{ name: 'Moshe', class: 'Class 4' },
{ name: 'Peter', class: 'Class 5' },
];
And transform it into an array of names, arranged into columns by their classname, like this:
const rows = [
['Tammy', 'Sarah', 'Roland', 'Moshe', 'Peter'],
['Helen', 'Eric', 'Fiona', 'Darren', 'Andy'],
];
Thats going to take a bit of work. I don't think that you will be able to accomplish it with if/else statement inside a few map functions.
Let's try this. I propose adding a class method to your component called getRows. This method will do the transformation. We start by iterating over your hits and grouping the names by class.
Then we setup a while loop, to push the names into the new rows array. While we still have names, keep building rows. Each row will pick a name according to the column and insert it.
Finally, when we are all out of names, we can return the rows to the render function. Then we map the rows, and map the columns in each rows. We also need unique keys for each mapped element.
getRows()
const getRows = () => {
const columns = ['Class 1', 'Class 2', 'Class 3', 'Class 4', 'Class 5'];
const rows = [];
const groupByColumn = this.state.hits.reduce((acc, next) => {
return { ...acc, [next.class]: [...(acc[next.class] || []), next.name] };
}, {});
const haveNames = () => columns.some((column) => (groupByColumn[column] || []).length > 0);
while (haveNames()) {
const newRow = columns.map((column) => {
return (groupByColumn[column] || []).shift() || '';
});
rows.push(newRow);
}
return rows;
};
The complete component:
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
};
}
async componentDidMount() {
this.setState({ isLoading: true });
const response = await fetch('https://xxxxxxx');
const body = await response.json();
this.setState({ hits: body, isLoading: false, error: null });
}
getRows = () => {
const columns = ['Class 1', 'Class 2', 'Class 3', 'Class 4', 'Class 5'];
const rows = [];
const groupByColumn = this.state.hits.reduce((acc, next) => {
return { ...acc, [next.class]: [...(acc[next.class] || []), next.name] };
}, {});
const haveNames = () => columns.some((column) => (groupByColumn[column] || []).length > 0);
while (haveNames()) {
const newRow = columns.map((column) => {
return (groupByColumn[column] || []).shift() || '';
});
rows.push(newRow);
}
return rows;
};
render() {
if (this.state.error) {
return <p>{error.message}</p>;
}
if (this.state.isLoading) {
return <p>Loading ...</p>;
}
return (
<form>
<div className="container border border-secondary rounded center">
<div className="row">
<div className="col-12">
{' '}
<h4>
<b>Class Mapping</b>
</h4>{' '}
</div>
</div>
<div className=".col-xs-12 center text-center">
<Table responsive striped bordered hover>
<tr>
<th>Class 1</th>
<th>Class 2</th>
<th>Class 3</th>
<th>Class 4</th>
<th>Class 5</th>
</tr>
<tbody>
{this.getRows().map((row) => (
<tr key={row.reduce((a, b) => a + b)}>
{row.map((column) => (
<td key={column}>{column}</td>
))}
</tr>
))}
</tbody>
</Table>
</div>
</div>
</form>
);
}
}
export default App;
Example code
const hits = [
{ name: 'Tammy', class: 'Class 1' },
{ name: 'Camen', class: 'Class 2' },
{ name: 'Happy', class: 'Class 3' },
{ name: 'Hello Kitty', class: 'Class 4' },
{ name: 'Hello Mimi', class: 'Class 3' },
];
const getRows = (hits) => {
const columns = ['Class 1', 'Class 2', 'Class 3', 'Class 4', 'Class 5'];
const rows = [];
const groupByColumn = hits.reduce((acc, next) => {
return { ...acc, [next.class]: [...(acc[next.class] || []), next.name] };
}, {});
const haveNames = () => columns.some((column) => (groupByColumn[column] || []).length > 0);
while (haveNames()) {
const newRow = columns.map((column) => {
return (groupByColumn[column] || []).shift() || '';
});
rows.push(newRow);
}
return rows;
};
const rows = getRows(hits);
console.log(rows);
I have logged: false in my store and I need to change it to true on a button action in a component in react js. If you could tell me how to edit/update data in store or share a link?
How to create Store
const redux = require('redux');
const createStore = redux.createStore;
const initialState = {
counter: 0
}
const rootReducer = (state = initialState, action) => {
if(action.type === 'INC_COUNTER'){
return {
...state,
counter: state.counter + 1
};
}
return state;
};
How to call Action
const mapDispatchToProps = dispatch => {
return {
onIncrementCounter: () => dispatch({type:'INC_COUNTER'})
};
};
Calling it on click
<button clicked={this.props.onIncrementCounter} />
Here is a simple React Component which implements create,read,update,delete functionality:
[You can also view code implementation on codesanbox.io https://codesandbox.io/s/81r0n6l112
import React from "react";
import idGenerator from "react-id-generator";
export default class App extends React.Component {
state = {
employees: [],
firstname: "",
lastname: "",
id: 0,
create: true
};
componentDidMount() {
//Intializing sample data
const emps = [
{ firstname: "John", lastname: "Doe", id: 0 },
{ firstname: "Bruno", lastname: "Mars", id: 0 }
];
this.setState({
employees: emps.map(e => {
return {
firstname: e.firstname,
lastname: e.lastname,
id: idGenerator()
};
})
});
}
handleChange = e => {
const name = e.target.name;
this.setState({ [name]: e.target.value });
};
handleCreateEmployee = () => {
if (this.state.employees) {
this.setState({
employees: [
...this.state.employees,
{
firstname: this.state.firstname,
lastname: this.state.lastname,
id: idGenerator()
}
]
});
} else {
this.setState({
employees: [
{
firstname: this.state.firstname,
lastname: this.state.lastname,
id: idGenerator()
}
]
});
}
this.setState({ firstname: "", lastname: "" });
};
handleEdit = e => {
const employee = this.state.employees.find(function(emp) {
if (emp.id === e.target.id) {
return emp;
}
});
this.setState({
firstname: employee.firstname,
lastname: employee.lastname,
id: employee.id,
create: false
});
};
handleDelete = e => {
this.setState({
employees: this.state.employees.filter(function(emp) {
if (emp.id !== e.target.id) return emp;
})
});
};
handleUpdateEmployee = () => {
const employee = {
firstname: this.state.firstname,
lastname: this.state.lastname,
id: this.state.id
};
const employeesupdated = this.state.employees.map(emp => {
if (emp.id === this.state.id) {
return employee;
} else return emp;
});
this.setState((prevStae, props) => ({
employees: employeesupdated,
create: true,
firstname: "",
lastname: ""
}));
};
render() {
const create = this.state.create ? "Save" : "Update";
const { employees } = this.state;
const inputIsEmpty =
this.state.firstname === "" || this.state.lastname === "" ? true : false;
return (
<div>
<input
style={{ width: 120 }}
type="text"
placeholder="Enter Firstname"
onChange={this.handleChange}
name="firstname"
value={this.state.firstname}
/>
<input
style={{ width: 120 }}
type="text"
placeholder="Enter Firstname"
onChange={this.handleChange}
name="lastname"
value={this.state.lastname}
/>
<button
style={{ width: 150 }}
disabled={inputIsEmpty}
onClick={
this.state.create
? this.handleCreateEmployee
: this.handleUpdateEmployee
}
>
{create}
</button>
<br />
<table border="1" style={{ width: 400, paddingTop: 5 }}>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{employees.map((emp, i) => {
return (
<tr key={i}>
<td>{emp.firstname}</td>
<td>{emp.lastname}</td>
<td>
<button onClick={this.handleEdit} id={emp.id}>
Edit
</button>
</td>
<td>
<button onClick={this.handleDelete} id={emp.id}>
Delete
</button>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
[You can also view the code implementation here][1]
[1]: https://codesandbox.io/s/81r0n6l112