Getting error while closing the react-modal - reactjs

here when a user click on a picture of the UserProfile component, a modal opens with details about the picture. But when a user closes the modal, an error is generated.
Error:
Cannot read property 'uid' of undefined
at t.value (PostListItem.js:68)
I think t is trying to rendering postlistItem after modal close which should not happen as the content is set to '' while closing the modal.
//UserProfile
class UserProfile extends React.Component{
constructor(props){
super(props);
this.state = {
isFollowed: false,
content: undefined
}
}
componentDidMount(){
this.props.dispatch(usersFetchData(`http://localhost:5000/api/user/
${this.props.match.params.uid}`));
(Object.keys(this.props.user).length !== 0) &&
(this.props.user.followers.includes(this.props.currentUser.uid)) &&
this.setState({isFollowed: true});
}
componentWillUnmount(){
this.props.dispatch(resetUser());
}
onFollow = () =>{
if(this.state.isFollowed){
this.props.dispatch(removeFollower(this.props.user.uid,
this.props.currentUser.uid));
this.props.dispatch(removeFollowing(this.props.currentUser.uid,
this.props.user.uid));
this.setState({isFollowed: false});
}else{
this.props.dispatch(addFollower(this.props.user.uid, this.props.currentUser.uid));
this.props.dispatch(addFollowing(this.props.currentUser.uid,this.props.user.uid));
this.setState({isFollowed: true});
}
}
openModal = (post) => {
this.setState({content:post});
console.log(this.state);
}
closeModal = () =>{
this.setState(() => ({ content: '' }));
console.log(this.state);
}
render(){
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <p>Loading…</p>;
}
return(
<div className="userProfile">
<div>
{console.log(this.props.user)}
{ Object.keys(this.props.user).length !== 0 &&
<div className="user__details">
<div className="user__dp">
<div className="dp__container">
<img src={this.props.user.avatar} alt=
{this.props.user.name}/>
</div>
</div>
<div className="user__description">
<p className="user__name">
{this.props.user.name}</p>
<div className="user__button">
{(this.props.currentUser.uid ===
this.props.user.uid) ?
<button className="ef__button"><Link
to={`/${this.props.user.uid}/edit`}>Edit Profile</Link></button> :
<button
className="ef__button"
onClick={this.onFollow}>
{this.state.isFollowed? 'Following': 'Follow'}
</button>
}
</div>
</div>
</div>
}
</div>
<div className="user__bio">
<p>{this.props.user.bio}</p>
</div>
<div>
<h3>Posts</h3>
<div className="userContent">
{this.props.user.posts &&
this.props.user.posts.map((post) =>{
return(
<div className="userPost">
<img src={post.content} onClick={() =>
this.openModal(post)}/>
</div>
);
})
}
<ContentModal
content={this.state.content}
closeModal={this.closeModal}
/>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) =>{
console.log(state);
return{
currentUser: state.auth,
user: state.users,
hasErrored: state.usersHasErrored,
isLoading: state.usersIsLoading
}
};
export default connect(mapStateToProps)(UserProfile);
//contentModal
const ContentModal = (props) => (
<Modal
isOpen={!!props.content}
onRequestClose={props.closeModal}
shouldCloseOnOverlayClick={true}
shouldCloseOnEsc={true}
contentLabel="content"
closeTimeoutMS={200}
className="content__modal"
>
<div className="post__container">
{<PostListItem {...props.content}/>}
</div>
{console.log(props)}
</Modal>

You get the issue because intially the content is undefined and when you are closing the model the content is set to empty string so uid won't be available so call PostListItem only when content is not undefined and not empty.
Add the below condition in ContentModal component
{typeof props.content != "undefined" && props.content != "" && <PostListItem {...props.content}/>}

Related

Cannot read property 'key' of undefined react

Home.js component
import React, { Component } from 'react';
import axios from 'axios';
import styles from './home.module.css';
import TurnArrow from '../../assets/images/turn.svg';
import LoadingGif from '../../assets/images/loading.gif';
import SearchBox from '../SearchBox/SearchBox';
import RepoItem from '../RepoItem/RepoItem';
class Home extends Component {
constructor(props) {
super(props)
this.state = {
repos: [],
inputValue: "",
isEmptySearch: false,
isLoading: false,
per_page: 100,
limit: 10,
total_count: null,
showMore: true,
index: 10,
dataLoaded: false,
reposLength: null
}
this.myRef = React.createRef();
this.updateInputValue = this.updateInputValue.bind(this);
this.fetchRepos = this.fetchRepos.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
}
scrollToMyRef() {
window.scrollTo(0, this.myRef.current.offsetTop);
}
updateInputValue(e) {
this.setState({
inputValue: e.target.value
});
}
fetchRepos() {
if(this.state.inputValue.trim() === "" || this.state.inputValue.trim() === null) {
return this.setState({ isEmptySearch: true});
}
this.setState({
isEmptySearch: false,
isLoading: true
});
axios.get(`https://api.github.com/search/repositories?q=${this.state.inputValue}&per_page=100`)
.then(response => {
this.setState({
total_count: response.data.total_count,
repos: response.data.items,
isLoading: false,
dataLoaded: true,
reposLength: response.data.items.length
})
return this.scrollToMyRef();
})
.catch(err => console.log(err));
}
handleClick() {
this.fetchRepos();
}
handleKeyPress(e) {
if(e.key === "Enter") {
this.fetchRepos();
}
return
}
render() {
let { repos, isEmptySearch, total_count, isLoading } = this.state;
return (
<>
<header className={styles.hero}>
<div className="container">
<div className={styles.innerHero}>
<div>
<h1>Welcome to GIT M<span>EƎ</span>T</h1>
<p>Discover millions of github repositories <br></br>right here, right now.</p>
<p>Start by using the search box on the right.</p>
</div>
<div className={styles.searchBox}>
<SearchBox>
<img src={TurnArrow} alt="arrow pointing to search button" />
<h1>Search Repos</h1>
<input onKeyPress={this.handleKeyPress} onChange={this.updateInputValue} type="text" name="search" id="search" placeholder="E.g. 'ultra amazing html h1 tag...'" autoComplete="off" required />
<button disabled={ isLoading ? true : false } onClick={this.handleClick}>{ isLoading ? <img src={LoadingGif} alt="loading..." /> : "Search" }</button>
{ isEmptySearch ? <p className={styles.errorMessage}>Please enter something first!</p> : "" }
</SearchBox>
</div>
</div>
</div>
</header>
<main>
{this.state.dataLoaded ? <RepoItem ref={this.myRef} total_count={total_count} repos={repos}/> : "" }
<button className={styles.loadMore}>Load More</button>
</main>
</>
);
}
}
export default Home;
RepoList component
import React, { useState, useEffect } from 'react'
import styles from './repo_item.module.css';
import Footer from '../Footer/Footer';
const RepoList = React.forwardRef((props, ref) => {
const [repos, setRepos] = useState([props.repos]);
useEffect(() => {
setRepos(props.repos);
}, [props.repos]);
return (
<>
<div className="container">
<div className={styles.infoWrap}>
<h2>Results</h2>
<p>Found {props.total_count} results</p>
</div>
<div ref={ref} className={styles.repoWrap}>
{repos.length > 0 ? repos.map((item,index) => {
console.log(item);
return (
<div key={index} className={styles.repoItem}>
<div className={styles.userProfile}>
</div>
{ item.name && item.name.length > 20 ? item.name.substring(0,20) + "..." : item.name }
{ item.license.key }
</div>
);
}) : ""}
</div>
</div>
<Footer />
</>
);
})
export default RepoList;
Why... item.license.key doesnt work but item.name works.............help.
I suppes I messsed up with the connection between Home and repo component, But cannot see the error my self. Thats why I am posting it here, maybe someone will notice the problem faster.
Thank you for in advance, I have tried checking for item and its contents but I get same error everytime.
After finding a lot issue is not in code, data you are getting from API e.g https://api.github.com/search/repositories?q=bootstrap&per_page=100
license property is null so you are getting issue.
check null condition
{item.license && item.license.key}
API Call Response:
{
"total_count":276072,
"incomplete_results":false,
"items":[
{
"id":2126244,
"node_id":"MDEwOlJlcG9zaXRvcnkyMTI2MjQ0",
"name":"bootstrap",
.....
"license":{
"key":"mit",
"name":"MIT License",
"spdx_id":"MIT",
"url":"https://api.github.com/licenses/mit",
"node_id":"MDc6TGljZW5zZTEz"
},
......
},
{
"id":5689093,
"node_id":"MDEwOlJlcG9zaXRvcnk1Njg5MDkz",
"name":"android-bootstrap",
.....
"license":null,
.....
}
]
}

Passing react function to children down, event.target empty

I'm struggling to grasp a react concept that to me is likely used all the time.
I have an app with a state.
I have a section below app.
Below section I have clickable tile that receives a function to update app status. This works, however the event.target appears to be null.
I'm passing the function to update the status all the way down from app as a prop.
How can I fix this / what am I missing?
import React, { Component } from 'react';
import './App.css';
const Section = ({ handleClick }) => {
return (
<div className="section">
Section
<Tile handleClick={handleClick} title="1" />
<Tile handleClick={handleClick} title="2" />
<Tile handleClick={handleClick} title="3" />
</div>
)
}
const Tile = ({ handleClick, title }) => {
return (
<div className="tile" onClick={handleClick}>
tile {title}
</div>
)
};
class App extends Component {
constructor(props) {
super(props);
this.state = {
modalOpen: false
};
}
openModal = () => {
this.setState({
modalOpen: true,
openedBy: ""
})
}
closeModal = (event) => {
this.setState({
modalOpen: false,
openedBy: event.target.title
})
}
render() {
return (
<div className="App">
<div>ModalOpen = {this.state.modalOpen.toString()}</div>
<div>Opened by = {this.state.openedBy}</div>
<Section handleClick={this.openModal}></Section>
<a href="#" onClick={this.closeModal}>Close modal</a>
</div>
);
}
}
export default App;
Thanks so much for pointer in the right direction!
You are not passing down a title prop to your Tile component, but your are passing down a number prop.
You can create a new function in the Tile component that calls the handleClick with the number, which you then use to set the openedBy in your App.
Example
const Section = ({ handleClick }) => {
return (
<div className="section">
Section
<Tile handleClick={handleClick} number="1" />
<Tile handleClick={handleClick} number="2" />
<Tile handleClick={handleClick} number="3" />
</div>
);
};
const Tile = ({ handleClick, number }) => {
return (
<div className="tile" onClick={() => handleClick(number)}>
tile {number}
</div>
);
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
modalOpen: false,
openedBy: ""
};
}
openModal = title => {
this.setState({
modalOpen: true,
openedBy: title
});
};
closeModal = () => {
this.setState({
modalOpen: false,
openedBy: ""
});
};
render() {
return (
<div className="App">
<div>ModalOpen = {this.state.modalOpen.toString()}</div>
<div>Opened by = {this.state.openedBy}</div>
<Section handleClick={this.openModal} />
<a href="#" onClick={this.closeModal}>
Close modal
</a>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
It seems to be working perfectly fine :
const Section = ({ handleClick }) => {
return (
<div className="section">
Section
<Tile handleClick={handleClick} number="1" />
<Tile handleClick={handleClick} number="2" />
<Tile handleClick={handleClick} number="3" />
</div>
)
}
const Tile = ({ handleClick, title }) => {
return (
<div className="tile" onClick={handleClick}>
tile {title}
</div>
)
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
modalOpen: false
};
}
openModal = event => {
console.log(event.target)
this.setState({
modalOpen: true,
openedBy: ""
})
}
closeModal = event => {
console.log(event.target)
this.setState({
modalOpen: false,
openedBy: event.target.title
})
}
render() {
return (
<div className="App">
<div>ModalOpen = {this.state.modalOpen.toString()}</div>
<div>Opened by = {this.state.openedBy}</div>
<Section handleClick={this.openModal}></Section>
<a href="#" onClick={this.closeModal}>Close modal</a>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.2/umd/react-dom.production.min.js"></script>
<div id='root'>
However I assume that you want to pass down the title of the clicked element back into the handler. If so, I recommend using a curried function, with 2 sets of parameters, and setting the title variable as the first one :
openModal = title => event => {
console.log('Opened by : ', title, event.target)
this.setState({
modalOpen: true,
openedBy: ""
})
}
Your Tile component can now indicate which title it has by calling the function the first time :
const Tile = ({ handleClick, title }) => {
return (
<div className="tile" onClick={handleClick(title)}>
tile {title}
</div>
)
};
Working example :
const Section = ({ handleClick }) => {
return (
<div className="section">
Section
<Tile handleClick={handleClick} title="1" />
<Tile handleClick={handleClick} title="2" />
<Tile handleClick={handleClick} title="3" />
</div>
)
}
const Tile = ({ handleClick, title }) => {
return (
<div className="tile" onClick={handleClick(title)}>
tile {title}
</div>
)
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
modalOpen: false
};
}
openModal = title => event => {
console.log('Opened by : ', title)
this.setState({
modalOpen: true,
openedBy: ""
})
}
closeModal = event => {
this.setState({
modalOpen: false,
openedBy: event.target.title
})
}
render() {
return (
<div className="App">
<div>ModalOpen = {this.state.modalOpen.toString()}</div>
<div>Opened by = {this.state.openedBy}</div>
<Section handleClick={this.openModal}></Section>
<a href="#" onClick={this.closeModal}>Close modal</a>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.2/umd/react-dom.production.min.js"></script>
<div id='root'>

Reactjs use function from parent

I have 2 files. One is my app.js and the other one is productmodal.js
app.js gets a productlist from an api call. It views these productst in a list.
When a user clicks on the image productmodal.js is showed.
productmodal.js shows a popup with a bigger image, productname(title) and a button called "Product niet aanwezig" (product unavailable) if the user clicks on this link a mail is send to an other user.
When the button is click I also want to activate an other function (getUpdatedProduct). This function is gonna do a long polling call to a link to check when the product is updated to a new product and update this product in the app.
The problem is: I don't know how to call the function 'getUpdatedProduct' in productmodal.js
I get an error: Uncaught TypeError: Cannot read property 'getUpdatedProduct' of undefined
I tried some of these solutions https://reactjs.org/docs/faq-functions.html. Especially the arrow function in render, because its generating a new function every time when the modal is clicked (which I need).
But nothing seems to work. Has anyone some idea's?
App.js:
import React from 'react';
import image from '../images/sogyologo.svg';
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: [],
productDetail: [],
open: false,
modal: []
}
}
toggleModal(event)
{
console.log(event);
let itemIndex = event.target.getAttribute("data-itemIndex");
console.log(itemIndex);
const productModal = this.state.orders[itemIndex];
console.log(productModal);
this.setState({
open: true,
modal: this.state.orders[itemIndex]
});
}
handleClose() {
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/testing-9!8-7!6/10-04-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() {
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} = this.state;
return (
<div>
<header>
<img src={image}/>
<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, index) => {
const {productname, image, quantity, orderid} = order;
return<div className="product" key={orderid}>
<div className="plaatjediv" onClick={this.toggleModal.bind(this) }>
<img className="img-responsive" data-itemIndex={index} 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} = 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>
<ProductModal open={this.state.open} handleClose={this.handleClose.bind(this)}
title={this.state.modal.productname} plaatje={this.state.modal.image} orderid={this.state.modal.orderid}/>
<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();
this.getUpdatedProduct = this.getUpdatedProduct.bind(this);
}
handleClose() {
this.props.handleClose();
}
UserAction(event) {
let orderid = event.target.value;
fetch('http://localhost:54408/api/orders/change/testing-9!8-7!6/' + orderid + '/10-04-2018');
console.log("order id = " + event.target.value);
this.getUpdatedProduct();
}
getUpdatedProduct() {
console.log("fetching new product");
}
render() {
//const open = this.props.open;
const {title, plaatje, open, orderid} = this.props;
return (
<div className={'modal fade in '+(open?'show':'')} role="dialog">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" onClick={this.handleClose.bind(this)} className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 className="modal-title">{title}</h4>
</div>
<div className="modal-body">
<img className="plaatjediv img-responsive" src={plaatje} />
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default"
onClick={this.handleClose.bind(this)}>Sluiten
</button>
<button type="button" onClick={this.UserAction.bind()} value={orderid} className="btn btn-primary">Product niet aanwezig</button>
</div>
</div>
</div>
</div>
)
}
}
export default ProductModal;

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