Reactjs use function from parent - reactjs

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;

Related

React Element appearing after second button click

Im fairly new to react and im trying to build a webapp. I'm having this problem when it comes to displaying a div that contains multiple input fields, the field lesson dont show until the second time I click my create button. However it's working perfectly when I render it with this code:
Note: Im rendering TestClonereact in CourseVideoStructure
This is CourseVideoStructure.js
import React, { Component } from 'react'
import Sidenavbar from '../../Components/Sidenavbar'
import '../../Style/pagestyle/CourseVideoStructure.css'
import Footer from '../../Components/Footer'
import { Avatar } from '#material-ui/core'
import 'react-dropzone-uploader/dist/styles.css'
import EdiText from 'react-editext'
import TestClonereact from '../../Components/TestClonereact'
export default class CourseVideoStructure extends Component {
onSave = val => {
console.log('Edited Value -> ', val)
}
id = 1;
state = {
listq: [],
}
lessons(id) {
return (
<div key={id} id={`sectionlesson-${id}`}>
<div className="section-titles">
<i class="material-icons" id="iconsectionlist" type="button" >list</i>
<EdiText
type='text'
value='Lesson Title'
onSave={this.onSave}
/>
<i class="material-icons" id="iconsectiondel" type="button">smart_display</i>
<i class="material-icons" id="iconsectiondel" onClick={e => this.remove(`${id}`)} type="button" >delete</i>
</div>
<div className="testh" >
</div>
</div>
)
}
addlesson1 = () => {
const listlesson = this.state.listq;
listlesson.push(this.lessons(this.id))
this.setState({ listlesson });
this.id++;
}
remove(id) {
const newList = this.state.listq.filter(lessons => lessons.key !== id);
this.setState({
listq: newList
})
}
addsection = () => {
const list = this.state.list;
list.push(this.section(this.id))
this.setState({ list });
this.id++;
}
render() {
return (
<div>
<Sidenavbar></Sidenavbar>
<nav class="navbar navbar-expand-md navbar-white">
<a class="navbar-brand" href="#"></a>
<Avatar className="avatar" aria-controls="simple-menu" aria-haspopup="true" src="https://avatars2.githubusercontent.com/u/56764954?s=400&u=57d85794b8c753245870e2f9051b303d1188b01d&v=4" ></Avatar>
</nav>
<div className="row">
<div className="fluid-xld" id="coursevideo-structure-xld">
<div className="course-structure-form-dsp col-md-12">
<h3 className="container"> Video Course Structure</h3><br></br><br></br>
<div className="course-structure-form " id="csf1">
<div className="section-heading">
<i class="material-icons" id="iconsection">api</i>
<EdiText
type='text'
value='Section Title'
onSave={this.onSave}
/>
</div>
{
this.state.listq.map(lessons => lessons)
}
<div className="addnewlesson" onClick={e => this.addlesson1()}>
<i class="material-icons" id="iconsectionde" role="button" type="button" >add_circle</i><span>Add New Lesson</span>
</div>
</div>
</div>
<div>
<TestClonereact></TestClonereact>
</div>
</div>
</div>
<Footer></Footer>
</div>
)
}
}
However when I try to render this component in CourseVideoStructure(the code above) it doesnt render as I would like it to:
This is TestClonereact.jsx:
import React, {useEffect, useReducer} from 'react'
import '../Style/pagestyle/CourseVideoStructure.css'
import EdiText from 'react-editext'
class TestClonereact extends React.Component {
constructor(props) {
super(props);
this.state = {
listq: [],
list: []
};
}
onSave = val => {
console.log('Edited Value -> ', val)
}
id = 1;
lessons(id){
return (
<div key={id} id={`sectionlesson-${id}`}>
<div className="section-titles">
<i class="material-icons" id="iconsectionlist" type="button" >list</i>
<EdiText
type='text'
value='Lesson Title'
onSave={this.onSave}
/>
<i class="material-icons" id="iconsectiondel" type="button">smart_display</i>
<i class="material-icons" id="iconsectiondel" onClick={e => this.remove(`${id}`)} type="button" >delete</i>
</div>
<div className="testh" >
</div>
</div>
)
}
section(id){
return (
<div key={id} id={`sds-${id}`}>
<div className="course-structure-form " id="csf1">
<div className="section-heading">
<i class="material-icons" id="iconsection">api</i>
<EdiText
type='text'
value='Section Title'
onSave={this.onSave}
/>
</div>
{
this.state.listq.map(lessons => lessons)
}
<div className="addnewlesson" onClick={async () => { this.addlesson();}}>
<i class="material-icons" id="iconsectionde" role="button" type="button" >add_circle</i><span>Add New Lesson</span>
</div>
</div>
</div>
)
}
addsection = () => {
const list = this.state.list;
list.push(this.section(this.id))
this.setState({ list });
this.id++;
}
addlesson = () => {
const listlesson = this.state.listq;
listlesson.push(this.lessons(this.id))
this.setState({ listlesson });
this.id++;
}
deletelesson = () => {
const list = this.state.list;
list.splice(this.section(this.id))
this.setState({ list });
this.id--;
}
remove(id) {
const newList = this.state.listq.filter(lessons => lessons.key !== id);
this.setState({
listq: newList
})
}
render(){
return (
<div>
{
this.state.list.map(section => section)
}
<div className="add-section-button-structure">
<button class="tablink" onClick={e => this.addsection()} >Add New Section</button>
<button class="tablink" onClick={e => this.deletelesson()} >Delete Section</button>
<button class="tablink" >Preview</button>
<button class="tablink" >Submit</button>
</div>
</div>)
}
}
export default TestClonereact
So the result in images is this:
Working fine and Added Lessons 1 by 1 in the same Section:
Working Fine and able to add lessons
Problem is when I click on Add Lesson in the Second section, nothing happens but when I click on Add section again, the lesson appear in the 3rd section not the second one:
Problem image here
I've kept tryint to solve this issue with no luck. Any kind of help is much appreciated.
Forgive me for any horrible coding.

Moving an item from Todolist to delete list and delete it from TodoList

Hello i want to move an item from todo list to delete list in ReactJS and i want to delete it from todo list when i move it to done list i did everything i can delete the selected item or all items but i cant add it to done list when i move it
import React from 'react';
import './App.css';
import Todoinput from './Components/Todoinput'
import Todolist from './Components/Todolist'
import Tododone from './Tododone'
import { render } from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import uuid from 'uuid';
class App extends React.Component {
state= {
items:[],
id:uuid(),
item:'',
editItem:false
}
handleChange = (e) => {
this.setState ({
item:e.target.value
})
}
handleSubmit = (e) => {
e.preventDefault ();
const newItem = {
id:this.state.id,
title:this.state.item,
};
const updatedItems = [...this.state.items,newItem]
this.setState ({
items:updatedItems,
item:'',
id:uuid(),
editItem:false
})
}
clearList = (e) => {
this.setState ({
items:[]
})
}
doneItem = (id) => {
const doneItems = this.state.items.filter (item => item.id !== id);
this.setState ({
items:doneItems,
})
}
handleEdit = (id) => {
const doneItems = this.state.items.filter (item => item.id !== id);
const selectedItem = this.state.items.find(item=> item.id === id)
console.log(selectedItem)
this.setState ({
items:doneItems,
item:selectedItem.title,
editItem:true,
id:id
})
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-10 mx-auto col-md-8 mt-4">
<h3 className="text-capitalize text-center">Todo Inputs</h3>
<Todoinput item={this.state.item} handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
editItem={this.state.editItem}
/>
<Todolist items={this.state.items} clearList={this.clearList} doneItem={this.doneItem} handleEdit={this.handleEdit}/>
<Tododone doneItem={this.doneItem} />
</div>
</div>
</div>
);
}
}
export default App;
/**/
import React from 'react'
import Todoitem from './Todoitem'
class Todolist extends React.Component {
render() {
const {items,clearList,doneItem,handleEdit}=this.props
return (
<ul className="list-group my-5">
<h3 className="text-capitalize text-center">todo list</h3>
{
items.map(item => {
return (
<Todoitem
key={item}
title={item.title}
doneItem={()=> doneItem(item.id)}
handleEdit={()=> handleEdit(item.id)}
/>
)
})
}
<button type="button" className="btn btn-danger btn-block text-capitalize mt-5"
onClick={clearList}
>clear list</button>
</ul>
)
}
}
export default Todolist
/**/
import React from 'react'
class Todoinput extends React.Component {
render() {
const {item,handleChange,handleSubmit,editItem} = this.props
return (
<div className="card card-body my-3">
<form onSubmit={handleSubmit}>
<div className="input-group">
<div className="input-group-prepend">
<div className="input-group-text bg-primary text-white">
<i className="fa fa-book" ></i>
</div>
</div>
<input type="text" className="form-control text-capitalize" placeholder="Add A To Do Item"
value={item}
onChange={handleChange}
/>
</div>
<button type="submit"
className={editItem ? "btn btn-block btn-success mt-3" : "btn btn-block btn-primary mt-3" }>
{editItem ? 'Edit Item' : "Add Item"}</button>
</form>
</div>
)
}
}
export default Todoinput
/**/
import React from 'react'
class Todoitem extends React.Component {
render() {
const {title,doneItem,handleEdit} = this.props
return (
<li className="list-group-item text-capitalize d-flex justify-content-between my-2">
<h6>{title}</h6>
<div className="todo-icon">
<span className="mx-2 text-success" onClick={handleEdit}>
<i className="fa fa-edit"></i>
</span>
<span className="mx-2 text-danger"onClick={doneItem}>
<i className="fa fa-window-close"></i>
</span>
</div>
</li>
)
}
}
export default Todoitem
/**/
import React from 'react'
class Tododone extends React.Component {
render() {
const {items,clearList,doneItem,title,item}=this.props
return (
<div>
<h2 className="text-capitalize text-center">Done Items</h2>
<li className="list-group-item text-capitalize d-flex justify-content-between my-2">
<h6>{item}</h6>
<div className="todo-icon">
<span className="mx-2 text-danger" onClick={doneItem}>
<i className="fa fa-trash"></i>
</span>
</div>
</li>
<button type="button" className="btn btn-danger btn-block text-capitalize mt-5"
onClick={clearList}>clear list</button>
</div>
)
}
}
export default Tododone
so if anyone can help Please i post all the code above if anyone can help me please <
To track if a task is done, add a isDone field to item, when you say it's done, flag it to true.
So when you create a new item:
const newItem = {
id:this.state.id,
title:this.state.item,
isDone: false
};
When you render items that are not done, filter through isDone===false, like this:
<Todolist items={this.state.items.filter(item => item.isDone === false)} ... />
When you delete an item from the ToDoList you want it to go to the DoneList, so you set your doneItem function like this:
doneItem = id => {
const newItems = [...this.state.items];
const item = newItems.find(item => item.id === id);
item.isDone = true;
this.setState({
items: newItems
});
}
When you render the done list, filter through isDone === true, like this:
<Tododone items={this.state.items.filter(item => item.isDone === true)} ... />
Now get the items prop in Tododone and map it to see the done items, this below is just an example:
{items.map(item => (
<li className="list-group-item text-capitalize d-flex justify-content-between my-2">
<h6>{item.title}</h6>
<div className="todo-icon">
<span className="mx-2 text-danger" onClick={doneItem}>
<i className="fa fa-trash"></i>
</span>
</div>
</li>
))}
Since I don't know what you want to do with those divs and spans I'll leave them like you set them.
When you click on clear list I assume you want to delete only the todoList or only the doneList, I suggest you to pass a flag to tell App which list to clear.
Here's the sandbox with your code that solves your problem.
down and dirty because I have to head to work would be to add something like doneItemsArray: [] in your state and then just do another filter in your doneItem method.
doneItem = id => {
const filteredTodos = this.state.items.filter(item => item.id !== id);
const doneItem = this.state.items.filter(item => item.id === id);
this.setState({
items: doneItems,
doneItemsArray: [...this.state.doneItemsArray, doneItem]
});
};

how do i toggle disabled between two buttons in react map

I have a list of candidates with two buttons hire and reject. when i press hire it should be disabled and reject stays enabled. When i press reject it should be disabled and hire must be enabled.
{result && result.map(appliedCandidate => {
if (joblist.id === appliedCandidate.jobid) {
return (
<div className="row pb-3">
<div className=" col-md-4 text-left font-weight-bold">
<p className={this.state.applystatus==="hire" ? "text- info" : "text-danger"}>
{appliedCandidate.firstName}
</p>
</div>
<div className="col-md-8">
<div className="row">
<div className="col-4">
<div className="back-btn">
<input id='hire' type='button' ref='hire' data-id={appliedCandidate.jobid} name={appliedCandidate.id} data-tag={appliedCandidate.phoneno} onClick={this.hireReject} className="btn btn-success card-btn-width" value='hire' />
</div>
</div>
<div className="col-4">
<div className="back-btn">
<input id='reject' type='button' ref='reject' data-id={appliedCandidate.jobid} name={appliedCandidate.id} data-tag={appliedCandidate.phoneno} onClick={this.hireReject} className="btn btn-danger card-btn-width" value='reject' />
</div>
</div>
<div className="col-4">
<div className="back-btn">
<Link to={{ pathname: '/individualchat', state: { name: appliedCandidate.firstName, jobid: appliedCandidate.jobid, id: appliedCandidate.id, Title: appliedCandidate.Title } }}>
<button type="button" className="btn btn-info">chat</button>
</Link>
</div>
</div>
</div>
</div>)
}
})}
hireReject = (event) => {
var dis = event.target.setAttribute('disabled','true')
const phoneno = event.target.getAttribute('data-tag');
const id = event.target.getAttribute('name');
const jobid = event.target.getAttribute('data-id');
const applystatus = event.target.value;
{ applystatus === 'hire' ? toastr.success('Successfully hired') : toastr.error('Successfully rejected') }
{ applystatus === 'hire' ? document.getElementById('reject').disabled = false : document.getElementById('hire').disabled = false }
this.setState({
jobid: jobid, id: id, candidatephoneno: phoneno, applystatus: applystatus
}, () => {
this.props.hireReject(this.state)
})
{return applystatus === 'hire' ? 'hired' : 'rejected'}
}
Consider separating the buttons and hiring/rejecting logic into its own component like the following so you can better handle the toggling.
Index.js
import React from "react";
import ReactDOM from "react-dom";
import Candidate from "./Candidate";
import "./styles.css";
class App extends React.Component {
state = {
text: ""
};
render() {
const candidates = [{ name: "Bob" }, { name: "Sam" }, { name: "Jessie" }];
return candidates.map(candidate => {
return <Candidate candidate={candidate} />;
});
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Candidate.js
import React from "react";
class Candidate extends React.Component {
state = {
hired: null
};
handleHire = () => {
this.setState({
hired: true
});
};
handleReject = () => {
this.setState({
hired: false
});
};
render() {
const hired = this.state.hired;
return (
<div>
<h4>{this.props.candidate.name}</h4>
<button
onClick={this.handleHire}
disabled={hired == null ? false : hired}
>
Hire
</button>
<button
onClick={this.handleReject}
disabled={hired == null ? false : !hired}
>
Reject
</button>
</div>
);
}
}
export default Candidate;
Here is a sandbox for your reference as well: https://codesandbox.io/s/zrlyq0l29m

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.

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