I need to pass params from child component to the node elements from parent props.
Page component
export default function Categories() { const dispatch = useDispatch();
useEffect(() => {
dispatch(loaderAction(false));
return () => dispatch(loaderAction(true)); }, [dispatch]);
function handleClick(params) {
alert(); }
function handleEditClick(params) {
alert(); }
return (
<div className="categories-body">
<div className="categories-header">
<div className="left">
<h2>{t('[categories]')}</h2>
</div>
<div className="right">
<button className="button orange">{t('[addNewCategory]')}</button>
<LanguageSettings name="categoriesLanguageSetting" />
</div>
</div>
// Table component imported
<Table
action={
<>
//node elements
<button onClick={handleClick}>save</button>
<button onClick={handleEditClick}>edit</button>
</>
}
/>
</div> ); }
TableComponent
export default function Table({action}) {
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>date</th>
<th>key</th>
<th>category</th>
<th>actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>{action}</td> //pass parameter to node props
</tr>
</tbody>
</table>
);
}
I have pass two buttons to the Table component and need to pass for example row id to button onClick
Just pass the function... not the component
const handleClick = id => alert();
<Table action={handleClick} />
function Table({action}) {
return (
<table>
...
<td><button onClick={() => action(`someId`)}>action</button></td>
</table>
);
}
Or if you insist, pass a function component not an element:
actions={({id}) => <button onClick={() => handleClick(id)}>save</button>}
// Usage
function Table({action}) {
const Action = props.action;
return (
<table>
...
<td><Action id="Some id"/></td>
</table>
);
}
in your page component, just pass the actions prop as a render prop function
function handleClick(params) {
console.log(params);
alert();
}
function handleEditClick(params) {
console.log(params);
alert();
}
return (
<Table
action={ (params) => (
<>
<button onClick={() => handleClick(params)}>save</button>
<button onClick={() => handleEditClick(params)}>edit</button>
</>
)
}
/>
)
and in the table component call that function with the desired params,
with this approach, you can extend the render prop function to deliver multiple params
function Table({action}) {
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>date</th>
<th>key</th>
<th>category</th>
<th>actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>{action(23)}</td> // pass params here
</tr>
</tbody>
</table>
);
}
Related
There are two table components in the code with same number of columns. Need to move row from One table to Another table using Drag and Drop.
Example:
Table 1:
<table className='table1'>
<thead>
<tr><th>Col 1</th><th>Col 2</th></tr>
</thead>
<tbody>
<tr><td>1</td><td>2</td></tr>
<tr><th>Col 2</th><th>Col 2</th></tr>
<tr><th>Col 3</th><th>Col 2</th></tr>
</tbody>
</table>
Table 2:
<table className='table2'>
<thead>
<tr><th>Col 1</th><th>Col 2</th></tr>
</thead>
<tbody>
<tr><td>2</td><td>23/td></tr>
<tr><th>Col 4</th><th>Col 23</th></tr>
<tr><th>Col 5</th><th>Col 32</th></tr>
</tbody>
</table>
Table 1 and Table 2 need to be drag and droppable. Can anyone help regarding this?
Here is the code, I'm trying to fetch some data from JSON file. Tables are filled by the data, I can drag within the tables, when I drag and drop to another table, I can't move the row to another table, but both are Drag and Droppable. There are no errors shown, when doing drag and drop.
import "./styles.css";
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
import "bootstrap/dist/css/bootstrap.min.css";
import userdata from "./tempData.json";
import user2data from "./tempData_2.json";
import { useState } from "react";
export default function App() {
const [users, setUsers] = useState(userdata.data);
const [userrs, setUserrs] = useState(user2data.data);
const handleDragEnd = (e) => {
if (!e.destination) return;
let tempData = Array.from(users);
let [source_data] = tempData.splice(e.source.index, 1);
tempData.splice(e.destination.index, 0, source_data);
setUsers(tempData);
};
const handleDraggEnd = (e) => {
if (!e.destinationn) return;
let temppData = Array.from(userrs);
let [sourcee_data] = temppData.splice(e.source.index, 1);
temppData.splice(e.destinationn.index, 0, sourcee_data);
setUserrs(temppData);
};
return (
<div className="App mt-4">
<DragDropContext onDragEnd={handleDragEnd}>
<table className="table borderd">
<thead>
<tr>
<th />
<th>Username</th>
<th>Age</th>
<th>Gender</th>
</tr>
</thead>
<Droppable droppableId="droppable-2">
{(provider) => (
<tbody
className="text-capitalize"
ref={provider.innerRef}
{...provider.droppableProps}
>
{users?.map((user, index) => (
<Draggable
key={user.name}
draggableId={user.name}
index={index}
>
{(provider) => (
<tr {...provider.draggableProps} ref={provider.innerRef}>
<td {...provider.dragHandleProps}> = </td>
<td>{user.name}</td>
<td>{user.age}</td>
<td>{user.gender}</td>
</tr>
)}
</Draggable>
))}
{provider.placeholder}
</tbody>
)}
</Droppable>
</table>
</DragDropContext>
<DragDropContext onDragEnd={handleDraggEnd}>
<table className="table borderd">
<thead>
<tr>
<th />
<th>Username</th>
<th>Age</th>
<th>Gender</th>
</tr>
</thead>
<Droppable droppableId="droppable-1">
{(provider) => (
<tbody
className="text-capitalize"
ref={provider.innerRef}
{...provider.droppableProps}
>
{userrs.map((user, index) => (
<Draggable
key={user.name}
draggableId={user.name}
index={index}
>
{(provider) => (
<tr {...provider.draggableProps} ref={provider.innerRef}>
<td {...provider.dragHandleProps}> = </td>
<td>{user.name}</td>
<td>{user.age}</td>
<td>{user.gender}</td>
</tr>
)}
</Draggable>
))}
{provider.placeholder}
</tbody>
)}
</Droppable>
</table>
</DragDropContext>
</div>
);
}
I have passed an array of objects in useState hook as the initial state and i want to iterate over it using map method in other component, i have passed the current state as prop in the other object and have used map method over it but console message still shows values.map is not a function, i know we can only use map method on array i have done that only still the error shows.
created state and passed an array of objects-
const [values, setValues] = useState([
{
name: "Vansh",
age: 22,
email: "vansh#gmail.com",
},
]);
Passed values as props in Home component-
<Home
addFormData={addFormData}
setAddFormData={setAddFormData}
values={values}
setValues={setValues}
/>
Code of my home component-
const Home = ({ values }) => { return (
<div>
<table>
<thead>
<tr>
<th>name</th>
<th>age</th>
<th>email</th>
</tr>
</thead>
<tbody>
{values.map((val, index) => (
<tr>
<td key={val.index}>{val.name}</td>
<td key={val.index}>{val.age}</td>
<td key={val.index}>{val.email}</td>
</tr>
))}
</tbody>
</table>
<Link to="/form">
<button>FORM</button>
</Link>
</div> ); };
Please see the code it's working fine export below your missing export.
const Home = ({ values }) => {
// console.log(values);
return (
<div>
<table>
<thead>
<tr>
<th>name</th>
<th>age</th>
<th>email</th>
</tr>
</thead>
<tbody>
{values.map((val, index) => (
<tr>
<td key={val.index}>{val.name}</td>
<td key={val.index}>{val.age}</td>
<td key={val.index}>{val.email}</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default Home;
Please see the code SandBoxLink
Do you know why am I not a able to map through the todos? I am following tutorial online and I have it exactly the same as the other guy but It's not mapping through the data. I get the json back and I can see the todos inside of the client-side console.
import React, { Fragment, useEffect, useState } from "react";
const ListTodos = () => {
const [todos, setTodos] = useState([]);
const getTodos = async () => {
try {
const response = await fetch("http://localhost:5000/todos");
const jsonData = await response.json();
setTodos(jsonData);
} catch (err) {
console.error(err.message);
}
};
useEffect(() => {
getTodos();
}, []);
return (
<Fragment>
<table className="table mt-5 text-center">
<thead>
<tr>
<th>Description</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{todos.map((todo) => {
<tr>
<td>{todo.description}</td>
<td>Edit</td>
<td>Delete</td>
</tr>;
})}
</tbody>
</table>
</Fragment>
);
};
Thanks
You should return the JSX if you are using curly braces in function. Like This
{todos.map((todo) => {
return (<tr>
<td>{todo.description}</td>
<td>Edit</td>
<td>Delete</td>
</tr>;
)})}
Else use parentheses to directly return , Like This
{todos.map((todo) => (<tr>
<td>{todo.description}</td>
<td>Edit</td>
<td>Delete</td>
</tr>
))}
you should use round brackets insted of curly braces in the map function
return (
<Fragment>
<table className="table mt-5 text-center">
<thead>
<tr>
<th>Description</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{todos.map((todo) => (
<tr>
<td>{todo.description}</td>
<td>Edit</td>
<td>Delete</td>
</tr>
))}
</tbody>
</table>
</Fragment>
);
I have a array of employee objects and i'm using that array(passed as state) to build rows in a table(as shown below). I get this error while iterating over the array. when I display the array using {props.employee_data}(the line is commented)
TypeError: Cannot read property 'map' of null
Code:
export default function(props) {
let employees = null
return (
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>Full Name</th>
<th>Gender</th>
<th>Current Annual Salary</th>
<th>2018 Gross Pay Received</th>
<th>2018 Overtime Pay</th>
<th>Department</th>
<th>Department Name</th>
<th>Division</th>
<th>Assignment Category</th>
<th>Employee Position Title</th>
<th>Position Under-filled</th>
<th>Date First Hired</th>
</tr>
</thead>
<tbody>
{/* <tr>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
*/}
{/* {props.employee_data} */}
{props.employee_data.map((employee)=>{
return <tr>employee</tr>
}
)}
</tbody>
</Table>
)
}
parent component
class App extends Component {
constructor(props){
super(props)
this.state = {
employee_data: null,
column_names: null
}
}
componentDidMount = () => {
this.fetchData();
}
fetchData = async () => {
fetch(county_data).
then(response => response.json()).
then(response => {
console.log(response.data)
let column_names = response.meta.view.columns.map((item)=>{
return item['name']
})
// console.log(JSON.stringify(response.data))
this.setState({
employee_data: response.data,
column_names: column_names
})
})
}
render() {
return (
<div className="App">
<Container>
<Row>
<Col lg={4}>1 of 3</Col>
<Col lg={4}>2 of 3</Col>
<Col lg={4}>2 of 3</Col>
</Row>
</Container>
<br></br>
<br></br>
<DataTable employee_data={this.state.employee_data}/>
</div>
);
}
}
export default App;
Initially the employee_data is null, it is not until your fetch, the employee data is an array.
map is a function on the array's prototype, hence it will not be available on the initial employee_data which is null. Only after the fetch, the employee data is an array and the map function is available.
To get around this, you can initially declare employee_data as an empty array.
this.state = {
employee_data: [],
... other state data,
}
you can do th
export default function(props) {
let employees = props.employee_data?props.employee_data:[];
return (
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>Full Name</th>
<th>Gender</th>
<th>Current Annual Salary</th>
<th>2018 Gross Pay Received</th>
<th>2018 Overtime Pay</th>
<th>Department</th>
<th>Department Name</th>
<th>Division</th>
<th>Assignment Category</th>
<th>Employee Position Title</th>
<th>Position Under-filled</th>
<th>Date First Hired</th>
</tr>
</thead>
<tbody>
{/* <tr>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
*/}
{/* {props.employee_data} */}
{employees.map((employee)=>{
return <tr>employee</tr>
}
)}
</tbody>
</Table>
)
}
I am tryng to display search results for each key press on my input:
getMovies(e){
axios.get(`http://www.omdbapi.com/?t=${e.target.value}`)
.then((response) => {
this.setState({ movies: response.data });
})
.catch((error) => {
console.log(error);
});
}
render() {
return (
<div className="container">
<SearchForm onkeydown={this.getMovies} />
<MovieList movies={this.state.movies}/>
</div>
);
}
}
In my search form I bind my function to the FormControl onChange:
export default class SearchForm extends React.Component{
render(){
return(
<Row>
<Col md={6} >
<h2>Custom search field</h2>
<div className="custom-search-input">
<Col md={12} className="input-group" >
<FormControl
type="text"
bsSize="lg"
value={this.props.val}
placeholder="Enter text"
onChange={this.props.onkeydown.bind(this)}
/>
<span className="input-group-btn">
<button className="btn btn-lg" type="button">
<i className="glyphicon glyphicon-search"></i>
</button>
</span>
</Col>
</div>
</Col>
</Row>)
}
}
My movielist component:
export default class MovieList extends React.Component{
render(){
var userNodes = this.props.movies.map(function(movie){
return (
<tr key={movie.id}>
<td>{movie.Year}</td>
<td >{movie.Title}</td>
<td >{movie.Released}</td>
</tr>
)
});
return (
<div>
<Table responsive>
<thead>
<tr>
<th>id</th>
<th>Year</th>
<th>Title</th>
<th>Released</th>
</tr>
</thead>
<tbody>
{userNodes}
</tbody>
</Table>
</div>
);
}
}
I can get the response on the network panel, but the state is not updating to display the MovieList component.
How can I update the state and display it in my MovieList ?
I've checked that API and seems it returns an object, not an array.
Update 1
You can convert your component in something like:
export default class MovieList extends React.Component{
render(){
const { movie } = this.props;
return (
<div>
<Table responsive>
<thead>
<tr>
<th>Id</th>
<th>Year</th>
<th>Title</th>
<th>Released</th>
</tr>
</thead>
<tbody>
<tr>
<td>{movie.imdbID}</td>
<td>{movie.Year}</td>
<td>{movie.Title}</td>
<td>{movie.Released}</td>
</tr>
</tbody>
</Table>
</div>
);
}
}
and use it like:
<MovieList movie={this.state.movies} />
Please notice I'm using movie instead of movies.
Update 2:
You can also (and I would suggest doing this) convert your MovieList into a dumb functional component:
const MovieList = ({ movie }) => (
<div>
<Table responsive>
<thead>
<tr>
<th>Id</th>
<th>Year</th>
<th>Title</th>
<th>Released</th>
</tr>
</thead>
<tbody>
<tr>
<td>{movie.imdbID}</td>
<td>{movie.Year}</td>
<td>{movie.Title}</td>
<td>{movie.Released}</td>
</tr>
</tbody>
</Table>
</div>
)
export default MovieList;