I am using VueJS 2.6.11 and bootstrap 4 to create two dynamic sections(Category and Product) that contain divs and input fields. The product section is nested within the category section. When someone clicks the New Category button another category should get generated. The same behavior should also happen when someone clicks the New Product button, another Product section should get generated, but only inside the current category section.
Issue:
When someone clicks the New Product button, the Add Product section will get generated inside all current Category sections. Also, v-model appears to bind to every product name input. When someone clicks the X button for a specific Product section one product section would get deleted from all current Category sections.
I'm not exactly sure why this is happening.
codepen: https://codepen.io/d0773d/pen/ExjbEpy
code:
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>Create Categories and Products</title>
<!-- New Category -->
<button class="btn btn-success mt-5 mb-5"
@click="addNewCategoryForm">
New Category
</button>
<div class="card mb-3" v-for="(category, index) in categories">
<div class="card-body">
<span class="float-right"
style="cursor:pointer"
@click="deleteCategoryForm">
X
</span>
<h4 class="card-title">Add Category</h4>
<div class="category-form">
<input
type="text"
class="form-control mb-2"
placeholder="Category Name"
v-model="category.name">
</div>
<!-- New Product -->
<button class="btn btn-success mt-5 mb-5"
@click="addNewProductForm">
New Product
</button>
<div class="card mb-3" v-for="(product, index) in products">
<div class="card-body">
<span class="float-right"
style="cursor:pointer"
@click="deleteProductForm">
X
</span>
<h4 class="card-title">Add Product</h4>
<div class="product-form">
<input
type="text"
class="form-control mb-2"
placeholder="Product Name"
v-model="product.name">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '.container',
data: {
categories: [
{
name: '',
}
],
products: [
{
name: '',
}
]
},
methods: {
addNewCategoryForm () {
this.categories.push({
name: '',
});
},
deleteCategoryForm (index) {
this.categories.splice(index, 1);
},
addNewProductForm () {
this.products.push({
name: '',
});
},
deleteProductForm (index) {
this.products.splice(index, 1);
},
}
});
</script>