React pass params to the node elements from child component - reactjs

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

How to drag and drop HTML table rows between two tables using ReactJS

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>
);
}

values.map is not a function n reactjs while passing array in state and mapping the current state

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

Issue with mapping through the data - React

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>
);

reactjs iterate over a array in functional component

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>
)
}

Display search results on keypress

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;

Resources