I’m building the RecipeBox App.
I’ve got the following features so far -
- Lets you add a new recipe(name + ingredients + tags)
- Lets you delete an existing recipe
- Lets you edit an existing recipe <- this is not working right now
Here’s my app on Codepen.
The problem I’m facing with the edit recipe feature is that no matter which recipe you edit, in addition to your selected recipe, the app also edits the very first recipe item with the changes you make.
The three main components you’ll need to focus on are - RecipeBoxApp
, RecipeFlexContainer
and RecipeCard
. RecipeBoxApp
acts as the outermost container component. RecipeFlexContainer
acts as the (flex container
) container component for each RecipeCard
(which acts as the flex item
).
Here’s my RecipeCard
component -
class RecipeCard extends React.Component {
constructor(props) {
super(props);
this.handleRecipeDelete = this.handleRecipeDelete.bind(this);
this.handleRecipeNameChange = this.handleRecipeNameChange.bind(this);
this.handleRecipeIngredientsChange = this.handleRecipeIngredientsChange.bind(this);
this.handleRecipeTagsChange = this.handleRecipeTagsChange.bind(this);
this.handleEditRecipeSubmit = this.handleEditRecipeSubmit.bind(this);
this.handleRecipeEditSelection = this.handleRecipeEditSelection.bind(this);
//test key of index
//this.cardKey = this.props.index;
}
handleRecipeNameChange(e) {
this.props.onRecNameEdit(e.target.value);
}
handleRecipeIngredientsChange(e) {
this.props.onRecIngredientsEdit(e.target.value);
}
handleRecipeTagsChange(e) {
this.props.onRecTagsEdit(e.target.value);
}
handleRecipeEditSelection() {
console.log(this.props.index);
this.props.onRecipeEdit(this.props.index);
}
handleEditRecipeSubmit(e) {
console.log(this.props.index);
let pos = this.props.index;
//let pos = this.cardKey;
console.log(`Recipe to be edited = #${pos}`);
this.props.onRecEditSubmit(pos);
}
handleRecipeDelete(e) {
//console.log(e.target.value);
console.log(this.props.index);
//call onDelete event handler with number of recipecard to be deleted
this.props.onDelete(this.props.index);
}
render() {
var recipeName = this.props.recipe.name;
var ingredients = this.props.recipe.ingredients.split(",").map(function (ingredient, index) {
return <a href="#!" className="collection-item" key={index}>{ingredient}</a>
});
var tags = this.props.recipe.tags.split(",").map(function (tag, index) {
return <div className="chip" key={index}>{tag}<i className="close material-icons">close</i></div>
});
return (
<div>
<div className="card medium hoverable">
<div className="card-image waves-effect waves-block waves-light">
<img className="activator" src="https://search.chow.com/thumbnail/320/0/www.chowstatic.com/s/recipe_placeholder_main_img-710dbe7756144f55f01c42cc4892e6de.jpg"/>
</div>
<div className="card-content">
<span className="card-title activator grey-text text-darken-2" onClick={this.handleRecipeEditSelection}><i className="material-icons brown-text text-darken-4 right">more_vert</i></span>
<h1 style={styles.cardContent.title}>{recipeName}</h1>
{/*<p><a href="#">This is a link</a></p>*/}
<div id="tags" style={styles.cardContent.tags}>
{tags}
</div>
<a className="btn-floating pulse waves-effect waves-light red right" style={styles.cardContent.deleteButton} onClick={this.handleRecipeDelete}><i className="material-icons right">delete</i></a>
</div>
<div className="card-reveal">
<span className="card-title grey-text text-darken-4"><i className="material-icons right">close</i></span>
<h4 style={styles.cardReveal.header}>{recipeName}</h4>
{/*<h5>Ingredients</h5>*/}
<div className="collection">
{ingredients}
</div>
<a className="btn-floating btn-large waves-effect waves-light cyan darken-4 right pulse" href="#modal2"><i className="material-icons right">mode_edit</i></a>
</div>
</div>
<div id="modal2" className="modal">
<div className="modal-content">
<h2 style={styles.modal.header}>Edit Recipe</h2>
<div className="row">
<form className="col s12">
<div className="row">
<div className="input-field col s6">
<input id="input_text2" type="text" data-length="10" value={this.props.filterNameEdit} onChange={this.handleRecipeNameChange}/>
<label htmlFor="input_text2">Name</label>
</div>
</div>
<div className="row">
<div className="input-field col s12">
<textarea id="textarea3" className="materialize-textarea" data-length="120" value={this.props.filterIngredientsEdit} onChange={this.handleRecipeIngredientsChange}></textarea>
<label htmlFor="textarea3">Ingredients (separate with commas)</label>
</div>
</div>
<div className="row">
<div className="input-field col s12">
<textarea id="textarea4" className="materialize-textarea" data-length="30" value={this.props.filterTagsEdit} onChange={this.handleRecipeTagsChange}></textarea>
<label htmlFor="textarea4">Tags (separate with commas)</label>
</div>
</div>
</form>
</div>
</div>
<div className="modal-footer">
<a href="#!" className="modal-action modal-close waves-effect waves-green btn btn-floating btn-large green darken-4 pulse" onClick={this.handleEditRecipeSubmit}><i className="material-icons">done</i></a>
</div>
</div>
</div>
)
}
}
The faulty function is this one -
handleEditRecipeSubmit(e) {
console.log(this.props.index);
let pos = this.props.index;
//let pos = this.cardKey;
console.log(`Recipe to be edited = #${pos}`);
this.props.onRecEditSubmit(pos);
}
This works as an event handler whenever you selected a recipe for edit and click the “done” button for saving the changes. The problem is that this.props.index
always returns 0
, no matter which recipe is being edited. index
is the prop
passed in to RecipeCard
and it contains the sequence of each recipecard when it was being created, using .map()
, in component RecipeFlexContainer
-
var recipeCards = gridRecipes.map(function (recipe, index) {
return <div className="recipe-item" key={index}>
<RecipeCard recipe={recipe} key={index} index={index} onDelete={onDelete}
onRecNameEdit={onRecipeNameEdit}
onRecIngredientsEdit={onRecipeIngEdit}
onRecTagsEdit={onRecipeTagsEdit}
onRecEditSubmit={onRecipeEditSubmit}
filterNameEdit={filterNameEdit}
filterIngredientsEdit={filterIngredientsEdit}
filterTagsEdit={filterTagsEdit}
onRecipeEdit={onRecipeEditSelect}
/>
</div>
});
What I don’t understand is why this.props.index
always returns 0
here in the handleEditRecipeSubmit
function when you try to edit a recipe, while it correctly returns the sequence of the card if you try to delete it instead-
//this works perfectly
handleRecipeDelete(e) {
//console.log(e.target.value);
console.log(this.props.index);
//call onDelete event handler with number of recipecard to be deleted
this.props.onDelete(this.props.index);
}
I’m mostly building this app locally, that version is here. SearchBar
is yet to be hooked up.
Steps to reproduce -
- Click on the three vertical dots on any recipe card (other than the first)
- Modify any field in the resulting form
- Click the done button
- Changes are reflected on the selected card and the first card
Would appreciate any help in finding the bug.