Реагировать на спецификацию редактирования c элемент - PullRequest
0 голосов
/ 06 марта 2020

List of items

Когда я нажимаю кнопку «Редактировать», я запускаю флаг для включения редактирования. Желаемым поведением будет включение редактирования только для одного элемента за раз. Однако все элементы включаются для редактирования под флагом.

<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;

1 Ответ

2 голосов
/ 06 марта 2020

Вы не передали свой полный код, но он должен выглядеть примерно так:

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>

Если вы не хотите, чтобы элементы редактировались, сбросьте state.editableId на ноль

...