Context
Hi everyone, I had created a product page which populate the products info from api . Now I am building the edit Product page. On edit product page , it contains 4 components which I am rendering through bootstrap-vue tabs components. You can see image & code below
editProduct.vue
<template>
<div class="landing-page">
<div class="titleStyle">
<span> <i class="bx fw-bold" :class="'bx-arrow-back'" id="btn" @click="$router.go(-1)" /> </span>
Edit details: {{ item.productName }}
</div>
<div class="tableContainer">
<div class="mt-5">
<b-tabs content-class="mt-3" fill>
<b-tab :title="tabTitles.first" active>
<updateCatalog :item="item" />
</b-tab>
<b-tab :title="tabTitles.second">
<updateDetails :item="item" :changeDetailData="changeDetailData" />
</b-tab>
<b-tab :title="tabTitles.third">
<changeDetails :item="changeDetailData" />
</b-tab>
<b-tab :title="tabTitles.fourth" disabled>
<p>I'm a disabled tab!</p>
</b-tab>
</b-tabs>
</div>
</div>
</div>
</template>
<script>
import updateCatalog from '@/components/modal/product/editProductComponent/updateCatalog.vue';
import updateDetails from './editProductComponent/updateDetails.vue';
import changeDetails from '@/components/modal/product/editProductComponent/changeDetails.vue';
import { callAxios } from '@/helper/callAxios';
import { errorToast } from '@/mixins/errorToast';
import { successToast } from '@/mixins/successToast';
export default {
name: 'edit-product',
components: {
updateCatalog,
updateDetails,
changeDetails,
},
props: ['item'],
mixins: [errorToast, successToast],
data() {
return {
productObj: this.item,
tabTitles: {
first: "Product Catalog Details",
second: "Update Details",
third: "Change Details",
fourth: "Procurement Vendor Update",
},
changeDetailData:{},
}
},
computed: {
getGlobalHubId() {
return this.$store.getters.getMb_hubId;
}
},
methods: {
async fetchChangeDetailData(pid ) {
const reqData = { query: {resolve: 'hub,vendor,productcatalog'}, body: {}, headers: {} };
try {
let res = await callAxios('GET', `products/${pid}/hubs/${this.getGlobalHubId}`, reqData);
//console.log('res after api call of change page = ', res);
if (res) {
if (res.message) {
this.showErrorToast(res.errors[0].message)
}
else {
this.changeDetailData = res.data;
}
}
} catch (error) {
console.error('Error during API call:', error);
}
}
},
async mounted() {
console.log('Item recieved at edit product= ', this.item)
await this.fetchChangeDetailData(this.item.productId)
}
}
</script>
<style>
</style>
As you can see I am calling the api here only (inside editProduct.vue) to get the changeDetailData
which is used in update Details component as I am passing it through props. Since switching the tabs will not reload the page , so after switching to updateDetails tab
, I used watch()
to get the changeDetailData
which is passed as props in updateDetail.vue
. Below is the code
updateDetail.vue
<template>
<div class="sectionContainer">
<div class="pt-2 ">
<div class="accordion w-75 m-auto" role="tablist">
<!-- acc1 -->
<b-card no-body>
<b-alert show variant="primary">
<b-card-header header-tag="header" class="bg-transparent border-bottom-0" role="tab">
<span class="d-flex justify-content-between align-items-center">
<p class="my-auto ps-4">Vendor : {{ item.vendorName }}</p>
<b-button block v-b-toggle.accordion-1
variant="primary-outline text-primary fw-bold pe-4">Update</b-button>
</span>
</b-card-header>
<b-collapse id="accordion-1" visible accordion="my-accordion" role="tabpanel">
<b-card-body>
<vendor-detail
:product_id="2"
:vendorDetailData="formData" />
</b-card-body>
</b-collapse>
</b-alert>
</b-card>
</div>
</div>
</div>
</template>
<script>
import vendorDetail from './updateDetailComponents/vendorDetail.vue';
export default {
name: 'update-details',
components: {
vendorDetail,
},
props: {
item: {
type: Object,
required: true
},
changeDetailData: {
type: Object,
required: true
}
},
data() {
return {
productObj: this.item,
formData: {},
}
},
watch: {
changeDetailData: {
handler(newValue) {
//console.log("WATCH = ", newValue)
this.formData = newValue;
console.log("FormData in update = ", this.formData)
},
immediate: true
}
},
methods: {
selectionChanged(selectedOption) {
console.log(selectedOption);
this.form.active = selectedOption;
},
},
mounted() {
console.log('Item recieved at update Details = ', this.changeDetailData)
}
}
<style>
</style>
On entering the updateDetail.vue
, I am passing the changeDetailData as formData
to vendorDetail component
, which is simply a form inside a accordion ( bootstrap component). So again the page does not reload and renders over the same single page
Issue I am facing
Now the issue is that when I come to this vendor detail form and without changing any value , just simply save it. All the fields in the form in the payload remains empty. (ALso I need to edit each fields if I want them to reflect in the payload.)
Below is the code where I had prepopulate the form fields with the data in props but they are coming empty.
vendorDetail.vue
<template>
<div class="landing-page">
<div class="formContainer">
<b-form @submit="onSubmit" @reset="onReset">
<!-- {{ vendorDetailData.aisleId }} -->
<div class="row">
<div class="col">
<nitrozen-input type="text" label="Vendor" placeholder="Vendor Name" required id="inputField"
:value="vendorDetailData?.vendor?.name" @input="onChange('vendorName', $event)"
validationMessage="Field is required" />
<div v-if="isFieldEmpty['vendorName']">
<validationMessage msg="Vendor is required!" />
</div>
</div>
<div class="col">
<nitrozen-dropdown id="active" :items="aisleOptions" label="Aisle" placeholder="Aisle"
tooltip="Select Aisle"
v-model="selectedAisle" @change="setAisle" />
</div>
</div>
<div class="row">
<div class="col">
<nitrozen-input type="text" label="Rack" placeholder="Rack" required id="inputField" :value="vendorDetailData?.rack"
@input="onChange('rack', $event)" />
<div v-if="isFieldEmpty['rack']">
<validationMessage msg="Rack is required!" />
</div>
</div>
<div class="col">
<nitrozen-input type="text" label="Shelf" placeholder="Shelf" required id="inputField" :value="vendorDetailData?.shelf"
@input="onChange('shelf', $event)" />
<div v-if="isFieldEmpty['shelf']">
<validationMessage msg="Shelf is required!" />
</div>
</div>
</div>
<div class="btnContainer">
<b-button type="submit" variant="primary" class="submitBtn" >Save</b-button>
</div>
</b-form>
</div>
</div>
</template>
<script>
import router from '@/router';
import { NitrozenInput, NitrozenDropdown} from '@gofynd/nitrozen-vue';
import { callAxios } from '@/helper/callAxios';
import validationMessage from '@/components/validationMessage.vue';
import { errorToast } from '@/mixins/errorToast';
import { successToast } from '@/mixins/successToast';
export default {
name: 'vendor-detail',
components: {
NitrozenInput,
NitrozenDropdown,
validationMessage
},
props: {
vendorDetailData: {
type: Object,
required: true
},
product_id : {
type : Number,
required : true,
}
},
mixins:[errorToast,successToast],
data() {
return {
item: {},
aisleListData : [],
form: {
vendorId: this.vendorDetailData?.vendor?.id, //these values comes empty
aisleId: this.vendorDetailData?.aisleId, //these values comes empty
rack: this.vendorDetailData?.rack, //these values comes empty
shelf: this.vendorDetailData?.shelf, //these values comes empty
},
aisleOptions: [],
selectedAisle: this.vendorDetailData?.aisleId, //these values comes empty
aisleList: [
{
"createdOn": "2019-05-01 13:25:29",
"createdBy": -3,
"modifiedOn": "2019-05-01 13:25:29",
"modifiedBy": -3,
"id": 8,
"name": "A4",
"sortOrder": 0
},
{
"createdOn": "2019-05-01 13:25:29",
"createdBy": -3,
"modifiedOn": "2019-05-01 13:25:29",
"modifiedBy": -3,
"id": 6,
"name": "A5",
"sortOrder": 0
},
],
isFieldEmpty:{vendorName:false,rack:false,shelf:false},
}
},
computed: {
getGlobalHubId() {
return this.$store.getters.getMb_hubId;
},
getCompanyId() {
return this.$store.getters.getCompanyId;
}
},
methods: {
async onSubmit(event) {
event.preventDefault();
this.form.vendorId = this.vendorDetailData.vendor.id;
//This comes empty
alert("API PAYLAOD = ",JSON.stringify(this.form))
const payload = this.form;
const reqData = { query: {}, body: payload, headers: {} };
try {
let res = await callAxios('PATCH', `products/${this.product_id}/hubs/${this.getGlobalHubId}/vendor`, reqData);
if (res) {
if (res.message) {
this.showErrorToast(res.errors[0].message)
}
else {
this.showSuccessToast('Vendor Details Updated');
router.push(`company/${this.getCompanyId}/product`)
}
}
} catch (error) {
console.error('Error during API call:', error);
}
},
onReset(event) {
event.preventDefault()
this.show = false
this.$nextTick(() => {
this.show = true
})
},
onChange(field, event) {
this.isFieldEmpty[field] = event.length == 0 ? true:false;
this.form[field] = event;
},
setAisle(selectedAisle) {
console.log(selectedAisle);
this.form.aisleId = selectedAisle;
},
createAisleOptions() {
this.aisleOptions = this.aisleList.map(ele => ({ text: ele.name, value: ele.id }));
},
},
mounted() {
this.createAisleOptions();
console.log('Item recieved vendor component= ', this.vendorDetailData)
}
}
</script>
<style>
</style>
Please help me in this issue.( I know its a long explanation ) , I want that payload and all the values which coming empty should get prepopulated :<
form: {
vendorId: this.vendorDetailData?.vendor?.id, //these values comes empty
aisleId: this.vendorDetailData?.aisleId, //these values comes empty
rack: this.vendorDetailData?.rack, //these values comes empty
shelf: this.vendorDetailData?.shelf, //these values comes empty
},