Reputation: 2894
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;
Upvotes: 0
Views: 138
Reputation: 4603
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
Upvotes: 2