Edit posts in react - javascript

I am trying to edit the text inside my Products component---
import React, { Component } from 'react'
import Newitem from './Newitem'
import App from '../App';
export default class Products extends Component {
state = {
name:this.props.name,
price:this.props.price,
description:this.props.description,
rating:this.props.rating,
img:this.props.img,
newName:'',
newPrice:'',
newDescription:'',
newImg:'',
inputsDisplay:'',
index:this.props.index,
}
deleteFunc=()=>{
this.props.delete(this.state.index)
}
changeName=(e)=>{
let changeNameInput=e.target.value;
this.setState({newName:changeNameInput})
}
changePrice=(e)=>{
let priceInput=e.target.value;
this.setState({newPrice:priceInput})
}
changeDescrip=(e)=>{
}
changeImg=(e)=>{
}
editButton=()=>{
if(this.state.newName.length==0){
this.setState({
inputsDisplay:'block'
})
}
else{
this.setState({
name:this.state.newName,
price:`${this.state.newPrice} NIS`,
inputsDisplay:'block'
})
}
}
hideEditInputs=()=>{
this.setState({inputsDisplay:'none'})
}
render() {
return (
<div className='container' id='Container'>
<span className='namestyle'>{this.props.name}</span>
<span className='descriptionstyle'>{this.props.description}</span>
<img className='imgstyle' alt='Bad source' src={this.props.img}></img>
<span className='pricestyle'>{this.props.price}</span>
<span className='ratingstyle'>{this.props.rating}</span>
<button onClick={this.deleteFunc} id='deleteButton'>X</button>
<input className='editNameInput' onChange={this.changeName} placeholder='Edit name'
style={{display:this.state.inputsDisplay}}>
</input>
<button className='editButton' onClick={this.editButton}>EDIT</button>
<input onChange={this.changePrice} className='editPriceInput' placeholder='Edit price'
style={{display:this.state.inputsDisplay}}>
</input>
<input className='editDescripInput' placeholder='Edit description'
style={{display:this.state.inputsDisplay}}>
</input>
<input className='editImgInput' placeholder='Edit IMG'
style={{display:this.state.inputsDisplay}}>
</input>
<button onClick={this.hideEditInputs}className='hideEditButton' >HIDE EDIT</button>
</div>)
}
}
I have 3 components Products, Header, App, and Newitem.
The Header is for the title, the App holds my data array, Newitem is placing new 'post'(product) inside of my data array, Products get props from App.
I created 4 inputs and my goal is When I click the EDIT button the text in the input will replace the text I got from the props.
I tried with setState but it seems to bug the Newitem function(it's giving me a new product with the same info I have in the data array and not what I gave to the function)
I really clueless about what I did wrong, here are my other components Newitem---
import React, { Component } from 'react'
import Products from './Products'
export default class Newitem extends Component {
state = {
imgInput:'',
discriptionInput:'',
nameInput:'',
priceInput:'',
validNameBG:'white',
validPriceBG:'white',
validDiscriptionBG:'white',
validImgBG:'white'
}
validName=(e)=>{
let nameInput=e.target.value
console.log(nameInput)
if(nameInput.length>=4 && nameInput.length<40){
this.setState({
nameInput:nameInput,
validNameBG:'lightgreen'
})
}
else if(nameInput.length==0){
this.setState({validNameBG:'white'})
}
else{this.setState({
validNameBG:'red',
nameInput:''
})}
}
validPrice=(e)=>{
let priceInput=Number(e.target.value)
if(isNaN(priceInput)){
this.setState({validPriceBG:'red'})}
else if(!isNaN(priceInput)){
this.setState({
priceInput:priceInput,
validPriceBG:'lightgreen'
})
}
if(priceInput === 0){
this.setState({
validPriceBG:'white',
priceInput:'',
})
}
}
validDescription=(e)=>{
let discriptionInputValue=e.target.value
if(discriptionInputValue.length>=4 && discriptionInputValue.length<100){
this.setState({
validDiscriptionBG:'lightgreen',
discriptionInput:discriptionInputValue})
}
else if(discriptionInputValue.length==0){
this.setState({
validDiscriptionBG:'white'
})
}
else{this.setState({
validDiscriptionBG:'red',
discriptionInput:''
})}
}
validImg=(e)=>{
let imgInputValue=e.target.value;
if(imgInputValue.length>7){
this.setState({
validImgBG:'lightgreen',
imgInput:imgInputValue
})
}
else if(imgInputValue.length <= 7 && imgInputValue.length>0){
this.setState({
validImgBG:'red',
imgInput:''
})
}
else{
this.setState({
validImgBG:'white',
imgInput:''
})
}
}
addFunc=()=>{
if(this.state.validDiscriptionBG=='red'||this.state.validImgBG=='red'||this.state.validNameBG=='red'
||this.state.validPriceBG=='red'){
return alert('Invalid value.')
}
else if(this.state.validDiscriptionBG=='white'||this.state.validImgBG=='white'||this.state.validNameBG=='white'
||this.state.validPriceBG=='white'){
return alert('Invalid value.')
}
else{
this.props.add(
this.state.nameInput,
`${this.state.priceInput} NIS`,
this.state.discriptionInput,
this.state.imgInput,
)}
}
render() {
return (
<div>
<ul id='placing '>
<input onChange={this.validName}
id='nameInput' placeholder='Name'
style={{backgroundColor:this.state.validNameBG}}>
</input>
<input onChange={this.validPrice}
id='priceInput' placeholder='Price'
style={{backgroundColor:this.state.validPriceBG}}>
</input>
<button onClick={this.addFunc} className='plusbutton'>Add</button>
</ul>
<ul>
<input onChange={this.validDescription}
id='descriptionInput' placeholder='Description'
style={{backgroundColor:this.state.validDiscriptionBG}}
></input>
<input onChange={this.validImg}
id='imgInput' placeholder='Img Source'
style={{backgroundColor:this.state.validImgBG}}
></input>
</ul>
</div>
)
}
}
App component----
import React, { Component } from 'react'
import Header from './components/Header'
import Products from './components/Products'
import Newitem from './components/Newitem'
import '../src/App.css';;
export default class App extends Component {
state = {
products: [
{
name:'Apple iphone 11 Pro max 256gb',
price:'4749 NIS',
description:'Iphone 11 256 gb,with 4gb ram, 6.5 inch,thickness 8.1',
rating:'5/5 Stars ! ',
img:'https://img.zap.co.il/pics/3/3/2/9/52789233b.gif'
},
{
name:'Samsung Galaxy S20 Plus',
price:'3749 NIS',
description:'Android operation system 8gb of ram Thickness 7.8m,weight 186 gram',
rating:'5/5 Stars !',
img:'https://img.zap.co.il/pics/0/2/1/8/54298120b.gif'
},
{
name:'Xiamo Poco X3',
price:'1265 NIS',
description:'Android operation system 6gb of ram Thickness 9.4m,refresh rate 120Hz',
rating:'3/5 Stars ! ',
img:'https://img.zap.co.il/pics/2/8/3/8/57738382b.gif'
},
{
name:'Samsung Galaxy A71',
price:'1049 NIS',
description: 'Android operation system 6gb of ram ,48 Mega pixel Thickness 7.9m',
rating:'4/5 Stars !',
img:'https://img.zap.co.il/pics/3/1/3/3/53803313b.gif'
}]
}
addNewProduct =(n,p,d,i,r)=>{
const newProduct= {
name:n,
price:p,
description:d,
img:i,
rating:r,
}
this.setState({products:[newProduct,...this.state.products]})
}
deleteProduct=(i)=>{
let filteredProducts=this.state.products.filter((item,index)=>(index!==i))
this.setState({products:filteredProducts})
}
render() {
return (
<div className="App">
<Newitem add={this.addNewProduct}/>
<Header />
{this.state.products.map((item,index)=>{
return(
<Products
name={item.name}
price={item.price}
description={item.description}
rating={item.rating}
img={item.img}
delete={this.deleteProduct}
index={index}
/>
)
})}
</div>
)
}
}
Thank you a lot

Props should be immutable, so a component shouldn't manage is own props. You can do it the same way you are using to delete a product.
This code should be in your App component. Receive the index and update your data.
changeName=(index, e)=>{
const updatedProducts = [...this.state.products];
updatedProducts[index].name = e.target.value;
this.setState({ products: updatedProducts });
}
Then pass the function as a prop to Product component.

Related

Adding a New Value to State is Overwriting Previous State in React Redux

My reducer adds a new workout object to an array called workouts. It works perfectly fine on the first initial change. The problem is when I try to add another workout my reducer overwrites the previous workout I just added.
I am pretty sure it has something to do with my reducer and how I'm manipulating the workouts array.
Form to add a new Workout:
import React from 'react';
import { Field, reduxForm } from 'redux-form';
let Form = props => {
const { handleSubmit } = props;
return (
<form onSubmit={handleSubmit}>
<label>Name</label>
<Field name='name' component='input' type='text' />
<label>Total Calories</label>
<Field name='calories' component='input' type='number' />
<label>Duration</label>
<Field name='duration' component='input' type='number' />
<button type='submit'>Submit</button>
</form>
);
};
export default reduxForm({ form: 'workout' })(Form);
actions.js (my action):
export const addWorkout = workout => ({
type: 'ADD_WORKOUT',
payload: {
workout,
},
});
workouts.js (reducer):
const initialState = {
workouts: [
{
name: 'HIIT',
calories: '320',
duration: '30',
},
{
name: 'Run',
calories: '35',
duration: '400',
},
],
totalCal: 0,
};
export default function workoutReducer(state = initialState, action) {
switch (action.type) {
case 'ADD_WORKOUT': {
console.log(state.workouts);
return {
...state,
workouts: [...state.workouts, action.payload.workout],
};
}
default:
return state;
}
}
Screenshots:
Before adding any workouts, initial state contains two workouts, HIIT and Run
After adding a workout, in this case I added a Yoga workout
Adding a second workout
As you can see my first workout I added was overwritten.
Any help would be very much appreciated, thanks in advance!
Edit
Here is my component that displays the list of workouts.
import React, { useEffect } from 'react';
import './Dashboard.scss';
import { connect } from 'react-redux';
import Chart from './Chart';
import Plan from './Plan';
const Dashboard = props => {
return (
<div className='dashboard-container'>
<div className='daily'>
<h4>Keep it going Steven you got this!</h4>
<div className='stats'>
<p className='calories'>Calories</p>
<p className='stand'>Stand Hours </p>
<p className='exercise'>Exercise Minutes</p>
</div>
<p>Workouts</p>
{props.workouts.map((workout, i) => {
return (
<div>
<p key={i}>{workout.name}</p>
</div>
);
})}
</div>
<div className='workouts'>
<Chart />
<Plan />
</div>
</div>
);
};
const mapStateToProps = state => ({
workouts: state.workouts.workouts,
totalCals: state.workouts.totalCal,
});
export default connect(mapStateToProps)(Dashboard);
The problem was regarding my Add Workout link in the Navbar. Instead of using Link from react-router-dom I was just using a Nav.Link tag from bootstrap which reset my state every time I navigated to the form.
import { Link } from 'react-router-dom';
...
<Nav className='mr-auto'>
...
{/* <Nav.Link href='/addworkout'>Add Workout</Nav.Link> */}
<Link to='/addworkout'>Add Workout</Link>
</Nav>

React App class won't render when a child Component changes

I just started to learn React. I'm trying to write a Todo list and so far it looks like:
However when I check the box of a Todo, the count of things left to do won't change even when the state of a list of Todos changes (the 'checked' property of a Todo that I just checked change to true)
My App.js:
import React, {Component} from 'react';
import TaskComponent from "./TaskComponent";
class App extends Component {
constructor(props) {
super(props)
this.state = {
taskList: [],
newTaskContent: ''
}
this.generateTask = this.generateTask.bind(this)
this.updateNewTaskContent = this.updateNewTaskContent.bind(this)
}
generateTask() {
if (this.state.newTaskContent) {
const joined = this.state.taskList.concat({
id: this.state.taskList.length + 1,
content: this.state.newTaskContent,
checked: false
})
this.setState({taskList: joined, newTaskContent: ''})
}
}
updateNewTaskContent({target: {value}}) {
this.setState({newTaskContent: value})
}
render() {
return (
<div>
<ul>{this.state.taskList.map(task => <TaskComponent key={task.id} task={task.content}
checked={task.checked}/>)}</ul>
<input type='text' placeholder='Type your new task'
onChange={this.updateNewTaskContent} value={this.state.newTaskContent}/>
<button name='generateTask' onClick={this.generateTask}>Generate task</button>
<div>There are {this.state.taskList.filter(task => !task.checked).length} things left to do!</div>
</div>
);
}
}
export default App;
My TaskComponent.js file:
import React, {Component} from 'react'
class TaskComponent extends Component {
constructor({task, checked}) {
super(undefined)
this.state = {
taskContent: task,
checkedState: checked
}
this.changeHandler = this.changeHandler.bind(this)
}
changeHandler({target: {checked}}) {
this.setState({checkedState: checked})
}
render() {
return (
<div>
<span>{this.state.taskContent}</span>
<input type="checkbox" checked={this.state.checkedState} onChange={this.changeHandler}/>
</div>
);
}
}
export default TaskComponent;
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
taskList: [],
newTaskContent: ''
}
this.generateTask = this.generateTask.bind(this)
this.updateNewTaskContent = this.updateNewTaskContent.bind(this)
}
generateTask() {
if (this.state.newTaskContent) {
const joined = this.state.taskList.concat({
id: this.state.taskList.length + 1,
content: this.state.newTaskContent,
checked: false
})
this.setState({taskList: joined, newTaskContent: ''})
}
}
updateNewTaskContent({target: {value}}) {
this.setState({newTaskContent: value})
}
render() {
return (
<div>
<ul>{this.state.taskList.map(task => <TaskComponent key={task.id} task={task.content}
checked={task.checked}/>)}</ul>
<input type='text' placeholder='Type your new task'
onChange={this.updateNewTaskContent} value={this.state.newTaskContent}/>
<button name='generateTask' onClick={this.generateTask}>Generate task</button>
<div>There are {this.state.taskList.filter(task => !task.checked).length} things left to do!</div>
</div>
);
}
}
class TaskComponent extends React.Component {
constructor({task, checked}) {
super(undefined)
this.state = {
taskContent: task,
checkedState: checked
}
this.changeHandler = this.changeHandler.bind(this)
}
changeHandler({target: {checked}}) {
this.setState({checkedState: checked})
}
render() {
return (
<div>
<span>{this.state.taskContent}</span>
<input type="checkbox" checked={this.state.checkedState} onChange={this.changeHandler}/>
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector("#root"));
<script src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Inside the TaskComponent class I add the function for the event of changing the "checked" state of the check box but somehow the 'taskList' state in my App does not change at all when I try to console.log it. What is my problem here? Be gentle since I'm new to React and Javascript in general.
You are setting state in TaskComponent and expecting it to change the prop in App.js.
Instead of setting a TaskComponents's state when it is checked, I would recommend calling a function passed in as a prop when it is checked, which has its id and new value. Something along the lines of:
App.js:
// somewhere in your class:
handler(id, value) {
// set state to reflect changes
}
// in your render()
<ul>{this.state.taskList.map((task) => {
<TaskComponent onChange={this.handler} id={task.id} key={task.id} task={task.content} checked={task.checked} />})}</ul>
In TaskComponent.js:
changeHandler({target: {checked}}) {
this.props.onChange(this.props.id, checked);
}
I would also recommend making TaskComponent not have state at all, because it seems unnecessary to me.

Get keys of every object and insert that data into array

I want to get the keys of every frame object and insert that data into array. After it should have arrays in array. I have tried multiple ways and have not figured it out. Any suggestions?
This is the output.json that i will be working with, it could go up to 550 frame number's.
[{"frame_number": 1, "roi0": [101.78202823559488, 99.39509279584912, 49.546951219239915, 29.728170731543948], "intensity0": 80.0, "roi1": [101.78202823559488, 99.39509279584912, 49.546951219239915, 29.728170731543948], "intensity1": 157.0},
{"frame_number": 2, "roi0": [102.56623228630755, 97.95906005049548, 50.25603182631066, 30.153619095786393], "intensity0": 80.0, "roi1": [102.56623228630755, 97.95906005049548, 50.25603182631066, 30.153619095786393], "intensity1": 158.0},
{"frame_number": 3, "roi0": [103.39336535376313, 98.20468223716023, 49.58465295946593, 29.750791775679556], "intensity0": 80.0, "roi1": [103.39336535376313, 98.20468223716023, 49.58465295946593, 29.750791775679556], "intensity1": 157.0},
The following is my app.js where i get the output.json file from the api and send it through to a component, button_footer
import "bootstrap/dist/css/bootstrap.css";
import React from "react";
import Radio_Button from "./components/Radio_Button.js";
import Buttons_Footer from "./components/Buttons_Footer.js";
import LeftPane from "./components/LeftPane.js";
//import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { apiResponse: [] };
}
// Comunicate with API
callAPI() {
fetch("http://localhost:9000/IntensityAPI") //React app talks to API at this url
.then(res => res.json())
.then(res => this.setState({ apiResponse: res }));
}
componentWillMount() {
this.callAPI();
}
render() {
return (
<div className="App">
<header className="App-header">
<p></p>
<div class="row fixed-bottom no-gutters">
<div class="col-3 fixed-top fixed-bottom">
<LeftPane></LeftPane>
</div>
<div class="offset-md-3" >
<Buttons_Footer readings = {this.state.apiResponse}/>
</div>
</div>
</header>
</div>
);
}
}
export default App;
The following is the button_footer which is where I tried to handle this data and put it in a array but failed.
import $ from "jquery";
import React, { Component } from 'react';
import { MDBFormInline } from 'mdbreact';
import { Container, Row, Col } from 'reactstrap';
import Radio_Button from "./Radio_Button.js";
// Footer Component with checkbox's used to select region/region's of interest
class Buttons_Footer extends Component {
// Enables the Functionality of the "Select Multiple Region's" switch using jquerys
componentDidMount() {
$(".region").click(function(e){
if($('#customSwitches').is(':not(:checked)')){
if($('.region:checked').length > 1){ // Multiply regions unable to be selected
alert('You can not check multiple');
e.preventDefault();
}
}
});
$("#customSwitches").click(function(e){ // Multiply regions able to be selected
$(".region").prop('checked', false);
}); }
//<p>{this.props.region.roi0}</p>
render() {
return (
<Container class = "container offset-md-3" >
<div className='custom-control custom-switch' >
<input type='checkbox' className='custom-control-input' id='customSwitches' />
<label className='custom-control-label' htmlFor='customSwitches'>
Select Multiple Region's
</label>
{this.props.readings.map((region)=>{
return <Radio_Button region ={region} key ={region.frame_number}/>
})}
Object.keys({this.props.readings}).map((key, index) => {
const myItem = myObject[key]
return <MyComponent myItem={myItem} key={index} />
})
<MDBFormInline>
<input class="region" type="checkbox" name="region1" value="1" />
<label for="region1"> 1</label>
<input class="region" type="checkbox" name="region2" value="2" />
<label for="region2"> 2</label>
</MDBFormInline>
</div>
</Container>
);
}
}
export default Buttons_Footer;
```
Maybe this work
this.props.readings.map((reading, index) => {
Object.keys(reading).map((key, index) => {
const myItem = reading[key]
return <MyComponent myItem={myItem} key={index} />
})
})

Reload table after deleting an item from it with React

Using React.Js, I created a delete function to delete an item from a table. the delete is working fine but what I want to do is that after deleting I want the tables to be dynamically updated to show only the items left. Now after the delete I have to refresh manually the page or go to another page and comeback to see the items left after the delete
This is the code built so far :
import React, { Component } from "react";
import { Card, Button, Select,/* message, */ Form, Tooltip } from "antd";
import extraitMP3 from "./data";
import { arrayMove, SortableHandle } from "react-sortable-hoc";
import ContainerHeader from "components/ContainerHeader/index";
import { getExtraitMp3, hideMessageUpdate, showUpdateLoader, updateMp3Visibilite } from "appRedux/actions/Comedien";
import { deleteMp3Request } from "../../../appRedux/services/extraitMp3Service"
import { connect } from "react-redux";
import { NotificationContainer, NotificationManager } from "react-notifications";
import { userSignOut } from "appRedux/actions/Auth";
import { displayIcon } from '../../../util/Icon.js';
import CircularProgress from "components/CircularProgress";
import { Modal } from "antd";
const extraitMP32 = [extraitMP3];
const confirm = Modal.confirm;
const Option = Select.Option;
const DragHandle = SortableHandle(() =>
<span className="gx-draggable-icon gx-pt-2">
<i className="icon icon-menu" style={{ fontSize: 25 }} />
</span>);
class ListExtrait extends Component {
onSortEnd = ({ oldIndex, newIndex }) => {
this.setState({
extraitMP3: arrayMove(this.state.extraitMP3, oldIndex, newIndex),
});
};
constructor() {
super();
this.state = {
extraitMP3: extraitMP32[0],
nombreMP3: {
rechercheExtraits: 0,
recherchePossible: 0,
extraitFiche: 0,
extraitFichePossible: '',
extraitArchives: 0,
extraitArchivesPossible: '',
},
loader: false,
}
}
componentDidMount() {
this.props.getExtraitMp3();
}
componentDidUpdate() {
}
static getDerivedStateFromProps(nextProps, prevState,/* nextProps2,prevState2 */) {
if (nextProps.extraitMP3 !== prevState.extraitMP3 && nextProps.extraitMP3) {
return { extraitMP3: nextProps.extraitMP3 };
}
else return null;
}
showDeleteConfirmation(value, id, index, thisHandler) {
confirm({
title: 'Voulez vous supprimer cette audio ?',
content: '',
okText: 'Oui, je confirme',
okType: 'danger',
cancelText: 'Non',
onOk() {
deleteMp3Request(id);
const { extraitMP3 } = thisHandler.state;
Object.keys(extraitMP3).splice(index, 1);
NotificationManager.success("le fichier audio est supprimé avec succès !", "");
},
onCancel() {
},
});
}
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
this.props.showUpdateLoader();
this.props.updateMp3Visibilite(values);
}
});
};
render() {
const { loader, extraitMP3 } = this.state;
const selectOptions = new Map([
[1, "Visible dans la recherche et sur ma fiche"],
[2, "Visible sur ma fiche uniquement"],
[3, "Masqué"],
]);
console.log('extraitMP3', extraitMP3)
function handleChangeSelect(value) {
console.log(`selected ${value}`);
}
return (
<div>
{loader ? <CircularProgress className="gx-loader-400" /> : Object.keys(extraitMP3).map((ids, index) => {
return (
<Card>
<li key={ids}>
<Card styleName="gx-card-list icon icon-data-display gx-mr-2 gx-text-blue gx-fs-xl">
<div className="gx-media-body">
{extraitMP3[ids].Typenom}
{extraitMP3[ids].TypeIcon != null &&
displayIcon(extraitMP3[ids].TypeIcon)
}
</div>
{Object.keys(extraitMP3[ids].TypeMp3List).map(idJson => {
return (
<div className="gx-main-content gx-mb-4">
<ContainerHeader match={this.props.match} />
<div className="gx-contact-item gx-dragndrop-item">
<DragHandle />
<div className="gx-col gx-job-title ">
{extraitMP3[ids].TypeMp3List[idJson].intitule}
</div>
{extraitMP3[ids].TypeMp3List[idJson].interpretation1Icon !== '' &&
<Tooltip title={extraitMP3[ids].TypeMp3List[idJson].interpretation1Nom}>
{displayIcon(extraitMP3[ids].TypeMp3List[idJson].interpretation1Icon)}
</Tooltip>
}
{extraitMP3[ids].TypeMp3List[idJson].interpretation2Icon !== '' &&
<Tooltip title={extraitMP3[ids].TypeMp3List[idJson].interpretation2Nom}>
{displayIcon(extraitMP3[ids].TypeMp3List[idJson].interpretation2Icon)}
</Tooltip>
}
{extraitMP3[ids].TypeMp3List[idJson].interpretation3Icon !== '' &&
<Tooltip title={extraitMP3[ids].TypeMp3List[idJson].interpretation3Nom}>
{displayIcon(extraitMP3[ids].TypeMp3List[idJson].interpretation3Icon)}
</Tooltip>
}
{extraitMP3[ids].TypeMp3List[idJson].langueIcon !== '' &&
<div className="gx-col gx-job-title gx-d-sm-flex gx-text-truncate gx-px-8">
<Tooltip title={extraitMP3[ids].TypeMp3List[idJson].langueNom}>
<i className={`flag flag-24 gx-mr-2 ${extraitMP3[ids].TypeMp3List[idJson].langueIcon}`} />
</Tooltip>
</div>
}
<div className="gx-col gx-job-title gx-d-sm-flex gx-text-truncate gx-px-8">
<Select
showSearch
style={{ width: '100%' }}
placeholder="Selection la choix de votre numéro de téléphone "
optionFilterProp="children"
onChange={handleChangeSelect}
defaultValue={selectOptions.get(extraitMP3[ids].TypeMp3List[idJson].visibilite)}
filterOption={(input, Option) => Option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
>
{[...selectOptions].map(([value, label]) => <Option value={value}> {label} </Option>)}
</Select>
</div>
<div className="gx-col gx-job-title gx-d-sm-flex gx-text-truncate gx-px-8">
<i className="icon icon-edit gx-fs-xl gx-text-gris" />
</div>
<div className="gx-col gx-job-title gx-d-sm-flex gx-text-truncate gx-px-8">
<span className="gx-pointer">
<i className="icon icon-trash gx-pointer gx-text-danger gx-fs-xxl"
id={extraitMP3[ids].TypeMp3List[idJson].id}
onClick={e => this.showDeleteConfirmation(e.target.value, extraitMP3[ids].TypeMp3List[idJson].id, index, this)} />
</span>
</div>
</div>
</div>
)
})}
<NotificationContainer />
<Button type="primary" htmlType="submit" labelCol={{ xs: 24, sm: 5 }} wrapperCol={{ xs: 24, sm: 12 }}>
Enregistrer
</Button>
</Card>
</li>
</Card>
)
})}</div>
)
}
}
const VisibiliteFormMp3 = Form.create()(ListExtrait);
const mapStateToProps = ({ comedien }) => {
const {
extraitMP3,
alertMessageUpdate,
showMessageUpdate
} = comedien;
return {
extraitMP3,
alertMessageUpdate,
showMessageUpdate
}
};
export default connect(
mapStateToProps,
{
userSignOut,
getExtraitMp3,
hideMessageUpdate,
showUpdateLoader,
updateMp3Visibilite
})(VisibiliteFormMp3);
extraitMP3 is an object of objects that's why I used Object.keys(extraitMP3)
I didn't know how to update the state correctly.
this is the view :
You should put your data in state and then change the state. After changing the state the page automatically re-rendered and changed data of your state will be shown.
So in your delete function simply delete your chosen data and give your remaining data to your state.
Hope this helps, feel free to ask questions if I couldn't explain myself clearly.
I believe you can do this by calling something like and then just call this from within your delete
refreshMp3(){
this.setState({getExtraitMp3: !this.state.getExtraitMp3});}
One of the ideas of React is to make the functionality you ask for simple to implement and it would update automatically. I'm going to abstract a bit from your example. Think about your data in terms of what updates along with the UI. This way we can simplify your component. You have some items that you put in a table. Each item is a row and can be inside an array. We put that array in the state.
class ListExtrait extends Component {
constructor() {
super();
this.state = {
rowsForTable: [...],
somethingElse...
}
...
Then in the JSX in the render method you can render the table rows using map:
rowsForTable.map(item => <div/li/whatever>{item.name or something else}</div>
This way whenever an item is gone from rowsForTable the component will automatically update it's view and the table rows will be up to date.
You can simply call the function while clicking the delete button say deleteHandler. On that function call the api you have made to delete the item and then after successfull delete again call the api that will show the item from database after certain time interval.
Code:
import React, { Component } from 'react'
export default class show_schedule extends Component {
render() {
state={
}
show_item_after_delete=()=>{
setTimeout(()=>{
axios.get(`http://127.0.0.1:8000/account/api/show_item/`).then(res=>{
console.log('delete schedule data ',res.data)
})
},500)
}
deleteHandler=()=>{
axios.delete(`http://127.0.0.1:8000/account/api/delete_item/${id}`).then(res=>{
console.log(res.data)
})
this.show_item_after_delete()
}
return (
<div>
<button onClick={this.deleteHandler}>Delete</button>
</div>
)
}
}

Passing data to parent - recipebook React

I am working on the recipe book app and trying to implement the edit entry function.
How it works is to input recipe name (e.g Pasta), followed by ingredients (e.g egg, flour, salt). The ingredients have to be input with commas and will be shown as a list.
Pasta
-Egg
-Flour
i can see that it is somewhat working, because i can see the new entries in the input text (e.g initially was egg,flour,salt -> egg,flour,salt,water) when i tried to edit it again.
However, the extra ingredients (in the above example: water) is not showing up in the list. Do i have to figure a way to re-render the list?
updates:
I think i know where the error might be. There is some issue passing the data and setting the state.
<EditRecipe recipe={this.props.recipe} editRecipe={this.editRecipe.bind(this, this.props.recipe.id, recipe)}/>
App.js
import React, { Component } from 'react';
// import logo from './logo.svg';
import './App.css';
import uuid from 'uuid';
import Modal from 'react-modal';
import RecipeList from './components/RecipeList/RecipeList';
import AddRecipe from './components/AddRecipe/AddRecipe';
class App extends Component {
constructor(props){
super(props);
this.state = {
recipes:[]
};
}
getRecipes(){
this.setState({recipes:[
{
id: uuid.v4(),
food: "pumpkin pie",
ingredients: ["pumpkin puree", "sweetened condensed milk", "eggs", "pumpkin pie spice", "pie crust"]
},
{
id: uuid.v4(),
food: "spaghetti",
ingredients: ["noodles", "tomato sauce", "meatballs"]
},
{
id: uuid.v4(),
food: "onion pie",
ingredients: ["onion", "pie crust"]
},
]});
}
componentWillMount(){
this.getRecipes();
}
handleAddRecipe(recipe){
let recipes = this.state.recipes;
recipes.push(recipe);
this.setState({recipes: recipes});
}
handleDeleteRecipe(id){
let recipes = this.state.recipes;
let index = recipes.findIndex(x => x.id === id);
recipes.splice(index,1);
this.setState({recipes: recipes});
}
handleEditRecipe(id, recipe){
let recipes = this.state.recipes;
let index = recipes.findIndex(x => x.id === id);
recipes.splice(index,1,recipe);
this.setState({recipes: recipes});
}
render() {
return (
<div className="App">
<RecipeList recipes={this.state.recipes} onDelete={this.handleDeleteRecipe.bind(this)} onEdit={this.handleEditRecipe.bind(this)}/>
<AddRecipe addRecipe={this.handleAddRecipe.bind(this)}/>
</div>
);
}
}
export default App;
RecipeList.js
import React, { Component } from 'react';
import Collapsible from 'react-collapsible';
import RecipeItem from '../RecipeItem/RecipeItem'
import './RecipeList.css';
class RecipeList extends Component{
deleteRecipe(id){
this.props.onDelete(id);
}
editRecipe(id, recipe){
this.props.onEdit(id, recipe);
}
render(){
let recipeItem;
if(this.props.recipes){
recipeItem=this.props.recipes.map(recipe => {
return(
<RecipeItem onEdit={this.editRecipe.bind(this)} onDelete={this.deleteRecipe.bind(this)} key={recipe.id} recipe={recipe} />
)
});
}
return(
<div className="recipeList box">
{recipeItem}
</div>
)
}
}
export default RecipeList;
RecipeItem.js
import React, { Component } from 'react';
import Collapsible from 'react-collapsible';
import EditRecipe from '../EditRecipe/EditRecipe';
class RecipeItem extends Component{
deleteRecipe(id){
this.props.onDelete(id);
}
editRecipe(id, recipe){
this.props.onEdit(id, recipe);
}
render(){
let recipe=this.props.recipe
let foodName=recipe.food;
let ingredientItem;
if(recipe.ingredients){
ingredientItem=recipe.ingredients.map(ingredient=>{
return(
<a className="panel-block">
{ingredient}
</a>
)
})
}
return(
<ul>
<li className="Recipe">
<Collapsible trigger={foodName} transitionTime="200" easing="ease-in-out">
<nav className="panel">
<p className="panel-heading">
Ingredients
</p>
{ingredientItem}
<div className="panel-block">
<button className="button is-warning is-outlined" onClick={this.deleteRecipe.bind(this, this.props.recipe.id)}>
Delete
</button>
<EditRecipe recipe={this.props.recipe} editRecipe={this.editRecipe.bind(this, this.props.recipe.id, recipe)}/>
</div>
</nav>
</Collapsible>
</li>
</ul>
);
}
}
export default RecipeItem;
EditRecipe.js
import React, { Component } from 'react';
import RecipeForm from '../RecipeForm/RecipeForm';
// import './EditRecipe.css';
import Modal from 'react-modal';
import uuid from 'uuid';
// import Modal from 'boron/DropModal';
// import './RecipeList.css';
class RecipeEdit extends Component{
constructor(props){
super(props);
this.state = {
revisedRecipe:{
id: this.props.recipe.id,
food: this.props.recipe.food,
ingredients: this.props.recipe.ingredients
},
modalIsOpen: false,
speed: 100
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
openModal(){
this.setState({modalIsOpen: true});
}
closeModal(){
this.setState({modalIsOpen: false});
}
handleSubmit(e){
const revised = this.state.revisedRecipe;
this.props.editRecipe(revised);
e.preventDefault();
}
handleNameChange(e){
this.setState({revisedRecipe:{
food: e.target.value
}
});
}
handleIndChange(e){
this.setState({revisedRecipe:{
ingredients: e.target.value
}
});
}
render(){
const speed = this.state.speed;
let recipe=this.props.recipe;
let foodName=this.state.revisedRecipe.food;
let ingredients=recipe.ingredients;
return(
<div>
<button className="button is-primary" onClick={this.openModal}>Edit Recipe</button>
<Modal
isOpen={this.state.modalIsOpen}
onAfterOpen={this.afterOpenModal}
onRequestClose={this.closeModal}
closeTimeoutMS={speed}
contentLabel="Example Modal"
>
<div className="field">
<h2 className="title is-2">Edit Recipe</h2>
<form>
<label className="label">Recipe</label>
<div className="control">
<input className="input" type="text" placeholder="Recipe Name" ref="recipeName" value={this.state.revisedRecipe.food} onChange={this.handleNameChange.bind(this)}/>
</div>
<div className="field">
<label className="label">Ingredients</label>
<div className="control has-icons-left has-icons-right">
<input className="input" type="text" placeholder="Enter ingredients. (if more than 1 ingredient, separate them with commas)" ref="ingredients" value={this.state.revisedRecipe.ingredients} onChange={this.handleIndChange.bind(this)}/>
<span className="icon is-small is-left">
<i className="fa fa-flask"></i>
</span>
</div>
</div>
<div className="field is-grouped">
<div className="control">
<button className="button is-primary" onClick={this.closeModal}>Edit Recipe</button>
</div>
<div className="control">
<button className="button" onClick={this.closeModal}>Cancel</button>
</div>
</div>
</form>
</div>
</Modal>
</div>
);
}
}
export default RecipeEdit;
I believe you're actually getting an error when trying to re-render after updating a list. The ingredients property in the recipes are an array (as shown in getRecipes()) but you're setting the new state of ingredients (in EditRecipe) as a string: "egg,flour,salt,water" and then trying to render the ingredients as an array: ingredients.map().
When you render an input field with an array <input value={["egg", "flour"]} /> it does show the values separated by comma, but the event.target.value in onChange is actually a string.
In EditRecipe's, handleIndChange could be fixed with:
this.setState({revisedRecipe: {ingredients: e.target.value.split(',')}});
This does have another problem, though in that you are overriding the revisedRecipe completely. So all of the setState calls should be something like:
const recipe = this.state.revisedRecipe;
recipe.ingredients = e.target.value.split(',');
this.setState({revisedRecipe: recipe);

Categories

Resources