Reputation: 664
In my react app, I have created a page named Add Product with a button named Add Variation to allow adding small, medium, large variations of a product but can't figure out how to remove the small, medium, or large variation object from the state if user changes their mind.
Here's a summary of the problem:
Here's what the component looks like now:
const AddProduct = () => {
const [addVar, setAddVar] = useState(0)
const [values, setValues] = useState({
name: "",
description: "",
categories: [],
category: "",
photo: "",
loading: false,
error: "",
createdProduct: "",
redirectToProfile: false,
variations: [],
formData: ""
});
const {
name,
description,
price,
categories,
category,
photo,
loading,
error,
createdProduct,
redirectToProfile,
variations,
formData
} = values;
const addVariation = (e) => {
e.preventDefault()
setAddVar(addVar + 1)
let oldV = Array.from(variations); // gets current variations
let n = oldV.length; // get current array position
console.log(`Current number of variations is: ${n}`);
let vPost = [{
number: n,
vname: "",
vprice: "",
vquantity: "",
vshipping: ""
}]
let newV = oldV.concat(vPost);
setValues({
...values,
variations: newV,
error: ""
})
}
const handleVariationChange = (name, numberVal) => event => {
// numberVal is the iteration number
// name is the variation property which can be vname, vprice, vshipping, vquantity
// these are tested next in the following if statements
const value = event.target.value;
console.log(`numberVal: `, numberVal);
event.preventDefault()
let newVariations = Array.from(variations)
if(name === "vname") {
newVariations[numberVal].vname = value;
console.log(`newVariations[numberVal].vname value: `, newVariations)
}
if(name === "vprice") {
newVariations[numberVal].vprice = value;
console.log(`newVariations[numberVal].vprice value: `, newVariations)
}
if(name === "vshipping") {
newVariations[numberVal].vshipping = value;
console.log(`newVariations[numberVal].vshipping value: `, newVariations)
}
if(name === "vquantity") {
newVariations[numberVal].vquantity = value;
console.log(`newVariations[numberVal].vquantity value: `, newVariations)
}
setValues({...values, variations: newVariations})
formData.set("variations", JSON.stringify(newVariations));
};
const removeVariation = (e) => {
e.preventDefault()
let newVariations = Array.from(variations)
let popped = newVariations.pop()
setValues({
...values,
variations: newVariations,
error: ""
})
}
const newPostForm = () => (
<form className="mb-3" onSubmit={clickSubmit}>
<h4>Main Photo</h4>
<div className="form-group">
<label className="btn btn-secondary">
<input
onChange={handleChange("photo")}
type="file"
name="photo"
accept="image/*"
/>
</label>
</div>
<div className="form-group">
<label className="text-muted">Main Product Name</label>
<input
onChange={handleChange("name")}
type="text"
className="form-control"
value={name}
placeholder="Add main product name"
/>
</div>
<div className="form-group">
<label className="text-muted">Description</label>
<textarea
onChange={handleChange("description")}
className="form-control"
value={description}
placeholder="Add description"
/>
</div>
<div className="form-group">
<label className="text-muted">Category</label>
<select
onChange={handleChange("category")}
className="form-control"
>
<option>Please select</option>
{categories &&
categories.map((c, i) => (
<option key={i} value={c._id}>
{c.name}
</option>
))}
</select>
</div>
<div>
<button onClick={addVariation}>Add variation</button>
</div>
{variations ? VariationComponent() : null}
<br />
<br />
<button type="submit" className="btn btn-outline-primary">Create Product</button>
</form>
);
return (
<Layout>
<div className="row">
<div className="col-md-8 offset-md-2">
{newPostForm()}
</div>
</div>
</Layout>
);
};
export default AddProduct;
Every time Add variation is clicked, another VariationComponent
form is appended to the page . For example, if Add variation button was clicked 3 times, it would result in 3 VariationComponent
forms with 3 attached Remove variation buttons. Unfortunately, I do not see how to tell React the position of the #2 item in variations
to remove it so I resorted to solving this with .pop()
, which is not what I want.
How can I tell React to remove the right array item when Remove variation button is clicked?
Upvotes: 0
Views: 131
Reputation: 664
Thanks to @RobinZigmond's and @7iiBob's answers, I was able to solve this by this code:
const removeVariation = (e, num) => {
e.preventDefault();
setValues({
...values,
variations: variations.filter(item => item.number !== num),
error: ''
});
};
Remove variation button:
<button onClick={(e) => removeVariation(e, variations[i].number)} className="btn-danger">
{`Remove Variation`}
</button>
Keep in mind the empty variation object looks like this:
{
number: n,
vname: "",
vprice: "",
vquantity: "",
vshipping: ""
}
and n
is coming from addVariation
here:
const addVariation = (e) => {
e.preventDefault()
setAddVar(addVar + 1)
let oldV = Array.from(variations); // gets current variations
let n = oldV.length; // get current array position
console.log(`Current number of variations is: ${n}`);
let vPost = [{
number: n,
vname: "",
vprice: "",
vquantity: "",
vshipping: ""
}]
let newV = oldV.concat(vPost);
setValues({
...values,
variations: newV,
error: ""
})
}
Wholehearted thank you as this cost me hours of headache!
Upvotes: 1
Reputation: 690
If I understand correctly, you can use Arrray.filter() determine which variation to remove. It returns a new array with all but the matching numberVal.
onClick={e=>removeVariation(e)}
const removeVariation = e => {
e.preventDefault();
setValues({
...values,
variations: variations.filter(item => item.name !== e.target.value),
error: ''
});
};
Upvotes: 1