I am fetching data from a backend endpoint and I want to display this data by using a component I found that takes as props the columns and the rows. I went ahead and created the columns(header) but I don't know how to handle the json response as it's array of objects.
Before I used a for the columns and with the map function to sort the data to rows. The objects have more than just 6 columns but I only wanted to display the important ones.
Take a look in my code to see the previous method I used and please provide any help how I can do it with the new way.
const Trademarks = () => {
const navigate = useNavigate();
const user = useUser();
const [trademarks, setTrademarks] = useState(null);
useEffect(() => {
obtainFromServer("api/trademarks", "GET", user.jwt).then(trademarksData => {
setTrademarks(trademarksData);
});
if(!user.jwt){
navigate("/login");
}
},[user.jwt]);
const trademarksColumns = {
columns: [
{ Header: "action", accessor: "id", width: "7%" },
{ Header: "cy number", accessor: "cynumber", width: "13%" },
{ Header: "ir number", accessor: "irnumber", width: "16%" },
{ Header: "Date Publish", accessor: "dtpublish", width: "15%" },
{ Header: "Status", accessor: "status", width: "15%" },
{ Header: "Notes", accessor: "notes" },
],
}
const trademarksRows = {
rows: [
{
id: "i",
cynumber: "i",
irnumber: "i",
dtpublish: "i",
status: "i",
notes: "i",
},
{
id: "ai",
cynumber: "ai",
irnumber: "ai",
dtpublish: "ai",
status: "ai",
notes: "ai",
}
],
}
console.log(trademarks);
function getRolesFromJWT(){
if(user.jwt){
const decodedJwt = jwt_decode(user.jwt);
return decodedJwt.authorities;
}
return [];
}
function LogOut (){
fetch("/api/auth/logout").then((response) => {
if (response.status === 200) {
user.setJwt(null);
// navigate(0);
}
});
}
return (
<>
<Box my={3}>
<Table striped bordered hover variant="dark">
<thead>
<tr style={{ textAlign: 'center' }}>
<th>Action</th>
<th>CY Number</th>
<th>IR Number</th>
<th>Date Publish</th>
<th>Status</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{trademarks ? trademarks.map(trademark =>
<tr key={trademark.id} style={{ textAlign: 'center' }}>
<td><Link to={`/trademarks/${trademark.id}`}>View/Edit</Link></td>
<td>{trademark.cynumber}</td>
<td>{trademark.irnumber}</td>
<td>{trademark.dtpublish}</td>
<td>{trademark.status}></td>
<td>{trademark.notes}</td>
</tr>) : <></>}
</tbody>
</Table>
</Box>
<Box pt={6} pb={3}>
<Card>
<Box p={3} lineHeight={1}>
<Typography variant="h5" fontWeight="medium">
Datatable Search
</Typography>
</Box>
<DataTable columnsTitle={trademarksColumns} rowsData={trademarksRows} canSearch />
</Card>
</Box>
</>
);
};
export default Trademarks;
Basically, I need to put the JSON response but only the needed columns inside the constant trademarksRows inside the rows array. Lastly for each row previously I included a button so the user can navigate to the trademark by the id.
What's the best way to solve my problem and how can I do that?
Finally, figure it out. This is how I did it.
const [trademarksRows, setTrademarksRows] = useState({
rows: [],
})
useEffect(() => {
obtainFromServer("api/trademarks", "GET", user.jwt).then(trademarksData => {
setTrademarks(trademarksData);
let rowsTr = trademarksData.map(trademarkData => ({
id: <MDButton color="secondary" onClick={() => (navigate(`/trademarks/${trademarkData.id}`))}>View/Edit</MDButton>,
cynumber: trademarkData.cynumber,
irnumber: trademarkData.irnumber,
dtpublish: trademarkData.dtpublish,
status: <StatusBadge text={trademarkData.status}/>,
notes: trademarkData.notes,
}));
setTrademarksRows({rows:rowsTr});
});
},[]);
Related
i have crated a react table , to display my product variation showing its id , variation sunch weight,width,height and so on, also its price and add to cart button in the table, I wanted to loop the header so that , the each variation name is a header in the table. i have save the data in state . below is my code of table function which I created
<table {...getTableProps()} className="w-100">
<thead>
{headerGroups.map((headerGroup) => (
<tr key={headerGroup.id} {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th
className={classnames(
" text-left pl-0 rt-th rt-resizable-header",
{
"-cursor-pointer": column.sortable,
"-sort-asc": column.isSorted && !column.isSortedDesc,
"-sort-desc": column.isSorted && column.isSortedDesc,
}
)}
key={column.id}
{...column.getHeaderProps()}
>
<div
className="rt-resizable-header-content"
{...(column.sortable && {
...column.getHeaderProps(column.getSortByToggleProps()),
})}
>
{column.render("Header")}
</div>
{/* Render the columns filter UI */}
<div>
{column.canFilter ? column.render("FilterColumn") : null}
</div>
</th>
))}
</tr>
))}
</thead>
<tbody className="text-left" {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row);
return (
<tr
key={row.id}
{...row.getRowProps()}
className={classnames(
"rt-tr text-break",
{ " -odd": i % 2 === 0 },
{ " -even": i % 2 === 1 }
)}
>
{row.cells.map((cell) => (
<td key={row.id} {...cell.getCellProps()}>
{cell.render("Cell")}
</td>
))}
</tr>
);
})}
</tbody>
</table>
below is how I save my data in the data state using useEFFECT inreact
React.useEffect(() => {
setDataState(
variation.map((variations) => ({
sn: variations.VariationSKU,
snId: <p className="megan-text">{variations.VariationSKU}</p>,
attributes: variations.Attributes.map((attribute) => (
<td key={attribute.ID} className="text-dark text-center">
<p className="mr-5">{attribute.Value}</p>
</td>
)),
price: <CurrencyFormat price={variations.Price} currency="MYR" />,
action: (
<Button
id="Sproduct-btn"
className={`btn add-to-cart w-100 ${submitResponse.class} `}
data-toggle="tooltip"
type="button"
tag={!user ? Link : "a"}
to={!user ? "/login" : ""}
disabled={
submitResponse.openState ||
status === "Inactive" ||
variationstatus === "Inactive" ||
stock === 0 ||
variationstock === 0
}
style={{ fontSize: "15px", width: "30%" }}
{...(user && {
onClick: () => {
onSubmit(productid, variations.ID);
// setResponse(addToCart(productid, variation.ID));
},
})}
>
<div className="cart">
<div>
<div />
<div />
</div>
</div>
<div className="dots" />
{/* {variationStock === 0 || data.data.Stock === 0 ? (
<div className="pl-2 default">SOLD OUT</div>
) : (
<span className="pl-2 default">ADD TO BAG</span>
)} */}
<span className="pl-2 default">{result}</span>
<div className="success">ADDED</div>
<div className="failed">FAILED TO ADDED, PLEASE TRY AGAIN</div>
</Button>
),
}))
);
}, [submitResponse]);
const getTableHeaders = () =>
variation.map((varian) =>
varian.Attributes.map((attribute) => ({
id: attribute.ID,
Header: attribute.Name,
accessor: String(attribute.Value),
sortable: true,
}))
);
these are how I call the data in where I wanted the attribute name, and value in their own column in the table. Currently, my variation are in 1 column but I wanted each attributes have its own column which I don't know how to do, can anyone pls help, thank you
{dataState !== [] && (
<Table
responsive
columns={[
{
Header: "SN",
accessor: "snId",
sortable: true,
},
{
...getTableHeaders(),
},
{
Header: "Price",
accessor: "price",
sortable: true,
},
{
Header: "",
accessor: "action",
},
]}
data={dataState}
className="-striped -highlight primary-pagination font-weight-bold"
/>
)}
this how my table looks like
these the response of variation which I used in getTableHeader
"VariationList": [
{
"ID": "63eaf4417f339ebdb324fe33",
"VariationSKU": "102100489N",
"Price": 2250,
"Attributes": [
{
"ID": "63eaf3167f339ebdb324efa9",
"Name": "Hook",
"Value": "CAKUK S"
},
{
"ID": "63eaf3167f339ebdb324efa7",
"Name": "Weight",
"Value": 3.8
},
{
"ID": "63eaf3167f339ebdb324efaa",
"Name": "Length",
"Value": 28
},
{
"ID": "63eaf3167f339ebdb324efa4",
"Name": "Width",
"Value": 1.3
}
],
},{},{},{},{}
[![enter image description here][2]][2]
Looks like you're only returning one column object for all three attributes. Rather than doing a map inside 1 column object, you could do a map outside. You should also have an id field in all columns with accessors - I would suggest a function like:
const getTableHeaders = (attributelist) =>
attributelist.map((attribute) => ({
id: attribute.ID,
Header: attribute.Name,
accessor: String(attibute.Value),
sortable: true,
}));
And then, you could use it like this:
columns = {[
{
Header: "SN",
accessor: "snId",
sortable: true,
},
...getTableHeaders(attributelist),
{
Header: "Price",
accessor: "price",
sortable: true,
},
{
Header: "",
accessor: "action",
},
]};
The key thing you're missing is that you should have 1 object per column, whereas you currently have 1 object for all 3 desired columns.
what I try to do is to have the same display as this picture :
So in my menu the plant type (Type of plant1) is displayed above a gray bar and when you click on the down chevron then you can see all the plants name, related to this type, with checkboxes on left, by default there will be all checked. And the blue rectangle indicates the number of plants that have been selected.
How can I do that, which package can help me in REACT?
Here my plants.json :
{
"plants_type": [
{
"_id_type": "1",
"name_type": "Type of plant1",
"plants": [
{
"name": "Plant1.1",
"_id": "2"
},
{
"name": "Plant1.2",
"_id": "3"
}
]
},
{
"_id_type": "4",
"name_type": "Type of plant2",
"plants": [
{
"name": "Plant2.1",
"_id": "5"
},
{
"name": "Plant2.2",
"_id": "6"
}
]
}
]
}
You can create a dropdown list on your own like below. I have added the logic of selecting items to the data itself.
You can keep a component called Category to keep a single state of the parent menu item. Whether it's open or not. Then iterate over the plants as checkbox inputs to make them selectable.
I have used a simple initialize function to make all the items selected initially. This should work as you expect. Add a console log of selectionMenu to see how selected property changes while toggling items.
Move the inline styles to CSS classes to make the code more clear.
const data = { plants_type: [ { _id_type: "1", name_type: "Type of plant1", plants: [ { name: "Plant1.1", _id: "2" }, { name: "Plant1.2", _id: "3" } ] }, { _id_type: "4", name_type: "Type of plant2", plants: [ { name: "Plant2.1", _id: "5" }, { name: "Plant2.2", _id: "6" } ] } ] };
const Category = ({ _id_type, name_type, plants, changeSelection }) => {
const [toggleState, setToggleState] = React.useState(false);
return (
<div key={_id_type}>
<div
style={{
cursor: "pointer",
userSelect: "none",
display: "flex",
margin: "2px",
backgroundColor: "lightgray"
}}
onClick={() => setToggleState((prev) => !prev)}
>
<div>{name_type}</div>
<div
style={{
backgroundColor: "blue",
color: "white",
padding: "0px 10px",
marginLeft: "auto"
}}
>
{plants.filter(({ selected }) => selected).length}
</div>
</div>
<div style={{ marginLeft: "10px" }}>
{toggleState &&
plants.map(({ name, _id, selected }) => (
<div key={_id}>
<input
key={_id}
type="checkbox"
value={name}
checked={selected}
onChange={(e) => changeSelection(_id_type, _id, e.target.value)}
/>
{name}
</div>
))}
</div>
</div>
);
};
const App = () => {
const initializeSelectionMenu = (data) => {
return data.map((item) => {
return {
...item,
plants: item.plants.map((plant) => ({ ...plant, selected: true }))
};
});
};
const [selectionMenu, setSelectionMenu] = React.useState(
initializeSelectionMenu(data.plants_type)
);
console.log(selectionMenu);
const changeSelection = (catId, itemId, value) => {
setSelectionMenu((prevSelectionMenu) =>
prevSelectionMenu.map((item) => {
if (item._id_type === catId) {
return {
...item,
plants: item.plants.map((plant) => {
if (plant._id === itemId) {
return { ...plant, selected: !plant.selected };
}
return plant;
})
};
}
return item;
})
);
};
return (
<div>
{selectionMenu.map((item) => (
<Category
{...item}
changeSelection={changeSelection}
key={item._id_type}
/>
))}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Here is my backend code
app.get("/sortedcustomers", (req, res) => {
db.query("SELECT * FROM customer_info ORDER BY contacted", (err, result) => {
if (err) {
console.log(err);
} else {
res.send(result);
}
});
});
which gives me data in this form:
[{"ID":1,"name":"Queen","email":"Queen#gmail.com","counts_of_visit":13,"latest_time_of_visit":"2021-03-12T12:08:23.000Z","contacted":"No"},{"ID":3,"name":"Alex","email":"Alex#gmail.com","counts_of_visit":7,"latest_time_of_visit":"2021-04-30T09:50:23.000Z","contacted":"No"},{"ID":2,"name":"Wayne","email":"Wayne#gmail.com","counts_of_visit":10,"latest_time_of_visit":"2021-04-30T09:50:23.000Z","contacted":"Yes"},{"ID":4,"name":"Jack","email":"Jack#gmail.com","counts_of_visit":3,"latest_time_of_visit":"2021-04-30T09:50:23.000Z","contacted":"Yes"}]
Then my frontend code:
function Home(props) {
const [customerList, setCustomerList] = useState([]); //store all that information of the database in a list
//make an axios request to get information from database
useEffect(() => {
Axios.get("http://localhost:3001/customers").then((response) => {
setCustomerList(response.data);
});
}, []);
const getSortedCustomerList = () => {
Axios.get("http://localhost:3001/sortedcustomers").then((response) => {
setCustomerList(response.data);
});
};
const updateCustomerContacted = (ID) => {
Axios.put("http://localhost:3001/update", {
contacted: newContacted,
ID: ID,
}).then((response) => {
setCustomerList(
customerList.map((val) => {
return val.ID == ID
? {
ID: val.ID,
name: val.name,
email: val.email,
counts_of_visit: val.counts_of_visit,
latest_time_of_visit: formatDatetime(val.latest_time_of_visit),
contacted: newContacted,
}
: val;
})
);
});
};
//function to format the datetime to correct format
const formatDatetime = (datetime) => {
const dateStr = new Date(datetime).toLocaleDateString("en-CA");
const timeStr = new Date(datetime).toLocaleTimeString();
return `${dateStr} ${timeStr}`;
};
const deleteCustomer = (ID) => {
Axios.delete(`http://localhost:3001/stats/delete/${ID}`).then(
(response) => {
setCustomerList(
customerList.filter((val) => {
return val.ID != ID;
})
);
}
);
};
//pagination
const [pageNumber, setPageNumber] = useState(0);
const customersPerPage = 5; //change this number according to desired number of rows in a page
const pagesVisited = pageNumber * customersPerPage;
const displayCustomers = customerList
.slice(pagesVisited, pagesVisited + customersPerPage)
.map((val, key) => {
const dateStr = new Date(val.latest_time_of_visit).toLocaleDateString(
"en-CA"
);
const timeStr = new Date(val.latest_time_of_visit).toLocaleTimeString();
const dateTime = `${dateStr} ${timeStr}`;
const my_serial = key + pageNumber * customersPerPage;
return (
<tr>
{/*}
<td>{val.ID}</td>
*/}
<td>{my_serial + 1}</td>
<td>{val.name}</td>
<td>{val.email}</td>
<td>{val.counts_of_visit}</td>
<td>{dateTime}</td>
<td>{val.contacted}</td>
<td>
<select
onChange={(event) => {
setNewContacted(event.target.value);
}}
>
<option value="" selected disabled hidden>
Select Yes/No
</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<button
className="btn btn-primary"
onClick={() => {
updateCustomerContacted(val.ID);
}}
>
Update
</button>
</td>
<td>
<button
className="btn btn-danger"
onClick={() => {
deleteCustomer(val.ID);
}}
>
Delete
</button>
</td>
</tr>
);
});
//to account for the fact that total number of customers cannot be divided equally among the pages
const pageCount = Math.ceil(customerList.length / customersPerPage);
//page change
const changePage = ({ selected }) => {
setPageNumber(selected);
};
//update contacted column
const [newContacted, setNewContacted] = useState(0);
//export to csv function
const DataSet = [
{
columns: [
{
title: "S/N",
style: { font: { sz: "18", bold: true } },
width: { wpx: 125 },
}, // width in pixels
{
title: "Customer Information",
style: { font: { sz: "18", bold: true } },
width: { wpx: 250 },
}, // width in pixels
{
title: "Customer Email",
style: { font: { sz: "18", bold: true } },
width: { wpx: 250 },
}, // width in pixels
{
title: "Counts of Visit",
style: { font: { sz: "18", bold: true } },
width: { wpx: 175 },
}, // width in pixels
{
title: "Latest Time of Visit",
style: { font: { sz: "18", bold: true } },
width: { wpx: 250 },
}, // width in pixels
{
title: "Contacted?",
style: { font: { sz: "18", bold: true } },
width: { wpx: 250 },
}, // width in pixels
],
data: customerList.map((val, key) => [
{ value: key + 1, style: { font: { sz: "14" } } },
{ value: val.name, style: { font: { sz: "14" } } },
{ value: val.email, style: { font: { sz: "14" } } },
{ value: val.counts_of_visit, style: { font: { sz: "14" } } },
{
value: formatDatetime(val.latest_time_of_visit),
style: { font: { sz: "14" } },
},
{ value: val.contacted, style: { font: { sz: "14" } } },
]),
},
];
return (
<div>
<GridItem xs={12} sm={12} md={12}>
<Card>
<CardHeader color="warning">
<h4 className={classes.cardTitleWhite}>Customer Information</h4>
<p className={classes.cardCategoryWhite}></p>
</CardHeader>
<CardBody>
<div className="dashboardcontainer">
<div className="container"></div>
<table className="customertable">
<thead>
<tr>
{/*}
<th>S/N</th>
*/}
<th>S/N</th>
<th>Customer Name</th>
<th>Customer Email</th>
<th>Counts of Visit</th>
<th>Latest Time of Visit</th>
<th onClick={getSortedCustomerList}>Contacted?</th>
<th>Edit Contacted</th>
<th>Action</th>
</tr>
</thead>
<tbody>{displayCustomers}</tbody>
</table>
<ReactPaginate
previousLabel={"Previous"}
nextLabel={"Next"}
pageCount={pageCount}
onPageChange={changePage}
containerClassName={"paginationBttns"}
pageLinkClassName={"paginationNumber"}
previousLinkClassName={"previousBttn"}
nextLinkClassName={"nextBttn"}
disabledClassName={"paginationDisabled"}
activeClassName={"paginationActive"}
/>
<ExcelFile
filename="Customer Information"
element={
<button
type="button"
className="btn btn-success float-right m-3"
>
Export to Excel
</button>
}
>
<ExcelSheet
dataSet={DataSet}
name="Customer Information Report"
></ExcelSheet>
</ExcelFile>
</div>
</CardBody>
</Card>
</GridItem>
</GridContainer>
</div>
);
}
But the thing about my frontend is that when I click on the "Contacted?" header column it does show the sorted data, but how do I make it show the reverse sorted list then the normal unsorted customer list on the last click. So first click sorted list works, but second click sorted reverse list doesn't work and 3rd click unsorted list doesn't work.
So, basically, I have this crud table, when I click contacted column, it sorts itself accordingly, but when I click again it does not sort in reverse order, then when I click again it does not go back to unsorted order, how to solve this?
try
customerList.sort(function(a, b) {
return b - a;
})
,or, if that doesn't work:
customerList.reverse()
I'm trying to do a simple filter based on input text, but it has a bug, when i press 'backspace', it should refilter based on the original arrays, not the previous filtered array. I know what the problem is: I changed the original tasks every time when it filters. And i know i should do something like making a copy of the original arrays and filter based on the copy. But i just don't know how to achieve that in react.
Below is my code:
export class Main extends Component {
constructor(pros) {
super(pros)
this.state = {
tasks: [
{
id: 1,
content: "Sara's doctor and vaccine",
due: '2020-08-29',
completed: false
},
{
id: 2,
content: "Trash bags / facial masks / child allowance",
due: '2020-08-28',
completed: false
},
{
id: 3,
content: "Apply for Portugal nationality",
due: '2020-09-31',
completed: false
},
{
id: 4,
content: "My registration card",
due: '2020-09-28',
completed: false
}
]
}
handleSearch = (e) => {
let searchValue = e.target.value
console.log(searchValue)
let filteredTasks = this.state.tasks.filter(task => {
return task.content.toLowerCase().includes(searchValue.toLowerCase())
})
this.setState(state => ({
tasks: filteredTasks
}))
}
render() {
return (
<div>
<div style={{ textAlign: 'right' }}><input type='search' onKeyUp={this.handleSearch} id='search' name='search' placeholder='Search Tasks' autoComplete='on' style={{ width: '60%', margin: '15px 15px 45px auto' }} /></div>
<table>
<caption>Good {this.state.dayPeriod}! ♥ {this.state.userName}</caption>
<thead>
<tr>
<th>
<button type='button' onClick={this.handleSelect}>Select All</button>
</th>
<th>ID</th>
<th>Content</th>
{/* <th>Created On</th> */}
<th>Due</th>
<th>Completed</th>
</tr>
</thead>
<tbody>
{this.state.tasks.reverse().map((el, i) => (
<tr key={i} className='row' style={{ textDecoration: el.completed ? this.state.textDecoration : 'none', color: el.completed ? this.state.color : '#000000' }}>
<td>
<input type='checkbox' checked={el.completed} onChange={() => { el.completed = !el.completed }}></input>
</td>
<td className='taskID' style={{ verticalAlign: 'text-top' }}>{el.id}</td>
<td className='taskContent'>{el.content}</td>
{/* <td style={{whiteSpace: 'nowrap'}}>{new Date().getFullYear()}-{new Date().getMonth().toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})}-{new Date().getDate().toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})}</td> */}
<td style={{ whiteSpace: 'nowrap' }}>{el.due}</td>
<td>{el.completed === false ? 'N' : 'Y'}</td>
</tr>
))}
{/* {this.listTasks()} */}
</tbody>
</table>
</div>
)
}
}
There are many ways to achieve what you are asking, but simplest way is to not change the state, only change what should be rendered.
On top of your code I've added the filter, so the state remains the same but only the filter applies on the results:
export class Main extends Component {
constructor(pros) {
super(pros)
this.state = {
tasks: [
{
id: 1,
content: "Sara's doctor and vaccine",
due: '2020-08-29',
completed: false
},
{
id: 2,
content: "Trash bags / facial masks / child allowance",
due: '2020-08-28',
completed: false
},
{
id: 3,
content: "Apply for Portugal nationality",
due: '2020-09-31',
completed: false
},
{
id: 4,
content: "My registration card",
due: '2020-09-28',
completed: false
}
],
searchValue: ""
}
handleSearch = (e) => {
this.setState({ searchValue: e.target.value })
}
filterResults = () => {
if(!this.state.searchValue) return this.state.tasks
return this.state.tasks.filter(task => {
return task.content.toLowerCase().includes(this.state.searchValue.toLowerCase())
})
}
render() {
return (
<div>
<div style={{ textAlign: 'right' }}><input type='search' onKeyUp={this.handleSearch} id='search' name='search' placeholder='Search Tasks' autoComplete='on' style={{ width: '60%', margin: '15px 15px 45px auto' }} /></div>
<table>
<caption>Good {this.state.dayPeriod}! ♥ {this.state.userName}</caption>
<thead>
<tr>
<th>
<button type='button' onClick={this.handleSelect}>Select All</button>
</th>
<th>ID</th>
<th>Content</th>
{/* <th>Created On</th> */}
<th>Due</th>
<th>Completed</th>
</tr>
</thead>
<tbody>
{filterResults().reverse().map((el, i) => (
<tr key={i} className='row' style={{ textDecoration: el.completed ? this.state.textDecoration : 'none', color: el.completed ? this.state.color : '#000000' }}>
<td>
<input type='checkbox' checked={el.completed} onChange={() => { el.completed = !el.completed }}></input>
</td>
<td className='taskID' style={{ verticalAlign: 'text-top' }}>{el.id}</td>
<td className='taskContent'>{el.content}</td>
{/* <td style={{whiteSpace: 'nowrap'}}>{new Date().getFullYear()}-{new Date().getMonth().toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})}-{new Date().getDate().toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})}</td> */}
<td style={{ whiteSpace: 'nowrap' }}>{el.due}</td>
<td>{el.completed === false ? 'N' : 'Y'}</td>
</tr>
))}
{/* {this.listTasks()} */}
</tbody>
</table>
</div>
)
}
}
You should extract original Task List out of state and always filter on that. That way you will have reference of all Tasks every time you filter. Something like this.
const allTasks = [
{
id: 1,
content: "Sara's doctor and vaccine",
due: '2020-08-29',
completed: false
},
{
id: 2,
content: "Trash bags / facial masks / child allowance",
due: '2020-08-28',
completed: false
},
{
id: 3,
content: "Apply for Portugal nationality",
due: '2020-09-31',
completed: false
},
{
id: 4,
content: "My registration card",
due: '2020-09-28',
completed: false
}
];
export class Main extends Component {
constructor(pros) {
super(pros)
this.state = {
tasks: allTasks
}
}
handleSearch = (e) => {
let searchValue = e.target.value
console.log(searchValue)
let filteredTasks = allTasks.filter(task => {
return task.content.toLowerCase().includes(searchValue.toLowerCase())
})
this.setState(state => ({
tasks: filteredTasks
}))
}
render() {
return (
<div>
<div style={{ textAlign: 'right' }}><input type='search' onKeyUp={this.handleSearch} id='search' name='search' placeholder='Search Tasks' autoComplete='on' style={{ width: '60%', margin: '15px 15px 45px auto' }} /></div>
<table>
<caption>Good {this.state.dayPeriod}! ♥ {this.state.userName}</caption>
<thead>
<tr>
<th>
<button type='button' onClick={this.handleSelect}>Select All</button>
</th>
<th>ID</th>
<th>Content</th>
{/* <th>Created On</th> */}
<th>Due</th>
<th>Completed</th>
</tr>
</thead>
<tbody>
{this.state.tasks.reverse().map((el, i) => (
<tr key={i} className='row' style={{ textDecoration: el.completed ? this.state.textDecoration : 'none', color: el.completed ? this.state.color : '#000000' }}>
<td>
<input type='checkbox' checked={el.completed} onChange={() => { el.completed = !el.completed }}></input>
</td>
<td className='taskID' style={{ verticalAlign: 'text-top' }}>{el.id}</td>
<td className='taskContent'>{el.content}</td>
{/* <td style={{whiteSpace: 'nowrap'}}>{new Date().getFullYear()}-{new Date().getMonth().toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})}-{new Date().getDate().toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})}</td> */}
<td style={{ whiteSpace: 'nowrap' }}>{el.due}</td>
<td>{el.completed === false ? 'N' : 'Y'}</td>
</tr>
))}
{/* {this.listTasks()} */}
</tbody>
</table>
</div>
)
}
}
It's better to change the handleSearch function to:
handleSearch = (e) => {
setState({searchValue: e.target.value})
}
and handle the filter in your map:
this.state.tasks.reverse()
.filter(task => task.content.toLowerCase().includes(searchValue.toLowerCase()))
.map(...
You are overriding the source data. You should keep an variable that store the source data
const TASK = [
{
id: 1,
content: "Sara's doctor and vaccine",
due: "2020-08-29",
completed: false
},
{
id: 2,
content: "Trash bags / facial masks / child allowance",
due: "2020-08-28",
completed: false
},
{
id: 3,
content: "Apply for Portugal nationality",
due: "2020-09-31",
completed: false
},
{
id: 4,
content: "My registration card",
due: "2020-09-28",
completed: false
}
];
// ...
constructor(pros) {
super(pros);
this.state = {
tasks: [...TASK]
};
}
handleSearch = (e) => {
let searchValue = e.target.value;
console.log(searchValue);
let filteredTasks = TASK.filter((task) => {
return task.content.toLowerCase().includes(searchValue.toLowerCase());
});
this.setState((state) => ({
tasks: filteredTasks
}));
};
// ...
Codesandbox demo
I have a problem with PouchDB with array values.
In my document on the DB I have:
"ExercisesData": [
{
"Id": "01",
"Reps": "10",
"StartDate": "2019-06-20",
"EndDate": "2019-06-21",
"Notes": ".........."
},
{
"Id": "02",
"Reps": "1",
"Notes": "........"
},
{
"Id": "03",
"Reps": "150",
"Notes": "........"
}
]
I need to print this values, and let choose one of these values (Id) at the user.
I've tried to take this values from the db in this way:
findUtente(cf) {
let params = {};
params = {
"Person.FiscalCode": cf
};
global.utente.db.localdb().find({
selector: {params},
})
.then(response => {
let utente = response.docs[0];
console.log(utente);
this.setState({ Id: utente.ExercisesData.Id })
console.log("utente.ExercisesData.Id: " + utente.ExercisesData.Id)
})
.catch(function(err) {
console.log(JSON.stringify(err));
});
}
render() {
console.log("this.state.Id: " + this.state.Id)
return(
<View>
<Text>{this.state.Id}</Text>
</View>
);
}
But this code go in the catch, give me back the error: {}
The problem should be that I'm trying to take the elements in wrong way. Maybe I should use the .Map param ?
How can I do to recover these value and print them in a page? Thank you.
I have solved in this way:
const exercises = this.state.Exercises.map(exercise => {
return (
<View>
<Text style={{ fontSize: 15 }}> {exercise.Id}</Text>
<Text style={{ fontSize: 15 }}> {exercise.Reps}</Text>
<Text style={{ fontSize: 15 }}> {exercise.Notes}</Text>