Can't edit in td input of table in Reactjs - reactjs

I have two component here Addform (Childcomponent)and App component(parent) I have perform row add and delete operation Why my edit doesn't works ?I have pass the specific row value on which edit has to perform in td input element but I can't perform a onChange event on td input and how to update the data on specific row? How edit can be implement Here?
code
import React, { useState } from "react";
import Select from "react-select";
const AddForm = (props) => {
const newdata = props.editdata;
const [id, setId] = React.useState("");
const [name, setName] = React.useState("");
const [gender, setGender] = React.useState("");
console.log(gender);
return (
<tr>
<td>
<input
type="text"
value={id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select options={props.List} value={gender} onChange={setGender} />
</td>
<td>
<button
onClick={(e) => {
props.addRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
setId("");
setName("");
setGender("");
}}
>
Add
</button>
</td>
</tr>
);
};
const List = [
{
value: 1,
label: "Male"
},
{ value: 2, label: "Female" }
];
const App = (props) => {
const [data, setData] = React.useState([]);
const [edit, isEdit] = useState(false);
const [editdata, setEditData] = useState([]);
const [id, setId] = React.useState(editdata.id || "");
const [name, setName] = React.useState(editdata.name || "");
const [gender, setGender] = React.useState(editdata.gender || "");
const editRow = (e) => {
setData({ ...data, e });
};
return (
<div>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Gender</th>
<th>Action</th>
</tr>
{data &&
data.map((row, idx) => {
if (edit === idx) {
return (
<tr key={idx}>
<td>
<input
type="text"
value={editdata.id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={editdata.name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select
options={List}
value={editdata.gender}
onChange={setGender}
/>
</td>
<td>
{" "}
<button
onClick={(e) => {
editRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
}}
>
save
</button>
</td>
</tr>
);
} else {
return (
<tr key={idx}>
<td>{row.id}</td>
<td>{row.name}</td>
<td>{row.gender}</td>
<td>
<button
onClick={(e) => {
let _data = data.filter((item) => {
return item.id !== row.id;
});
setData(_data);
}}
>
Delete
</button>
</td>
<td>
<button
onClick={(e) => {
isEdit(idx);
setEditData(row);
// console.log(editdata);
<AddForm />;
}}
>
Edit
</button>
</td>
</tr>
);
}
})}
<AddForm
data={data}
List={List}
setData={setData}
editdata={editdata}
addRow={(e) => {
setData([...data, e]);
}}
/>
</table>
</div>
);
};
export default App
;

Related

How to get sum of column values for each row in React JS?

How can i get sum of column values for each row and push each row's total in rowTotalArray.
Image is Here
The number of rows and input fields are dynamic. When user enters number in input field for each column in row , last column (Total) must show sum of column value for each row.
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import Table from 'react-bootstrap/Table';
function RowWiseSum() {
const datas = useSelector(state => state.dataList.datas);
const [group, setGroup] = useState([{
g1: 0,
g2: 0,
g3: 0,
}]);
const [sum, setSum] = useState(0);
const [rowTotalArray, setRowTotalArray] = useState([]);
useEffect(() => {
let sum = parseFloat(group.g1) + parseFloat(group.g2) + parseFloat(group.g3);
setSum(sum);
}, [group])
return (
<Table striped bordered size="sm" style={{ fontSize: '12px' }}>
<thead>
<tr>
<th>Sn</th>
<th>Title</th>
<th>No. in G1</th>
<th>No. in G2</th>
<th>No. in G3</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{
datas.map((data, i) =>
(
<tr key={i}>
<td>{data.sno}</td>
<td>{data.description}</td>
<td>
<input type='text' name={`g1-${i+1}`} onChange={(e) => setGroup({ ...group, g1: e.target.value })} />
</td>
<td>
<input type='text' name={`g2-${i+1}`} onChange={(e) => setGroup({ ...group, g2: e.target.value })} />
</td>
<td>
<input type='text' name={`g3-${i+1}`} onChange={(e) => setGroup({ ...group, g3: e.target.value })} />
</td>
<td>
<input type='text' readOnly value={sum} name={`sum-${i+1}`} />
</td>
</tr>
))
}
</tbody>
</Table>
)
}
export default RowWiseSum
Your group state should be array of each row point, so you can caculate total of each row
const defaultGroup = datas.map((i) => ({
g1: 0,
g2: 0,
g3: 0
}));
const [group, setGroup] = useState(defaultGroup);
const onChange = (type, value, index) => {
const newGroup = group.map((g, idx) => {
if (index === idx)
return {
...g,
[type]: parseInt(value || 0)
};
return g;
});
setGroup(newGroup);
};
const total = group.reduce((acc, cur) => {
acc += cur.g1 + cur.g2 + cur.g3;
return acc;
}, 0);
return (
<div className="App">
<table striped bordered size="sm" style={{ fontSize: "12px" }}>
<thead>
<tr>
<th>Sn</th>
<th>Title</th>
<th>No. in G1</th>
<th>No. in G2</th>
<th>No. in G3</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{datas.map((data, i) => (
<tr key={i}>
<td>{data.sno}</td>
<td>{data.description}</td>
<td>
<input
type="number"
name={`g1-${i + 1}`}
defaultValue={group[i].g1}
onChange={(e) => onChange("g1", e.target.value, i)}
/>
</td>
<td>
<input
type="number"
name={`g2-${i + 1}`}
defaultValue={group[i].g2}
onChange={(e) => onChange("g2", e.target.value, i)}
/>
</td>
<td>
<input
type="number"
name={`g3-${i + 1}`}
defaultValue={group[i].g3}
onChange={(e) => onChange("g3", e.target.value, i)}
/>
</td>
<td>
<input
type="text"
readOnly
name={`sum-${i + 1}`}
value={group[i].g1 + group[i].g2 + group[i].g3}
/>
</td>
</tr>
))}
</tbody>
</table>
<div>TOTAL: {total}</div>
</div>
);
I've created a codesandbox, you can check it. Hope it help!
your group state should be like this
const [group, setGroup] = useState({ g1: 0, g2: 0, g3: 0, });
instead of
const [group, setGroup] = useState([{g1: 0, g2: 0, g3: 0,}])

CRUD operation on dynamic form reactjs?

AS a Learner in ReactJS ,I have tried to perform Crud operation on the dynamic form But failed to perform a Update operation i.e edit button .i want to pass specific row data to the ADDform component from the Appcomponent Table and edit the data in addForm Component and save the data.I am unable to show data in respected addform component inputs when click on edit button?
How to perform Edit operation ?
import React, { useState } from "react";
import Select from "react-select";
const AddForm = (props) => {
const newdata = props.editdata;
const [id, setId] = React.useState(newdata["id"]?newdata.id:"");
const [name, setName] = React.useState(newdata["name"]?newdata.name:"");
const [gender, setGender] = React.useState(()=>{
let _gender= newdata["gender"]?.toLowerCase() || ""
let id_ = props.List.filter( x => {return x["label"]?.toLowerCase() ===_gender } ) ||""
console.log(id_)
return id_[0]["label"]
});
console.log(gender)
return (
<tr>
<td>
<input
type="text"
value={id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select options={props.List} value={gender} onChange={setGender} />
</td>
<td>
<button
onClick={(e) => {
props.addRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
setId("");
setName("");
setGender("");
}}
>
Add
</button>
</td>
</tr>
);
};
const List = [
{
value: 1,
label: "Male"
},
{ value: 2, label: "Female" }
];
const App = (props) => {
const [data, setData] = React.useState([]);
const [edit, isEdit] = useState(false);
const [editdata, setEditData] = useState([]);
return (
<div>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Gender</th>
<th>Action</th>
</tr>
{data &&
data.map((row, idx) => {
return (
<tr key={idx}>
<td>{row.id}</td>
<td>{row.name}</td>
<td>{row.gender}</td>
<td>
<button
onClick={(e) => {
let _data = data.filter((item) => {
return item.id !== row.id;
});
setData(_data);
}}
>
Delete
</button>
</td>
<td>
<button
onClick={(e) => {
// isEdit(true);
setEditData(row);
// console.log(editdata);
<AddForm />;
}}
>
Edit
</button>
</td>
</tr>
);
})}
<AddForm
data={data}
List={List}
setData={setData}
editdata={editdata}
addRow={(e) => {
setData([...data, e]);
}}
/>
</table>
</div>
);
};
export default App;

Edit table row data in td with input in Reactjs

As beginner in Reactjs , I have two component here Addform (Childcomponent)and App component(parent) I have perform row add and delete operation Here.Why my edit doesn't works ?I have pass the specific row value on which edit has to perform in td input element but i can't perform a onChange event on td input and how to update the data on specific row? How edit can be implement Here? So ,far what I done is given below:
demo code sand box
**code**
import React, { useState } from "react";
import Select from "react-select";
const AddForm = (props) => {
const newdata = props.editdata;
const [id, setId] = React.useState("");
const [name, setName] = React.useState("");
const [gender, setGender] = React.useState("");
console.log(gender);
return (
<tr>
<td>
<input
type="text"
value={id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select options={props.List} value={gender} onChange={setGender} />
</td>
<td>
<button
onClick={(e) => {
props.addRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
setId("");
setName("");
setGender("");
}}
>
Add
</button>
</td>
</tr>
);
};
const List = [
{
value: 1,
label: "Male"
},
{ value: 2, label: "Female" }
];
const App = (props) => {
const [data, setData] = React.useState([]);
const [edit, isEdit] = useState(false);
const [editdata, setEditData] = useState([]);
const [id, setId] = React.useState(editdata.id || "");
const [name, setName] = React.useState(editdata.name || "");
const [gender, setGender] = React.useState(editdata.gender || "");
const editRow = (e) => {
setData({ ...data, e });
};
return (
<div>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Gender</th>
<th>Action</th>
</tr>
{data &&
data.map((row, idx) => {
if (edit === idx) {
return (
<tr key={idx}>
<td>
<input
type="text"
value={editdata.id}
onChange={(e) => {
setId(e.target.value);
}}
></input>
</td>
<td>
<input
type="text"
value={editdata.name}
onChange={(e) => {
setName(e.target.value);
}}
></input>
</td>
<td>
<Select
options={List}
value={editdata.gender}
onChange={setGender}
/>
</td>
<td>
{" "}
<button
onClick={(e) => {
editRow({
id: id,
name: name,
genderId: gender.value,
gender: gender.label
});
}}
>
save
</button>
</td>
</tr>
);
} else {
return (
<tr key={idx}>
<td>{row.id}</td>
<td>{row.name}</td>
<td>{row.gender}</td>
<td>
<button
onClick={(e) => {
let _data = data.filter((item) => {
return item.id !== row.id;
});
setData(_data);
}}
>
Delete
</button>
</td>
<td>
<button
onClick={(e) => {
isEdit(idx);
setEditData(row);
// console.log(editdata);
<AddForm />;
}}
>
Edit
</button>
</td>
</tr>
);
}
})}
<AddForm
data={data}
List={List}
setData={setData}
editdata={editdata}
addRow={(e) => {
setData([...data, e]);
}}
/>
</table>
</div>
);
};
export default App;

Table with with array of inputs duplicating row previous row when adding new row

I have a table full of text inputs. All the inputs are stored in a React state array (newUserPledges). If I have values in all the text inputs and add a new row, the new row is duplicating the previous row input values. I can't see why it would be doing that.
Here is my component with all the irrelevant code dotted out.
import React, { useEffect, useState } from 'react';
...
const initialNewPledgeState = {
campaign: '',
date: dateFormatted(new Date()),
pledges: 0,
howPaid: '',
confirmation: '',
sponsor: '',
notes: ''
};
const buttonRef = React.createRef();
const AdminControlPanel = () => {
...
const [addPledgeOptions, setAddPledgeOptions] = useState([]);
const [selectedDeleteUser, setSelectedDeleteUser] = useState('');
const [selectedEditUser, setSelectedEditUser] = useState('');
const [selectedPledgeUser, setSelectedPledgeUser] = useState('');
const [selectedAddPledgeUser, setSelectedAddPledgeUser] =
useState('');
const [allUsers, setAllUsers] = useState([]);
const [usersWithPledges, setUsersWithPledges] = useState([]);
const [usersWithPledgesCount, setUsersWithPledgesCount] =
useState(0);
const [userPledges, setUserPledges] = useState([]);
const [newUserPledges, setNewUserPledges] = useState([
initialNewPledgeState
]);
const alert = useAlert();
const setUpUsersArrays = () => {
getUsers('user').then((r) => {
setAllUsers(r.data.users);
const firstAddPledgeOption = [
{ value: '', label: 'Select a user to add pledges for...' }
];
const usersOptions = r.data?.users?.map((u) => {
return {
value: u.email,
label: `${u.email} - ${u.last_name}, ${u.first_name}`
};
});
if (usersOptions?.length) {
setAddPledgeOptions(
firstAddPledgeOption.concat(usersOptions)
);
} else {
setOptions([]);
setEditOptions([]);
}
});
getUsersWithPledges().then((r) => {
const firstPledgeOption = [
{ value: '', label: 'Select a user to view pledges for...' }
];
const usersOptions = r.data?.users?.map((u) => {
return {
value: u.email,
label: `${u.email} - ${u.last_name}, ${u.first_name}`
};
});
if (usersOptions) {
setUsersWithPledgesCount(usersOptions.length);
setUsersWithPledges(firstPledgeOption.concat(usersOptions));
}
});
};
useEffect(() => {
getDatabaseStats().then((r) => {
setDbStats(r.data.stats);
});
setUpUsersArrays();
}, []);
useEffect(() => {
console.log(selectedDeleteUser.value);
}, [selectedDeleteUser]);
...
const handlePledgeChange = (e, i) => {
// console.log(e.target);
const value = e.target.value;
const pledge = newUserPledges[i];
console.log({ pledge });
pledge[e.target.name] = value;
const tempPledges = [...newUserPledges];
tempPledges[i][e.target.name] = value;
// tempPledges.splice(i, 1, pledge);
setNewUserPledges(tempPledges);
// const value = e.target.value;
// setInputState({
// ...inputState,
// [e.target.name]: value
// });
};
const addNewPledgeRow = (e) => {
e.preventDefault();
const tempPledges = [...newUserPledges].concat(
initialNewPledgeState
);
console.log({ tempPledges });
setNewUserPledges(tempPledges);
};
const deletePledgeRow = (e) => {
e.preventDefault();
const tempPledges = [...newUserPledges];
tempPledges.pop();
setNewUserPledges(tempPledges);
};
const customStyles = {
menuList: (base) => ({
...base,
// kill the white space on first and last option
padding: 0,
minHeight: '300px'
})
};
return (
<div className={'container admin'}>
<h2>Admin Control Panel</h2>
...
<div
className={
'col-12 col-md-9 mx-auto my-4 p-1 border border-secondary bg-light accordion'
}
id={'admin-accordion-add-pledges'}
>
<div className={'accordion-item'}>
<h2 className={'accordion-header'} id={'headingAddPledges'}>
<button
className={'accordion-button collapsed'}
type={'button'}
data-bs-toggle={'collapse'}
data-bs-target={'#collapseAddPledges'}
aria-expanded={'true'}
aria-controls={'collapseAddPledges'}
>
<h4 className={'text-center'}>Add Pledges For User</h4>
</button>
</h2>
<div
id={'collapseAddPledges'}
className={'accordion-collapse collapse mt-1 px-2'}
aria-labelledby={'headingAddPledges'}
data-bs-parent={'#admin-accordion-add-pledges'}
>
{!!addPledgeOptions.length ? (
<Select
className={'mb-2'}
value={selectedAddPledgeUser}
onChange={(e) => setSelectedAddPledgeUser(e)}
options={addPledgeOptions}
styles={customStyles}
/>
) : (
<h4 className={'text-center'}>
No users to add pledges for
</h4>
)}
{selectedAddPledgeUser?.value?.length > 0 && (
<form>
<div className={'my-2 user-pledges'}>
<table className={'table table-bordered'}>
<thead>
<tr>
<th width={100}>Campaign</th>
<th width={120}>Date</th>
<th width={80}>Pledges</th>
<th>How Paid</th>
<th>Confirmation</th>
<th>Sponsor</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{!!newUserPledges.length &&
newUserPledges.map((p, i) => (
<tr key={i}>
<td>
<input
type={'text'}
className={'form-control'}
value={p.campaign}
name={'campaign'}
id={`campaign-${i}`}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'date'}
max={dateFormatted(new Date())}
className={'form-control'}
value={p.date}
name={'date'}
id={`date-${i}`}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.pledges}
name={'pledges'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.howPaid}
name={'howPaid'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.confirmation}
name={'confirmation'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.sponsor}
name={'sponsor'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
<td>
<input
type={'text'}
className={'form-control'}
value={p.notes}
name={'notes'}
onChange={(e) =>
handlePledgeChange(e, i)
}
/>
</td>
</tr>
))}
</tbody>
</table>
<div className={'d-flex justify-content-evenly'}>
<button
className={'btn btn-primary'}
onClick={addNewPledgeRow}
disabled={newUserPledges.length > 9}
>
<FontAwesomeIcon icon={faPlusSquare} />
Add New Row
</button>
<button
className={'btn btn-primary'}
onClick={deletePledgeRow}
disabled={newUserPledges.length === 1}
>
<FontAwesomeIcon icon={faMinusSquare} />
Delete Row
</button>
<button className={'btn btn-success'}>
Submit Pledges
</button>
<button className={'btn btn-danger'}>
Reset Table
</button>
</div>
</div>
</form>
)}
</div>
</div>
</div>
<br />
</div>
);
};
export default AdminControlPanel;
Here is an example of what is happening. I fill in values in the first row, and then hit add row and it adds a second row with duplicated values.
Asked my question in the Reactiflux Discord and got an answer right away. I was mutating my rows state in the handlePledgeChange function.
I have changed that function to this and it works great now.
const handlePledgeChange = (e, i) => {
const value = e.target.value;
const tempPledges = newUserPledges.map((item, idx) => {
if (i === idx) return { ...item, [e.target.name]: value };
return item;
});
setNewUserPledges(tempPledges);
};

React editing specific item

When I hit the Edit button I trigger a flag for enabling editing. The desired behaviour would be to enable editing only on one item at the time. However, all the item get enabled for editing by the flag.
<li key={recipe._id} className="list__item recipe" id={randomString()}>
<Card body id={`card-${recipe._id}`} >
<CardTitle name={randomString()}><input type="text" name="name" defaultValue={recipe.name} readOnly={disabled} className="recipe__name" onChange={(e) => {changeItem(e, recipe)}} /></CardTitle>
<CardImg top width="100%" src={require('../assets/318x180.svg')} alt="Card image cap" />
<input id={String(recipe._id)} className="toggle" type="checkbox" onChange={(e) => {handleChange(e)}} />
<label htmlFor={String(recipe._id)} className="lbl-toggle bold">Ingredients</label>
<ul key={recipe._id} className="ingredients expand-content" id='ingredientList'>
{iselect()}
</ul>
<table>
<tbody>
<tr>
<td className={'center'}><span className={'bold'}>Actual Cost:</span></td>
<td className={'center'}><span className={'bold'}>Proposed Price:</span></td>
</tr>
<tr>
<td className={'center'}><span className="recipe__cost">£{cost(Math.floor(Math.random()*10))}</span></td>
<td className={'center'}><span className="recipe__proposed">£{proposed(cost(Math.floor(Math.random()*10)))}</span></td>
</tr>
</tbody>
</table>
<Button color="primary" onClick={() => { saveEditRecipe(recipe); }} className={`bold save-button ${disabled ? "hidden" : "show"}`}>Save</Button>
<Button color="primary" onClick={(e) => { editRecipe(e, recipe); }} id={`card-${recipe._id}`} className={'edit-button'}>Edit</Button>
<Button color="danger" onClick={() => { deleteRecipe(recipe); }} className={'delete'}>X</Button>
</Card>
</li>
// /client/src/components/Recipe.js
import React, { useState, useEffect} from "react";
import { Card, Button, CardTitle, CardText, CardImg } from 'reactstrap';
import { FaPen} from "react-icons/fa";
import './Recipe.css';
// SERVICES
import recipeService from '../services/recipeService';
import ingredientService from '../services/ingredientService';
function Recipe() {
const initialEditState = { id: null, name: '', ingredients: null }
const [recipes, setrecipes] = useState(null);
const [newRecipe, setNewRecipe] = useState({});
const [ingredients, setingredients] = useState(null);
const [fields, setFields] = useState([{name:"", quantity: null}]);
const [editFields, setEditFields] = useState([{ name: "", quantity: null }]);
const [disabled, setDisabled] = useState(true);
const [currentRecipe, setCurrentRecipe] = useState(initialEditState)
// const inputRef = useRef();
// function handleGamClick() {
// setDisabled(!disabled);
// }
useEffect(() => {
if(!recipes) {
getRecipes();
}
if(!ingredients) {
getIngredients();
}
if(currentRecipe._id !== undefined) {
setDisabled(false);
}
// console.log(disabled);
}, [recipes, ingredients, currentRecipe])
const getRecipes = async () => {
let res = await recipeService.getAll();
setrecipes(res);
}
const getIngredients = async () => {
let res = await ingredientService.getAll();
setingredients(res);
}
// const loadIngredients = (recipe) => {
// let initial = recipe.ingredients;
// let ingredients;
// const values = [...editFields];
// for (var i in initial){
// ingredients = initial[i].ingredients;
// }
// initial.map((ingredient) => {
// setEditFields(ingredient);
// }
// )
// setEditFields(values);
// console.log(values);
// }
// Method for calculating recipe cost
const cost = (nameKey, ingredient) => {
return 20;
}
// Method for calculating recipe proposed price
const proposed = (recipe) => {
return recipe * 2.5;
}
// Method for creating recipe
const createRecipe = async (recipe) => {
const ingredients = fields;
const object = {...newRecipe, ingredients }
recipeService.create(object);
window.location.reload();
}
// Method for
const changeItem = (e, recipe) => {
recipe[e.target.name] = e.target.value;
return recipe;
}
// Method for editing recipe
const editRecipe = async (e, recipe) => {
setCurrentRecipe(recipe);
// if (e.target) {
// setDisabled(false);
// }
// setEditFields(recipe.ingredients);
// const ingredients = editFields;
// const object = { recipe, ingredients }
// if (recipe._id === currentRecipe._id) {
// setDisabled(false);
// }
// console.log(editFields);
// recipeService.edit(object);
// window.location.reload();
}
const saveEditRecipe = async (recipe) => {
setCurrentRecipe(initialEditState);
setDisabled(true);
}
// Method for deleting recipe
const deleteRecipe = async (recipe) => {
if (window.confirm('Are you sure you wish to delete this item?')) {
recipeService.delete(recipe);
window.location.reload();
}
}
// Method for
const handleChange = (e) => setNewRecipe({
...newRecipe,
// [e.target.name]:e.target.name === "name" ? e.target.value : Number(e.target.value ),
[e.target.name]:e.target.value
});
// Method for
function handleChanger(idx, event) {
// console.log(recipes)
// console.log(event.target.name);
const values = event.target.className.includes("edit") ? [...editFields] : [...fields];
if (event.target.name === "name") {
values[idx].name = event.target.value;
} else {
values[idx].quantity = event.target.value;
}
event.target.className.includes("edit") ? setEditFields(values) : setFields(values);
}
// Method for
function handleAdd(e, idx) {
console.log(idx);
const values = e.target.className.includes("edit") ? [...editFields] : [...fields];
values.push({name:"", quantity: null});
e.target.className.includes("edit") ? setEditFields(values) : setFields(values);
}
// Method for
function handleRemove(e, i) {
const values = e.target.className.includes("edit") ? [...editFields] : [...fields];
values.splice(i, 1);
e.target.className.includes("edit") ? setEditFields(values) : setFields(values);
}
// rendering ingredients dropdown
const renderIngredientName = (ingredient) => {
let initial =[];
for (ingredient in ingredients) {
initial.push(ingredients[ingredient].name);
}
let createOption = (option) => {
return <option key={option.toLowerCase()} defaultValue={option.toLowerCase()} >{option.toLowerCase()}</option>;
}
return initial.map(createOption);
}
// Method for
const randomString = (recipe) => {
return String("expand"+Math.floor(Math.random()*100))
}
// Rendering recipes
const renderRecipe = recipe => {
const iselect = () => {
let initial = recipe.ingredients;
function splice(idx){
return initial.splice(idx, 1)
}
return initial.map((ingredient, idx) =>
<li key={`${ingredient}-${idx}`}>
<select name="name" className="edit recipe__ingredient__name" value={ingredient.name || ""} disabled={disabled} onChange={(e) => {handleChanger(idx, e)}}>
{renderIngredientName()}
</select>
<input type="number" name="quantity" id="quantity" className="recipe__ingredient__quantity" disabled={disabled} defaultValue={ingredient.quantity} />
{/* <span className={"float"}><Button color="danger" onClick={() => splice(idx)} className={'edit delete-ingredient'}>x</Button></span> */}
</li>
);
}
// eslint-disable-next-line
const edit = () => {
let edit = [{name:"", quantity: null}];
return edit.map((ingredient, idx) =>
<li key={`${ingredient}-${idx}-${recipe._id}`}>
<select name="name" className="edit recipe__ingredient__name" value={ingredient.name || ""} onChange={(e) => {handleChanger(idx, e)}}>
<option value=""></option>
{renderIngredientName()}
</select>
<input type="number" name="quantity" className="edit recipe__ingredient__quantity" value={ingredient.quantity || ""} placeholder="grams" onChange={e => handleChanger(idx, e)} />
<span className={'float'}>
{ idx === edit.length-1 ?
(<Button color="primary" className={'edit create-ingredient'} onClick={(e) => handleAdd(e, idx)}>+</Button>)
:
(<Button color="danger" onClick={(e) => handleRemove(e, idx)} className={'edit delete-ingredient'}>x</Button>)
}
</span>
</li>
)
}
return (
<li key={recipe._id} className="list__item recipe" id={randomString()}>
<Card body id={`card-${recipe._id}`} >
<CardTitle name={randomString()}><input type="text" name="name" defaultValue={recipe.name} readOnly={disabled} className="recipe__name" onChange={(e) => {changeItem(e, recipe)}} /></CardTitle>
<CardImg top width="100%" src={require('../assets/318x180.svg')} alt="Card image cap" />
<input id={String(recipe._id)} className="toggle" type="checkbox" onChange={(e) => {handleChange(e)}} />
<label htmlFor={String(recipe._id)} className="lbl-toggle bold">Ingredients</label>
{/* <span className="bold">Ingredients:</span> */}
<ul key={recipe._id} className="ingredients expand-content" id='ingredientList'>
{iselect()}
{/* {editFields.map((ingredient, idx) => {
return (
<li key={`${ingredient}-${idx}-${recipe._id}`}>
<select name="name" className="edit recipe__ingredient__name" value={ingredient.name || ""} onChange={(e) => {handleChanger(idx, e)}}>
<option value=""></option>
{renderIngredientName()}
</select>
<input type="number" name="quantity" className="edit recipe__ingredient__quantity" value={ingredient.quantity || ""} placeholder="grams" onChange={e => handleChanger(idx, e)} />
<span className={'float'}>
{ idx === editFields.length-1 ?
(<Button color="primary" className={'edit create-ingredient'} onClick={(e) => handleAdd(e, idx)}>+</Button>)
:
(<Button color="danger" onClick={(e) => handleRemove(e, idx)} className={'edit delete-ingredient'}>x</Button>)
}
</span>
</li>
);
})} */}
</ul>
<table>
<tbody>
<tr>
<td className={'center'}><span className={'bold'}>Actual Cost:</span></td>
<td className={'center'}><span className={'bold'}>Proposed Price:</span></td>
</tr>
<tr>
<td className={'center'}><span className="recipe__cost">£{cost(Math.floor(Math.random()*10))}</span></td>
<td className={'center'}><span className="recipe__proposed">£{proposed(cost(Math.floor(Math.random()*10)))}</span></td>
</tr>
</tbody>
</table>
<Button color="primary" onClick={() => { saveEditRecipe(recipe); }} className={`bold save-button ${disabled ? "hidden" : "show"}`}>Save</Button>
<Button color="primary" onClick={(e) => { editRecipe(e, recipe); }} id={`card-${recipe._id}`} className={'edit-button'}>Edit</Button>
<Button color="danger" onClick={() => { deleteRecipe(recipe); }} className={'delete'}>X</Button>
</Card>
</li>
);
};
return (
<div className="recipe">
<ul className="list">
{(recipes && recipes.length > 0) ? (
recipes.map(recipe => renderRecipe(recipe))
) : (
<p>No recipes found</p>
)}
<li key='new' className="add__item list__item recipe">
<Card body>
<CardTitle><input type="text" name="name" id="name" placeholder="New Recipe" className="recipe__name" onChange={(e) => {handleChange(e)}} /></CardTitle>
<CardImg top width="100%" src={require('../assets/318x180.svg')} alt="Card image cap" />
<span className={'bold'}>ingredients
{/* <span className={'float'}><Button color="primary" className={'create-ingredient'} onClick={(e) => handleAdd(e)}>+</Button></span> */}
</span>
<ul className="ingredients" id='ingredientList'>
{fields.map((field, idx) => {
return (
<li key={`${field}-${idx}`}>
<select name="name" className="recipe__ingredient__name" value={field.name || ""} onChange={(e) => {handleChanger(idx, e)}}>
<option value=""></option>
{renderIngredientName()}
</select>
<input type="number" name="quantity" className="recipe__ingredient__quantity" value={field.quantity || ""} placeholder="grams" onChange={e => handleChanger(idx, e)} />
{/* <span className={'float'}><Button color="danger" onClick={(e) => handleRemove(e, idx)} className={'delete-ingredient'}>x</Button></span> */}
<span className={'float'}>
{idx === fields.length - 1 ?
(<Button color = "primary" className = { 'create-ingredient' } onClick = { (e) => handleAdd(e) }>+</Button>)
:
(<Button color="danger" onClick={(e) => handleRemove(e, idx)} className={'delete-ingredient'}>x</Button>)
}
</span>
</li>
);
})}
</ul>
<CardText><span className={'bold'}>Calculated Cost:</span></CardText>
<CardText><span className={'bold'}>Calculated Price:</span></CardText>
<Button color="success" className={'new-recipe, bold'} onClick={() => { createRecipe(newRecipe); }}>Create new recipe</Button>
</Card>
</li>
</ul>
</div>
);
}
export default Recipe;
You didn't share your full code, but it should look something like this:
state = {
editableId:null
}
editRecipe = (event,recipe) => {
this.setState(({editableId:recipe._id}))
}
<Button disabled={!this.state.editableId == recipe._id} color="primary" onClick={(e) => { editRecipe(e, recipe); }} id={`card-${recipe._id}`} className={'edit-button'}>Edit</Button>
When you want no items to be editable, reset the state.editableId to null

Resources