How to enable optional chaining -React - reactjs

I want to add a checkbox to each row in the table I have already created.
In addition, there should be a select all button and it should be able to select all rows.
I tried this but I'm getting the error
support for the experimental syntax 'optional chaining' isn't currently enabled.
import React, { useState, useEffect } from "react";
/* const userData = [{name: "Didem1"}, {name : "Didem2"}] */
const UserTable = (props) => {
const [users, setUsers] = useState([]);
const userData = [props.users];
useEffect(() => {
setUsers(userData);
}, []);
const handleChange = (e) => {
const { name, checked } = e.target;
if (name === "allSelect") {
let tempUser = users.map((user) => {
return { ...user, isChecked: checked };
});
setUsers(tempUser);
} else {
let tempUser = users.map((user) =>
user.name === name ? { ...user, isChecked: checked } : user
);
setUsers(tempUser);
}
};
return (
<table className="table table-dark">
<thead>
<tr>
<th scope="col">
<input
type="checkbox"
className="form-check-input"
name="allSelect"
onChange={handleChange}
checked={
users.filter((user) => user?.isChecked !== true).length < 1
}
/>
Select All
</th>
<th scope="col">Hostname</th>
<th scope="col">Username</th>
<th scope="col">Stop</th>
<th scope="col">Sleep</th>
<th scope="col">Start</th>
<th scope="col">Status</th>
<th scope="col">CPU Temperature(°C)</th>
<th scope="col">GPU Info</th>
<th scope="col">Edit/Delete</th>
</tr>
</thead>
<tbody>
{props.users.length > 0 ? (
props.users.map((user) => (
<tr key={user.id}>
<th scope="row">
<input
type="checkbox"
className="form-check-input"
/* user?.isChecked || false */
name={user.name}
checked={user?.isChecked || false}
onChange={handleChange}
/>
</th>
<td>{user.name}</td>
<td>{user.username}</td>
<td>
<button
onClick={() => props.editStopPC(user)}
className="btn btn-danger"
>
Stop
</button>
</td>
<td>
<button
onClick={() => props.editSleepPC(user)}
className="btn btn-warning"
>
Sleep
</button>
</td>
<td>
<button
onClick={() => props.editStartPC(user)}
className="btn btn-success"
>
Start
</button>
</td>
<td>{user.status}</td>
<td>{user.cpu}</td>
<td>{user.info}</td>
<td className="center-align">
<button
className="btn btn-info"
onClick={() => props.editRow(user)}
>
edit
</button>
<button
className="btn btn-danger"
onClick={() => props.deleteUser(user.id)}
>
delete
</button>
</td>
</tr>
))
) : (
<tr>
<td colSpan={9}>{props.users[0]} No Users</td>
</tr>
)}
</tbody>
</table>
);
};
export default UserTable;
So I installed react-scripts#3.3.0 and #babel/plugin-proposal-optional-chaining and now I am getting error:
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
I'm not sure what causes this. I would be glad if you help.

Related

How to check one item in a list of checkboxes in react?

I have a list of items from API with 2 checkboxes for each item. one checkbox for approve and the other for decline. But I encountered 2 problems, all the checkboxes are checked using the checked attribute.
function AllReferral() {
const [status, setStatus] = React.useState(false)
const handleChange = (item, checked) => {
setStatus((prevState) => !prevState);
checked
? setChecked((prev) => [
...prev,
{
serviceName: item?.label,
status: status,
},
])
: setChecked((prev) => [...prev, item].filter((c) => c !== item));
};
return (
<section>
<div>
{user?.services?.length > 0 && (
<div>
<table>
<thead>
<tr>
<th >Approve</th>
<th >Decline</th>
<th >Service Name</th>
</tr>
</thead>
{user?.services?.map((item, index) => (
<tbody key={index}>
<tr>
<td>
<input
name={item?.name}
type="checkbox"
checked={status}
onChange={(e) => handleChange(item, e.target.checked)}
/>
</td>
<td>
<input
name={item?.name}
type="checkbox"
checked={!status}
onChange={(e) => handleChange(item, e.target.checked)}
/>
</td>
<td>{item?.label}</td>
</tr>
</tbody>
))}
</table>
</div>
)}
</div>
</section>
);
}
from above implementation, if I have 4 items, all 4 is checked by default. I want each item in the list to be checked separately either approve or decline. Secondly I want the setChecked to return an array of both approved and declined item differentiated by status true or false.

unable to get table item in deleted section

i have created a component in which i delete the table item its deleted i also want to add a button to add in the deleted item in the table done successfully but problem is that when I remove table item it item should be shown in the deleted component here is my code
class Movies extends Component {
state = {
movies,
deleted:[]
};
handleDelete = (_id) => {
const movie = this.state.movies.find(movie => movie._id === _id);
this.setState({ deleted: [...this.state.deleted, movie] });
this.setState({movies:this.state.movies.filter(movie => movie._id !== _id)})
};
handleReinstate = (_id) => {
const movie = this.state.deleted.find((movie) => movie._id === _id);
this.setState({ movies:[ ...this.state.movies,movie] });
this.setState({deleted:this.state.deleted.filter((movie) => movie._id !== _id)})
};
render() {
return (
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map((movie) => {
return(
<tr key={movie._id}>
<td>{movie.title}</td>
<td>{movie.genre.name}</td>
<td>{movie.numberInStock}</td>
<td>{movie.dailyRentalRate}</td>
<td
onClick={() => this.handleDelete(movie._id)}
className="btn btn-danger btn-outline-warning btn-sm active "
>
Remove
</td>
</tr>
)})}
</tbody>
<tbody>
<h1>deleted</h1>
{this.state.deleted.map(movie => (
<tr key={movie._id}>
<td
onClick={() => this.handleReinstate(movie._id)}
className="btn btn-danger btn-outline-primary btn-sm active "
>
ADD
</td>
</tr>
))}
</tbody>
</table>
);
}
}
I want to show like this but failed
adding this will solve problem
{this.state.deleted.map(movie => (
<tr key={movie._id}>
<td>{movie.title}</td>
<td>{movie.genre.name}</td>
<td>{movie.numberInStock}</td>
<td>{movie.dailyRentalRate}</td>
<td
onClick={() => this.handleReinstate(movie._id)}
className="btn btn-danger btn-outline-primary btn-sm active "
>
ADD
</td>
</tr>
))}

Editable table react

I am trying to target a specific row to edit on my table in React.
My code looks something like this...
const [rowData, setRowData] = useState({ kind: { str: '', row: '' }});
const onChange = e => {
setRowData({...rowData, [e.target.name]: e.target.value }}
}
arr.map((ele, index) => (
<tr>
<td><input type='text' name='kind' value={kind.str} row={index} onChange={e => onChange(e)}></td>
</tr>
))
I didn't write all my code but I think that should be sufficient enough for an answer.
Basically I press a button edit that makes the row editable. When I press this button actually all rows and columns become editable which is not what I want but regardless of this outcome - I go to update the table and only that one input gets updated, unfortunately I get this error
A component is changing a controlled input of type text to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component
After reading the error I then decided to change my onChange function to this...
const onChange = e => {
setRowData({...rowData, [e.target.name]: { str: e.target.value, row: e.target.getAttribute('row')}}
}
the above solves the issue from making my controlled component becoming uncontrolled however all the input fields on each row that match the kind name get updated which is not the desired functionality I want.
How can I solve this issue. Eventually what I want is an editable table that the user can update a single row and update the database with the data they input.
The arr variable I am using is actually named files.
I have another component which gets all my files from my database and sets it to the files variable
const [files, setFiles] = useState([]);
useEffect(() => {
const fetchFiles = async () => {
setLoading(true);
const res = await fetch('http://localhost:5000/api/files/all', {
method: 'GET',
});
const data = await res.json();
setFiles(data);
setLoading(false);
};
fetchFiles();
}, []);
I then pass in as props files to my Items component which is where the code that I wrote for my question lives in.
Most of the code is here...
ShowList component
const ShowList = () => {
const [files, setFiles] = useState([]);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [filesPerPage, setFilesPerPage] = useState(5);
const [yourUploads, setYourUploads] = useState(false);
useEffect(() => {
const fetchFiles = async () => {
setLoading(true);
const res = await fetch('http://localhost:5000/api/files/all', {
method: 'GET',
});
const data = await res.json();
setFiles(data);
setLoading(false);
};
fetchFiles();
}, []);
const indexOfLastPage = currentPage * filesPerPage;
const indexOfFirstPage = indexOfLastPage - filesPerPage;
const currentFiles = files.slice(indexOfFirstPage, indexOfLastPage);
const paginate = (pageNumber) => setCurrentPage(pageNumber);
return (
<Fragment>
<div className='container'>
<h3 className='text-center'>
{yourUploads ? 'Your uploads' : 'All uploads'}
</h3>
<div className='d-flex dropdown'>
<button
className='btn mb-3 mr-3'
type='button'
id='dropdownMenuButton'
data-toggle='dropdown'
aria-haspopup='true'
aria-expanded='false'
>
Pages per row {filesPerPage}
</button>
<div className='dropdown-menu' aria-labelledby='dropdownMenuButton'>
<button
className='dropdown-item'
onClick={() => setFilesPerPage(5)}
>
5
</button>
<button
className='dropdown-item'
onClick={() => setFilesPerPage(10)}
>
10
</button>
</div>
<div className='dropdown'>
<button
className='btn mb-3'
type='button'
id='dropdownUploadsButton'
data-toggle='dropdown'
aria-haspopup='true'
aria-expanded='false'
>
{yourUploads ? 'your uploads' : 'all uploads'}
</button>
<div
className='dropdown-menu'
aria-labelledby='dropdownUploadButton'
>
<button
className='dropdown-item'
onClick={() => setYourUploads(true)}
>
your uploads
</button>
<button
className='dropdown-item'
onClick={() => setYourUploads(false)}
>
all uploads
</button>
</div>
</div>
</div>
<table id='myTable' className='table table-striped w-100'>
<thead>
<tr>
<th scope='col'>
<small>Title</small>
</th>
<th scope='col'>
<small>Kind</small>
</th>
<th scope='col'>
<small>Size</small>
</th>
<th scope='col'>
<small>Strength</small>
</th>
<th scope='col'>
<small>Combinations</small>
</th>
<th scope='col'>
<small>Favors</small>
</th>
<th scope='col'>
<small>Stock</small>
</th>
<th scope='col'>
<small>Carousel</small>
</th>
<th scope='col'>
<small>Owner</small>
</th>
<th scope='col'>
<small>Edit</small>
</th>
<th scope='col'>
<small>Delete</small>
</th>
</tr>
</thead>
<Items
files={currentFiles}
loading={loading}
yourUploads={yourUploads}
/>
</table>
<Pagination
filesPerPage={filesPerPage}
totalFiles={files.length}
paginate={paginate}
/>
</div>
</Fragment>
);
};
Items component
const Items = ({ files, loading, yourUploads }) => {
const [myUploads, setMyUploads] = useState([]);
const [editable, setEditable] = useState(false);
const [rowData, setRowData] = useState({
kind: { str: '', row: '' },
});
const { kind } = rowData;
useEffect(() => {
const fetchMyUploads = async () => {
const res = await fetch('http://localhost:5000/api/files/all/mine', {
method: 'GET',
});
const data = await res.json();
setMyUploads(data);
};
fetchMyUploads();
}, [files]);
const onChange = (e) => {
setRowData({ ...rowData, [e.target.name]: e.target.value });
};
const onSubmit = async (e, file_id) => {
e.preventDefault();
if (!editable) {
setEditable(!editable);
} else {
await fetch(`http://localhost:5000/api/files/${file_id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(rowData),
});
setEditable(!editable);
}
};
if (loading) {
return (
<tbody>
<tr>
<td>loading...</td>
</tr>
</tbody>
);
}
const list = yourUploads
? myUploads.map((file) => (
<tr key={file._id}>
<td>
<small>{file.title}</small>
</td>
<td>
<small>{file.kind}</small>
</td>
<td>
<small>{file.size}</small>
</td>
<td>
<small>{file.strength}</small>
</td>
<td>
<small>{file.combinations}</small>
</td>
<td>
<small>{file.favors}</small>
</td>
<td>
<small
className={file.availability ? 'alert-success' : 'alert-danger'}
>
{file.availability ? 'in stock' : 'out of stock'}
</small>
</td>
<td>
<small>{file.isCarousel ? 'carousel' : 'not caorousel'}</small>
</td>
<td>
<small>{file.owner}</small>
</td>
<td>
<button className='btn btn-dark'>
<small>edit</small>
</button>
</td>
<td>
<button className='btn btn-danger'>
<small>delete</small>
</button>
</td>
</tr>
))
: files.map((file, index) => (
<tr key={file._id}>
<td>
<small>{file.title}</small>
</td>
<td>
<small>
{editable ? (
<input
type='text'
name='kind'
value={kind.str}
row={index}
onChange={(e) => onChange(e)}
/>
) : (
file.kind
)}
</small>
</td>
<td>
<small>{file.size}</small>
</td>
<td>
<small>{file.strength}</small>
</td>
<td>
<small>{file.combinations}</small>
</td>
<td>
<small>{file.favors}</small>
</td>
<td>
<small
className={file.availability ? 'alert-success' : 'alert-danger'}
>
{file.availability ? 'in stock' : 'out of stock'}
</small>
</td>
<td>
<small>{file.isCarousel ? 'carousel' : 'not carousel'}</small>
</td>
<td>
<small>{file.owner}</small>
</td>
<td>
<button
className='btn btn-dark'
onClick={(e) => onSubmit(e, file._id)}
>
<small>{editable ? 'save' : 'edit'}</small>
</button>
</td>
<td>
<button className='btn btn-danger'>
<small>delete</small>
</button>
</td>
</tr>
));
return <tbody>{list}</tbody>;
};
This error message usually comes up when you pass null or undefined to the input value prop. If value prop is empty, then react thinks it became uncontrolled component.
So you need to fix the error here.
arr.map((ele, index) => (
<tr>
<td><input type='text' name='kind' value={kind.str} row={index} onChange={e => onChange(e)}></td>
</tr>
))
Change value={kind.str} to value={rowData.kind.str}
Thanks everyone for answering my question. I was able to figure it out by splitting my components. So from my Items I render an Item component that renders the item and an Edit component that brings props in for that row only. By doing this I was able to eliminate the need for a row field which therefore gets rid of my error. React knows which row I am editing.

React method doesn't return table data to display

In React I have a ternary operator returning a component if a condition is met:
{ this.state.houseHoldGroup.length > 0 ? (
<Table className="align-items-center table-flush" responsive>
<thead className="thead-light">
<tr>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{this.checkHouseholdGroup()}
</tbody>
</Table>
) : null }
Works good.
Inside this component I have a method: this.checkHouseholdGroup()
The expected behavior is for this method to return the table data inside <tbody></tbody>
checkHouseholdGroup = () => {
const householdDetails = this.state.houseHoldGroup;
householdDetails.forEach(el => {
console.log(el.firstHousehold)
return (
<tr>
<th scope="row">{el.firstHousehold}</th>
<td>{el.lastHousehold}</td>
<td>
<Button
color="primary"
href="#pablo"
onClick={e => e.preventDefault()}
size="sm"
onClick={e => this.submitMember(e)}>
Update
</Button>
</td>
<td>
<Button
color="primary"
href="#pablo"
onClick={e => e.preventDefault()}
size="sm"
onClick={e => this.submitMember(e)}>
Delete
</Button>
</td>
</tr>
)
})
}
I can confirm the element has data. I console.log(el.firstHousehold) can see it's not empty. What am I doing wrong? The expected result would be that it would return my with the data in it.
Have you tried mapping instead of using forEach?
checkHouseholdGroup = () => {
const householdDetails = this.state.houseHoldGroup;
return householdDetails.map(el => {
console.log(el.firstHousehold)
return (
<tr>
<th scope="row">{el.firstHousehold}</th>
<td>{el.lastHousehold}</td>
<td>
<Button
color="primary"
href="#pablo"
onClick={e => e.preventDefault()}
size="sm"
onClick={e => this.submitMember(e)}>
Update
</Button>
</td>
<td>
<Button
color="primary"
href="#pablo"
onClick={e => e.preventDefault()}
size="sm"
onClick={e => this.submitMember(e)}>
Delete
</Button>
</td>
</tr>
)
})
}
Replace householdDetails.forEach with return householdDetails.map and you should be good.
forEach is used to create side effects - it does not return anything. The parent component of checkHouseholdGroup waits for a value to be returned, but nothing comes out of the function.
Using return inside a forEach call will make the returned values go "nowhere". That's why you need to use map (ir returns a list with the elements), and then return the array.

want to retrieve the value of specific row in which button was clicked. but i am getting the last one

I have table so I want to retrieve key/value of specific row in which button was clicked.
componentDidMount() {
let com = this;
firebase
.database()
.ref()
.child("bills")
.once("value", snap => {
let items = [];
snap.forEach(childD => {
items.push({
balance: childD.val().balance,
bill_num: childD.val().bill_num,
date: childD.val().date,
key: childD.val().key,
name: childD.val().name,
total: childD.val().total
});
});
Array.prototype.push.apply(com.state.products, items);
com.setState({
products: com.state.products
});
});
}
open = e => {
e.preventDefault();
console.log("kal" + this.state.value);
};
handleChange=event=>{
this.setState({value: event.target.value});
}
render() {
return (
<table className="table table-striped">
<thead>
<tr>
<th scope="col">Bill number</th>
<th scope="col">Name</th>
<th scope="col">Date</th>
<th scope="col">Total</th>
<th scope="col">Balance</th>
<th scope="col">Delete</th>
<th scope="col">Open bill</th>
</tr>
</thead>
<tbody>
{console.log(this.state.products)}
{this.state.products.map((value, key) => (
<tr key={value.key}>
<th scope="row">{value.bill_num}</th>
<td>{value.name}</td>
<td>{value.date}</td>
<td>{value.total}</td>
<td>{value.balance}</td>
<td>
<form onSubmit={this.returnOrder}>
<input value={value.key} type="hidden" />
<button className="btn btn-danger" type="submit">
Return
</button>
</form>
</td>
<td>
<form onSubmit={this.open}>
<input value={value.key} onChange={this.handleChange} ref={ eKey => (this.inputeKey = eKey)} />
<button className="btn btn-info" type="submit">
Open
</button>
</form>
</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<Printout
keya={{
key: this.props.keyas
}}
/>
)}
);
}
}
Typically, tables in React are made from several components: whole table, row and for example buttons in row. So in table you place array of rows. Each row has it's child buttons. So you can send props to RowButtons child with information about clicked row.

Resources