Setting conditional onClick behaviour in ReactJS - reactjs

(This is my first time using React)
I am working on app that filters videos based on the button click and this is the code below
const data = [{ address: 'https://www.youtube.com/watch?v=eIrMbAQSU34', category: 'java' },
{ address: 'https://www.youtube.com/watch?v=RRubcjpTkks', category: 'C#' }];
class User extends React.Component {
constructor(props){
super(props);
this.state={
videos : data,
};
}
render(){
return (
<div className="box">
<div className="buttons-filter">
<button onClick={()=>{
this.setState({videos: data })
}}>
All
</button>
<button id="btnJava" onClick={()=>{
this.setState({videos: data },
()=>{
this.setState({
videos: this.state.videos.filter(item => { return item.category === 'java';})
})
})
}}>
Java
</button>
<button id="btnReact" onClick={()=>{
this.setState({videos: data },
()=>{
this.setState({
videos: this.state.videos.filter(item => {return item.category==='React';})
})
})
}} >
React
</button>
</div>
<div className="content">
<div className="wrapper">
{this.state.videos.map(video => (
<ReactPlayer className="vid" url={video.address} controls={true} height="300" width="350" />
))}
</div>
</div>
<div className='bottom-btn'>
{/* <a className='btn-logout'><Link to="/Login" className='link'>Logout</Link></a> */}
</div>
</div>
);
}
};
export default User;
I was thinking of a way to reduce redundancy in my code, so I want to add an onclick function, semthing like
onClick(){
if(button.id === 'btnJava')
{
this.setState({videos: this.state.videos.filter(item => {
return item.category === 'java';})})
}
else if()
{}
}
Any idea if and how JSX handles a situation like this?

You can have one function to handle all cases based on the button value:
handleClick = (event) => {
const value = event.target.value;
this.setState({ videos: this.state.videos.filter(item => {
return item.category === value
})
})
}
<button value="java" onClick={this.handleClick}>Java</button>
<button value="React" onClick={this.handleClick}>React</button>

The idea is good to abstract the button click into its own function.
onClick passes event as a value to the function and you can get the id or value or which ever attribute from that.
If you are going to use
this.setState({videos: this.state.videos.filter(item => {
return item.category === 'java';
})
The your are going to loose your original video state after filtering.
I would recommend storing the filtered state into a different variable. This way you have the option to reset the filter.
Combining the answer from HermitCrab
this.state={
videos : data,
filtered: data
};
...
handleClick = (event) => {
const value = event.target.value;
this.setState({ filtered: this.state.videos.filter(item => {
return item.category === value
})
})
}
...
<div className="box">
<div className="buttons-filter">
<button value="java" onClick={this.handleClick}>Java</button>
<button value="React" onClick={this.handleClick}>React</button>
</div>
<div className="content">
<div className="wrapper">
{this.state.filtered.map(video => (
<ReactPlayer className="vid" url={video.address} controls={true} height="300" width="350" />
))}
</div>
</div>

Related

Hide all div and show one div on clicking multiple button

I am trying to fit 3 component in a single page by hiding/showing on a div.But I am not really getting into how to do it.This is the first div.
<div>
<p>What is the type of your property?</p>
<button >Residence</button>
<button>Commercial</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
Only If i click the 'Commercial' or 'Next' button it would go into the second div and first div will hide.
<div>
<p>What is the type of your commercial property?</p>
<button>Office</button>
<button>Restaurant</button>
<button >Outlet</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
and lastly if i click 'restaurant' button from the first div and any button of the second div except the back button it will go into the third div and other div will hide.this is the third div.
<div>
<div className='slider' style={{ marginTop:'165px',marginLeft:'319px',width:'700px',backgroundColor:'EF5350'}} >
<Slider min={850} max={5000} value={value} onChangeStart={this.handleChangeStart}
onChange={this.handleChange}
onChangeComplete={this.handleChangeComplete}
/>
<div className='value'>{value} Squarefeet</div>
<div style={{marginTop:'86px'}}>
<span onChange={this.handleChange} onClick={() => this.saveValue()} >Next</span>
<span onChange={this.handleChange} onClick={() => this.saveValue()} >Next</span>
</div>
</div>
</div>
I tried to do it this way. But it will not work.
import React from 'react';
import Link from "next/link";
class Jh extends React.Component {
constructor() {
super();
this.state = {
shown: true,
hide: false
};
}
toggle() {
this.setState({
shown: !this.state.shown
});
}
toggles() {
this.setState({
shown: !this.state.hide
});
}
render() {
var shown = {
display: this.state.shown ? "block" : "none"
};
var hidden = {
display: this.state.shown ? "none" : "block"
}
return (
<div>
<button onClick={this.toggle.bind(this)} style={ shown }>
<div>
<p>What is the type of your property?</p>
<button >Residence</button>
<button>Commercial</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
</button>
<button onClick={this.toggles.bind(this)} style={ hidden }>
<div>
<p>What is the type of your commercial property?</p>
<button>Office</button>
<button>Restaurant</button>
<button >Outlet</button>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Back</span>
<span style={{background:'transparent', border:'0', fontSize:'16px',color:'#ef3530'}}>Next</span>
</div>
</button>
</div>
)
}
}
export default Jh
What should be my approach?
There are many patterns to achieve a "switch case", I'll try to show my favorites:
For sipmlicity, I'll use a generic use case.
Straight Forward
Managing visible state for every component:
return {visible && <CoolComponent id={1} />};
Switch case in disguise
Manage a state of object keys. (currentCounter)
const countersPicker = {
counter1: <Counter id={1} />,
counter2: <Counter id={2} />,
coolComponent: <CoolComponent id={3} />
};
return {countersPicker[currentCounter]};
Here you also can take action on the object, for example, adding a header:
return {Object.entries(countersPicker).map(([key,component]) =>
<div key={key}>
<h1>Component key = {key}</h1>
{component}
</div>
)};
Filter Children
Manage a predicate and use it for filtering/mapping the children.
Check React.Children API.
return (
<FilterComponents predicate={predicate}>
<Counter key={1} id={1} />
<Counter key={2} id={2} />
<CoolComponent key={3} id={3} />
<BestComponent key={4} id={4} />
</FilterComponents>
);
function FilterComponents({ children, predicate }) {
const filteredChildren = React.Children.toArray(children).filter(child =>
// Use the predicate.
// Filter a child by key, key & type or even use ref etc.
);
return <div>{filteredChildren}</div>;
}
I believe you are looking for something like this.
Main things to-do:
Enhance your state-value. Keep track of the different pages in sequence by using an array. Track the current page. Track the start and end of the collection.
Here is the sandbox as well: https://codesandbox.io/s/unruffled-sun-gpzx6
import React from "react";
class Pages extends React.Component {
state = {
currentPage: "property",
pages: ["property", "type", "firstBusiness"],
start: true,
end: false
};
changePage = event => {
const { currentPage, pages } = this.state;
const { name } = event.target;
//check if we are going to end
if (
name == "next" &&
pages[pages.indexOf(currentPage) + 1] === pages[pages.length - 1]
) {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
end: true,
start: false
});
//go to next page
} else if (name == "next") {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
start: false
});
//check if we are going to beginning
} else if (
name == "back" &&
currentPage !== pages[0] &&
pages[pages.indexOf(currentPage) - 1] == pages[0]
) {
this.setState({
currentPage: pages[pages.indexOf(currentPage) - 1],
start: true
});
//go back one page
} else {
this.setState({
currentPage: pages[pages.indexOf(currentPage) - 1],
end: false
});
}
};
goToNextPage = () => {
const { currentPage, pages, end } = this.state;
//check if we are going to end
if (pages[pages.indexOf(currentPage) + 1] === pages[pages.length - 1]) {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
end: true,
start: false
});
//go to next page
} else if (end) {
return;
} else {
this.setState({
currentPage: pages[pages.indexOf(currentPage) + 1],
start: false
});
}
};
render() {
const { currentPage, start, end } = this.state;
return (
<div style={{ background: "gray" }}>
{currentPage === "property" ? (
<div>
<p>What is the type of your property?</p>
<button onClick={this.goToNextPage}>Residence</button>
<button onClick={this.goToNextPage}>Commercial</button>
</div>
) : null}
{currentPage === "type" ? (
<div>
<p>What is the type of your commercial property?</p>
<button onClick={this.goToNextPage}>Office</button>
<button onClick={this.goToNextPage}>Restaurant</button>
<button onClick={this.goToNextPage}>Outlet</button>
</div>
) : null}
{currentPage === "firstBusiness" ? (
<div>
<p>Is this your first business?</p>
<button onClick={this.goToNextPage}>Yes</button>
<button onClick={this.goToNextPage}>No</button>
</div>
) : null}
<div>
<button onClick={this.changePage} name="back" disabled={start}>
Back
</button>
<button onClick={this.changePage} name="next" disabled={end}>
Next
</button>
</div>
</div>
);
}
}
export default Pages;
So essentially you want router like functionality. Here is one approach:
class FirstPage extends React.Component {
render() {
//...first page content
}
}
class SecondPage extends React.Component {
render() {
//...second page content
}
}
const pages = {
first: FirstPage,
second: SecondPage
};
class App extends React.Component {
constructor() {
this.state = {
page: 'first'
};
}
render() {
const PageComponent = pages[this.state.page];
return <div>
<button onClick={() => this.setState({page: 'first'})}>First page</button>
<button onClick={() => this.setState({page: 'second'})}>Second page</button>
<PageComponent/>
</div>
}
}
There are many ways to solve this problem. But in my opinion the best solution is the one which solves the problem in a succinct manner.
Please find below the working solution which I have tried and works like a charm:
import React from "react";
class Pages extends React.Component {
state = {
activeTab: 1
};
toggle = tab => {
this.setState({
activeTab: tab
});
};
togglePage = page => {
if (page === "next") {
this.setState({
activeTab: this.state.activeTab + 1
});
} else if (page === "back") {
this.setState({
activeTab: this.state.activeTab - 1
});
}
};
render() {
return (
<div style={{ background: "#dedede" }}>
<div hidden={this.state.activeTab === 1 ? false : true}>
<p>1) What is the type of your property?</p>
<button class="btn btn-primary" onClick={() => this.toggle(2)}>
Residence
</button>
<button onClick={() => this.toggle(2)}>Commercial</button>
</div>
<div hidden={this.state.activeTab === 2 ? false : true}>
<p>2) What is the type of your commercial property?</p>
<button onClick={() => this.toggle(3)}>Office</button>
<button onClick={() => this.toggle(3)}>Restaurant</button>
<button onClick={() => this.toggle(3)}>Outlet</button>
</div>
<div hidden={this.state.activeTab === 3 ? false : true}>
<p>3) Is this your first business?</p>
<button onClick={this.NextAction}>Yes</button>
<button onClick={this.NextAction}>No</button>
</div>
<div>
<button
onClick={() => this.togglePage("back")}
name="back"
disabled={this.state.activeTab === 1 ? true : false}
>
Back
</button>
<button
onClick={() => this.togglePage("next")}
name="next"
disabled={this.state.activeTab === 3 ? true : false}
>
Next
</button>
</div>
</div>
);
}
}
export default Pages;
In react we have a hidden attribute which you can use to show/hide the elements without having to write any css for the same.
And I have tried to solve the problem with the least number of variables.
The sandbox for the same can be found here : https://codesandbox.io/s/mysolution-g8fu6
Hope this helps!

To Do List: Delete Button Removes Info from Wrong List Item

I am creating a basic React application which is essentially a to do list. The user can enter text and add an item to the list, which is an array that is rendered with the map method. Each item can be upvoted, downvoted, or deleted. The input text, number of upvotes, and number of downvotes are displayed on each item.
Here's the problem: When I click the delete button on an item, the input text from that item is deleted, but not the upvotes or downvotes. The upvotes and downvotes are always removed from the last item in the array. So when the list is re-rendered, the votes become all mixed up.
I've included the code from both my parent component (Category) and child component (Item). Sorry if it's a lot of code but I've had trouble pinpointing the source of the problem.
class Category extends Component {
state = {
inputValue: '',
items: this.props.items,
};
handleSubmit = e => {
e.preventDefault();
this.setState({ items: this.state.items.concat(this.state.inputValue) })
this.setState({ inputValue: "" })
}
updateInputValue(evt) {
this.setState({
inputValue: evt.target.value
});
}
handleDelete = index => {
const newItems = this.state.items.filter((item, i) => {
return index !== i;
});
return this.setState({ items: newItems });
}
render() {
return (
<div className="category">
<h2>{this.props.name}</h2>
<form onSubmit={this.handleSubmit}>
<input value={this.state.inputValue} onChange={e => this.updateInputValue(e)}/>
<button type="submit">Submit</button>
</form>
{/* Enter all items: */}
{this.state.items.length > 0 ?
this.state.items.map((item, index) => {
const key = index;
return <Item
key={key}
text={item}
handleDelete={this.handleDelete.bind(this, index)}
/>
}) : <p>There are no items here.</p>
}
</div>
)
}
}
class Item extends Component {
state = {
likes: 0,
dislikes: 0
}
handleUpvote = () => {
return this.setState({ likes: this.state.likes + 1 });
}
handleDownvote = () => {
return this.setState({ dislikes: this.state.dislikes + 1 });
}
render() {
return (
<div className="item">
<div className="move-item">
<FontAwesomeIcon icon="chevron-left" />
</div>
<div className="item-content">
<div className="item-text">
<p>{this.props.text}</p>
</div>
<div className="item-actions">
<div className="item-action-icon">
<button onClick={this.handleUpvote}>
<FontAwesomeIcon icon="thumbs-up" />
</button>
<span> {this.state.likes}</span>
</div>
<div className="item-action-icon">
<button onClick={this.handleDownvote}>
<FontAwesomeIcon icon="thumbs-down" />
</button>
<span> {this.state.dislikes}</span>
</div>
<div className="item-action-icon">
<button onClick={this.props.handleDelete}>
<FontAwesomeIcon icon="trash-alt" />
</button>
</div>
</div>
</div>
<div className="move-item">
<FontAwesomeIcon icon="chevron-right" />
</div>
</div>
)
}
}
You need to lift up your state of likes/dislikes to be associated with each item. Otherwise, each one will be associated by position (AKA index), and once you remove one item, the index that dissapears is the last one, causing you to mess up the votes
your parent state would be like
items: this.props.items.map(item => ({ item, likes: 0, dislikes. 0 });
handleUpvote and handleDownvote should be on your Category component, and passed by props to your Item, which will call them passing the item.
That way you can update your likes/dislikes

Reactjs component modal onclick div

I am trying to make a modal component which I can reuse, but I don't get what I am doing wrong here. The Modal is not appearing. Can anyone help me out?
Little explanation about my app.
This app is loading a JSON url and shows a list of products, which can be marked as done. If you click the div plaatjediv you should get a popup (the modal) with details info over the clicked product.
EDIT: Edited the code as suggested here. I can see the state change to true and false if I click the div, but the Modal is still not appearing.
my code
App.js
import React from 'react';
import ProductModal from './ProductModal.js';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleModal = this.toggleModal.bind(this);
this.state = {
isLoading: true,
orders: [],
dealtOrders: [],
open: false
}
}
toggleModal() {
this.setState({
open: !this.state.open
});
}
componentWillMount() {
localStorage.getItem('orders') && this.setState({
orders: JSON.parse(localStorage.getItem('orders')),
isLoading: false
})
}
componentDidMount() {
if (!localStorage.getItem('orders')){
this.fetchData();
} else {
console.log('Using data from localstorage');
}
}
fetchData() {
fetch('http://localhost:54408/api/orders/all/26-03-2018')
.then(response => response.json())
.then(parsedJSON => parsedJSON.map(product => (
{
productname: `${product.ProductName}`,
image: `${product.Image}`,
quantity: `${product.Quantity}`,
isconfirmed: `${product.IsConfirmed}`,
orderid: `${product.OrderId}`
}
)))
.then(orders => this.setState({
orders,
isLoading: false
}))
.catch(error => console.log('parsing failed', error))
}
render() {
this.handleDoneAction = event =>
{
let itemIndex = event.target.getAttribute("data-itemIndex");
let prevOrders = [...this.state.orders];
let dealtOrders = [...this.state.dealtOrders];
const itemToMoveAtLast = prevOrders.splice(itemIndex, 1);
const addToDealtOrders = dealtOrders.concat(itemToMoveAtLast);
this.setState({dealtOrders: addToDealtOrders});
this.setState({orders: prevOrders});
};
this.handleUndoAction = event =>
{
let itemIndex = event.target.getAttribute("data-itemIndex");
let orders = [...this.state.orders];
let dealtOrders = [...this.state.dealtOrders];
const undoDealtOrder = dealtOrders.splice(itemIndex, 1);
const addToOrders = orders.concat(undoDealtOrder);
this.setState({orders: addToOrders});
this.setState({dealtOrders: dealtOrders});
};
const {isLoading, orders, dealtOrders,open} = this.state;
return (
<div>
<header>
<img src="/images/header.jpg"/>
<h1>Boodschappenlijstje <button className="btn btn-sm btn-danger">Reload</button></h1>
</header>
<ProductModal open={open} />
<div className={`content ${isLoading ? 'is-loading' : ''}`}>
<div className="panel">
{
!isLoading && orders.length > 0 ? orders.map((order, index) => {
const {productname, image, quantity, orderid} = order;
return<div className="product" key={orderid}>
<div className="plaatjediv" onClick={this.toggleModal}>
<img className="img-responsive" src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
</div>
<div className="bdone">
<button className="btn btn-lg btn-default btndone" data-itemIndex={index} onClick={this.handleDoneAction}>Done</button>
</div>
</div>
}) : null
}
</div>
<h2>Mandje</h2>
<div className="panel">
{
!isLoading && dealtOrders.length > 0 ? dealtOrders.map((dorder, index) => {
const {productname, image, quantity, orderid} = dorder;
return<div className="productDone" key={index}>
<div className="plaatjediv">
<img className="img-responsive" src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
</div>
<div className="bdone">
<button className="btn btn-lg btn-default btndone" data-itemIndex={index} onClick={this.handleUndoAction}>Undo</button>
</div>
</div>
}) : null
}
</div>
<div className="loader">
<div className="icon"></div>
</div>
</div>
</div>
);
}
} export default App;
ProductModal.js
import React from 'react';
class ProductModal extends React.Component {
constructor() {
super();
}
render() {
const open = this.props.open;
return (
<div className={'modal fade'+(open ? '' : 'hide')} tabindex="-1" role="dialog">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 className="modal-title">test</h4>
</div>
<div className="modal-body">
test
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" className="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
)
}
}
export default ProductModal;
I am unsure what your issue is from your question but I am guessing your model doesn't open?
When you set state, you need to set it to the opposite of this.state.open
You can do it like this:
toggleModal() {
this.setState({
open: !this.state.open
});
}
I can't see where the modal is supposed to be rendered. You have to add it to render function of your "App" class. like this:
render() {
...
return(
<ProductModal open={true} />
...
):
}
and also, in your toggleModal function, do something like this:
this.setState({ open: !this.state.open});
Hope this solves the issue.
The issue is that you do not have your <ProductModal /> as a component in your <App /> In addition to setting your open state, once shown, it will (or should) never hide because you will not be able to toggle it again using your button, and you also do not have any keybindings within your <ProductModal /> itself.
I would suggest you bind an event listener within <ProductModal /> to
Check is ESC key is pressed
Bind a Cancel/Close button (in addition to a header x button).
Listen for if anywhere outside of your dialog is clicked, dismiss the modal.
You will also need to pass a handler from <App /> down to <ProductModal /> to notify when the modal has been closed.
In your App.js
handleClose() {
this.setState({
open: false
});
}
render() {
return (
...
<ProductModal open={this.state.open} handleClose={this.handleClose.bind(this)} />
)
}
Then in your ProductModal.js
handleClose() {
this.props.handleClose();
}
Observe the following using my sandbox:
https://stackblitz.com/edit/react-98m4cr
You'll see that I've implemented the handleClose event to control the state back up to the parent. In addition, you may want to add listeners as mentioned above, all triggering handleClose in the end; just remember to unbind them in ProductModal.js componentWillUnmount.

Updating props in note taking app in React

I'm stuck on my note taking app. Basically the App component passes in data to the NoteEntry component through props. Yet I can't figure out how to edit the previous passed text through props within each NoteEntry instance when I click the "edit" button. The edit button is supposed to bring up text inputs to change the content by updating the text and then pressing the save button. Any tips on how to go about it?
class App extends Component {
constructor(props) {
super(props);
this.state = {
notes: [],
title: "",
details: ""
}
this.updateTitle = this.updateTitle.bind(this);
this.updateDetails = this.updateDetails.bind(this);
this.submitHandler = this.submitHandler.bind(this);
this.deleteHandler = this.deleteHandler.bind(this);
}
updateTitle(event) {
this.setState({ title: event.target.value });
}
updateDetails(event) {
this.setState({ details: event.target.value });
}
submitHandler(e) {
e.preventDefault();
if (!this.state.title.length || !this.state.details.length) {
return;
}
const newNote = {
newTitle: this.state.title,
newDetails: this.state.details
}
this.setState(prevState => ({
notes: prevState.notes.concat(newNote),
title: "",
details: ""
}))
}
deleteHandler(id) {
this.setState(prevState => ({
notes: prevState.notes.filter(el => el !== id)
}))
}
render() {
return (
<div className="container">
<h1 className="title">React Notes App</h1>
<NoteForm
titleValue={this.state.title}
detailsValue={this.state.details}
titleHandle={this.updateTitle}
detailsHandle={this.updateDetails}
onSubmit={this.submitHandler}
/>
<div className="entry-section">
{this.state.notes.map((note, i) => (
<NoteEntry
key={i}
title={note.newTitle}
details={note.newDetails}
deleteNote={this.deleteHandler.bind(this, note)}
/>
))}
</div>
</div>
);
}
}
const NoteForm = (props) => {
return (
<div>
<form className="form-section">
<input
className="title-input"
type="type"
placeholder="Title"
value={props.titleValue}
onChange={props.titleHandle}
/>
<br />
<textarea
className="details-input"
cols="20"
rows="3"
placeholder="Details"
value={props.detailsValue}
onChange={props.detailsHandle}
/>
<br />
<button
className="input-button"
onClick={props.onSubmit}
>Add Note</button>
</form>
</div>
)
}
class NoteEntry extends Component {
constructor(props) {
super(props);
this.state = {
display: false,
editTitle: this.props.title,
editDetails: this.props.details,
editing: false
}
this.displayToggle = this.displayToggle.bind(this);
this.edit = this.edit.bind(this);
this.save = this.save.bind(this);
}
displayToggle() {
this.setState(prevState => ({
display: !prevState.display
}))
}
edit() {
this.setState({
editing: true
})
}
save() {
let titleVal = this.refs.updateTitle.value;
let detailsVal = this.refs.updateDetails.value;
this.setState({
editTitle: titleVal,
editDetails: detailsVal,
editing: false
})
}
render() {
return (
<div className="entry">
<div className="entry-header" onClick={this.state.editing ? null : this.displayToggle}>
{this.state.editing ? (
<input ref="updateTitle" className="edit-title" type="text" />
) : (
<h2 className="entry-title">{this.props.title}</h2>
)}
<p className="timestamp">{this.displayTime}</p>
</div>
<hr />
<div className={"entry-content " + (!this.state.display ? "hide-details" : null)}>
{this.state.editing ? (
<textarea ref="updateDetails" className="edit-details" cols="10" rows="2"></textarea>
) : (
<p className="details">{this.props.details}</p>
)}
<div className="entry-buttons">
{this.state.editing ? (
<button className="save" onClick={this.save}>Save</button>
) : (
<button className="edit" onClick={this.edit}>Edit</button>
)
}
<button className="delete" onClick={this.props.deleteNote}>Delete</button>
</div>
</div>
</div>
)
}
}
You can do by pass data from child to parent component as mention it in comment.
In you case NoteEntry add onEditNote props. This props use for function by parent (App component) and use by onClick edit button.
<NoteEntry
...
onEditNote={this.handleClickEdit}
/>
then in class NoteEntry
<button className="edit" onClick={() => this.props.handleClickEdit(this.props.title, this.props.detail)}>Edit</button>
So, handleClickEdit handle by App component and set it to your state
handleClickEdit = (_title, _detail) => {
this.setState({title: _title, details: _detail});
}
Now, your NoteForm component able to edit.

React: change order list when button clicked

I am making my first app with Javascript and React and started with a page which views a shopping list. It gets the items from an api call.
If the user clicks on the button 'done' (or should I use an checkbox?) This product should go to the bottom of the list (and be grayed out with css but thats not the problem).
The problem is, I have no clue how to do this. Can anyone help me out a bit?
This is my code:
import React from 'react';
//import image from '../images/header.png';
//import Collapsible from './Collapsible';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
orders: []
}
}
componentWillMount() {
localStorage.getItem('orders') && this.setState({
orders: JSON.parse(localStorage.getItem('orders')),
isLoading: false
})
}
componentDidMount() {
if (!localStorage.getItem('orders')){
this.fetchData();
} else {
console.log('Using data from localstorage');
}
}
fetchData() {
fetch('http://localhost:54408/api/orders/all/15-03-2018')
.then(response => response.json())
.then(parsedJSON => parsedJSON.map(product => (
{
productname: `${product.ProductName}`,
image: `${product.Image}`,
quantity: `${product.Quantity}`,
isconfirmed: `${product.IsConfirmed}`,
orderid: `${product.OrderId}`
}
)))
.then(orders => this.setState({
orders,
isLoading: false
}))
.catch(error => console.log('parsing failed', error))
}
componentWillUpdate(nextProps, nextState) {
localStorage.setItem('orders', JSON.stringify(nextState.orders));
localStorage.setItem('ordersDate', Date.now());
}
render() {
const {isLoading, orders} = this.state;
return (
<div>
<header>
<img src="/images/header.jpg"/>
<h1>Boodschappenlijstje <button className="btn btn-sm btn-danger">Reload</button></h1>
</header>
<div className={`content ${isLoading ? 'is-loading' : ''}`}>
<div className="panel">
{
!isLoading && orders.length > 0 ? orders.map(order => {
const {productname, image, quantity, orderid} = order;
return<div className="product" key={orderid}>
<div className="plaatjediv">
<img className="plaatje" src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
<p>ID: {orderid}</p>
</div>
<div className="bdone">
<button className="btn btn-sm btn-default btndone">Done</button>
</div>
</div>
}) : null
}
</div>
<div className="loader">
<div className="icon"></div>
</div>
</div>
</div>
);
}
}
export default App;
You can achieve by using this :
this.handleDoneAction = event = > {
let itemIndex = event.target.getAttribute("data-itemIndex");
let prevOrders = [...this.state.orders];
var itemToMoveAtLast = prevOrders.splice(itemIndex, 1);
var updatedOrderList = prevOrders.concat(itemToMoveAtLast);
this.setState({order: updatedOrderList})
}
I have attach an event handler on the button handleDoneAction.
<button className="btn btn-sm btn-default btndone" data-itemIndex={index} onClick={this.handleDoneAction}>Done</button>
the attribute data-itemIndex is the index of the object in orders array.
And your map function will be like this:
orders.map((order, index) => {
//content
})
ANd for the different style effects on the done products, I will suggest you to use different array for all done products.

Resources