0

I am learning Vue.js and I am processing to create simple project. When I click on edit button, the product that select before don't return back and when I try to select product, I got the error "Cannot read property'includes'of undefined". And Sorry, I'm new on Vue.js and also stack-overflow.

Here is my label to select product.

<v-col cols="12">
    <label class="font-weight-bold">Select Product</label>
	<div>
		<v-autocomplete
		dense
		solo
		item-text="name"
		item-value="name"
		return-object
		:items="products"
		@input="addTocart"
		></v-autocomplete>
	</div>
</v-col>
enter image description here

And Here is my code in Script.

        fetchReturn() {
			this.$axios
			.$get(`api/return-purchase/` + this.$route.params.id)
			.then(res => {
				this.$set(this.$data, 'form', res.returnpurchase);
			
				// Initial value = pivot
				for (let i in this.form.items) {
					Vue.set(this.form.items[i], 'quantity', this.form.items[i].pivot.quantity);
					Vue.set(this.form.items[i], 'unit_price', this.form.items[i].pivot.unit_price);
					Vue.set(this.form.items[i], 'discount', this.form.items[i].pivot.discount);
				}
			})
			.catch(err => {
				console.log(res.response);
			});
		},
		addTocart(item) {
			if (this.form.items.include(item)) {
				alert("already there");
			} else {
				this.form.items.push(item);
			}
			Vue.set(item, 'quantity', 1);
			Vue.set(item, 'discount', 1);
		},

enter image description here

Full code.

<template>
	<v-app>
		<v-card class="mx-5 my-5">
			<div class="teal darken-1">
				<v-card-title class="white--text">Edit​ Return Purchase</v-card-title>
			</div>
			<v-divider></v-divider>
			<div class="px-5">
				<p class="caption font-italic pt-5">The field labels marked with * are required input fields.</p>
				<v-row>
					<v-col md="6" cols="12">
						<label for="reference_no" class="font-weight-bold">Reference No</label>
						<v-text-field 
							solo 
							outlined 
							dense 
							v-model="form.reference_no"
						></v-text-field>
					</v-col>
					<v-col md="6" cols="12">
						<label class="font-weight-bold">Location*</label>
						<v-autocomplete
							item-value="address"
							item-text="address"
							solo
							outlined
							dense
							label="Business Location"
							return-object
							v-model="form.branch"
							:items="locations"
						></v-autocomplete>
					</v-col>
					<v-col md="6" cols="12">
						<label class="font-weight-bold">Supplier</label>
						<v-autocomplete
							:items="suppliers"
							item-text="name"
							item-value="name"
							solo
							outlined
							dense
							return-object
							v-model="form.supplier"
							label="Please select Supplier"
						></v-autocomplete>
					</v-col>
					<v-col md="6" cols="12">
						<label class="font-weight-bold">Account</label>
						<v-autocomplete
							:items="accounts"
							item-text="name"
							item-value="name"
							solo
							outlined
							dense
							return-object
							v-model="form.account"
							label="Please select Account"
						></v-autocomplete>
					</v-col>
					
					<v-col cols="12">
						<label class="font-weight-bold">Select Product</label>
						<div>
							<v-autocomplete
								dense
								solo
								item-text="name"
								item-value="name"
								return-object
								:items="products"
								@input="addTocart"
							></v-autocomplete>
						</div>
					</v-col>
				</v-row>
				<div>
					<label class="font-weight-bold mb-3">Product Table</label>
					<table class="tableReturn">
						<thead>
							<tr class="tableReturn--header">
								<td>Name</td>
								<td>Code</td>
								<td>Quantity</td>
								<td>Unit Price</td>
								<td>Discount</td>
								<td>Total</td>
								<td>Actions</td>
							</tr>
						</thead>
						<tbody>
							<tr class="tableReturn--td" v-for="(item, index) in form.items" :key="index">
								<td>{{item.name}}</td>
								<td>{{item.code}}</td>
								<td>
									<input type="number" class="table-quantity" v-model="form.items[index].quantity" />
								</td>
								<td>
									<input
										type="number"
										class="table-quantity"
										v-model="form.items[index].unit_price"
										placeholder="0.00"
									/>
								</td>
								<td>
									<input
										type="number"
										class="table-quantity"
										v-model="form.items[index].discount"
										placeholder="0.00"
									/>
								</td>
								<td>USD {{ discountedPrice(item) | formatMoney }}</td>
								<td>
									<v-btn small color="red" outlined @click="removeItem(index)">
										<v-icon>mdi-delete</v-icon>
									</v-btn>
								</td>
							</tr>
							<tr>
								<td class="py-5" colspan="2">Total</td>
								<td colspan="3">{{ Qty }}</td>
								<td>USD {{ Total | formatMoney }}</td>
							</tr>
						</tbody>
					</table>
				</div>

				<v-row>
					<v-col md="6" cols="12">
						<div class="d-flex flex-column mb-5">
							<label for="" class="font-weight-bold">Return Note</label>
							<textarea cols="30" rows="7" class="textarea" v-model="form.return_des"></textarea>
						</div>
					</v-col>
					<v-col md="6" cols="12">
						<div class="d-flex flex-column mb-5">
							<label for="" class="font-weight-bold">Staff Note</label>
							<textarea cols="30" rows="7" class="textarea" v-model="form.staff_des"></textarea>
						</div>
					</v-col>
				</v-row>
			</div>
			<v-btn
				@click.prevent="updateReturn"
				class="blue mx-5 darken-2 mb-5 grey--text text--lighten-4"
			>
				<v-icon>mdi-check</v-icon>Update
			</v-btn>
		</v-card>
	</v-app>
</template>

<script>
	import Vue from "vue";

	let numeral = require('numeral');

	Vue.filter('formatMoney', function(value) {
		return numeral(value).format('00,00.00')
	});

	export default {

		name: "editReturn",

		created(){

			this.fetchReturn();
			this.fetchLocation();
			this.fetchSupplier();
			this.fetchAccount();
			this.fetchProduct();
			
		},

		data(){
			return {
				form: {
					items: []
				},
				suppliers: [],
				locations: [],
				products: [],
				returnpurchase: [],
				accounts: []
			};
		},

		computed: {
			Qty() {
				if (this.form.hasOwnProperty("items")) {
					return this.form.items.reduce((total, item) => {
					return total + Number(item.quantity);
					}, 0);
				}
			},

			Total() {
				if (this.form.hasOwnProperty("items")) {
					return this.form.items.reduce((total, item) => {
					let subtotal =
						(item.unit_price - (item.unit_price * item.discount) / 100) *
						item.quantity;
					return total + subtotal;
					}, 0);
				}
			}	
		},

		methods: {
			discountedPrice(product) {
				return (
					(product.unit_price -
						(product.unit_price * product.discount) / 100) *
					product.quantity
				);
			},

			fetchLocation() {
				this.$axios.$get(`api/location`)
				.then(res => {
					this.locations = res.locations.data;
					// this.$set(this.$data, "locations", res.locations.data);
					console.log(res);
				})
				.catch(err => {
					console.log(err.response);
				});
			},

			fetchSupplier() {
				this.$axios.$get(`api/supplier`)
				.then(res => {
					this.suppliers = res.suppliers.data;
					// this.$set(this.$data, "suppliers", res.suppliers.data);
					console.log(res);
				})
				.catch(err => {
					console.log(err.response);
				});
			},

			fetchAccount(){
				this.$axios.$get(`api/account`)
				.then(res =>{
					this.accounts = res.account;
					console.log(res)
				})
				.catch(err => {
					console.log(err.response);
				});
			},

			fetchProduct() {
				this.$axios
				.$get(`/api/product`)
				.then(res => {
					this.products = res.products.data;
					// this.$set(this.$data, "items", res.items.data);
					console.log(res);
				})
				.catch(err => {
					console.log(err);
				});
			},

			fetchReturn() {
				this.$axios
				.$get(`api/return-purchase/` + this.$route.params.id)
				.then(res => {
					this.$set(this.$data, 'form', res.returnpurchase);

					// Initial value = pivot
					for (let i in this.form.items) {
						Vue.set(this.form.items[i], 'quantity', this.form.items[i].pivot.quantity);
						Vue.set(this.form.items[i], 'unit_price', this.form.items[i].pivot.unit_price);
						Vue.set(this.form.items[i], 'discount', this.form.items[i].pivot.discount);
					}
				})
				.catch(err => {
					console.log(res.response);
				});
			},
			addTocart(item) {
				if (this.form.items.includes(item)) {
					alert("already there");
				} else {
					this.form.items.push(item);
				}
				Vue.set(item, 'quantity', 1);
				Vue.set(item, 'discount', 1);
			},

			updateReturn() {
				this.$axios.$patch(`api/return-purchase/` + this.form.id, {

					branch: this.form.branch,
					products: this.form.products,
					supplier: this.form.supplier,
					account: this.form.account,
					return_des: this.form.return_des,
					staff_des: this.form.staff_des,
					
				})
				.then(res => {
					this.returnpurchase = res.data;
					// this.$set(this.$data, "returnpurchase", res.data);
					this.$set(this.$data, "returnpurchase" , res.returnpurchase);
					this.$router.push(`/return/return-purchase/view`);
					console.log(res);
				})
				.catch(err => {
					console.log(err.response);
				});
			},
			removeItem(index) {
				this.form.items.splice(index, 1);
			}
		}
	};
</script>

<style lang="scss">
	.textarea {
		border: 1px solid rgba(0, 0, 0, 0.125);
		outline: 1px solid #461577;
	}

	.tableReturn {
		width: 100%;
		margin-top: 10px;
		border-collapse: collapse;
		&--header {
			font-weight: 500;
			text-align: left;
			border-bottom: 1px solid rgba(0, 0, 0, 0.125);
		}

		&--td {
			border-bottom: 1px solid rgba(0, 0, 0, 0.125);
		}
	}

	.table-quantity {
		border: 1px solid rgba(0, 0, 0, 0.125);
		padding: 5px 10px 5px 10px;
		margin-top: 5px;
		margin-bottom: 5px;
	}
</style>

7
  • 1
    how do you set your data? form.items Commented Jan 27, 2020 at 5:14
  • @Ahmad Mobaraki What's you mean? Commented Jan 27, 2020 at 7:07
  • Can you add console.log(this.form.items) to your addTocart(item) method? Commented Jan 27, 2020 at 9:14
  • @webprogrammer I added already, but it still error. Commented Jan 28, 2020 at 2:20
  • 1
    @adding console.log(this.form.items) don't fix the issue. Can you show me output of that function? Commented Jan 28, 2020 at 8:09

1 Answer 1

1

There is not property like include in array/list it should be includes. Small typo.

addTocart(item) {
  if (this.form.items.includes(item)) { // <-- change include to includes 
    alert("already there");
  } else {
    this.form.items.push(item);
  }
  Vue.set(item, 'quantity', 1);
  Vue.set(item, 'discount', 1);
},

Update

If res.returnpurchase is undefined then it is setting whole form variable as undefined or if items in undefined then it is setting items as undefined which should be [] for using includes. Add check for this,

if (res.returnpurchase == undefined 
   || res.returnpurchase.items == undefined) {
   this.form.items = []
}
Sign up to request clarification or add additional context in comments.

3 Comments

Here is my error alert. TypeError: Cannot read property 'includes' of undefined at VueComponent.addTocart (edit.vue?f0c5:293) at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854) at VueComponent.invoker (vue.runtime.esm.js?2b0e:2179) at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
I tried similar code but not getting any error. I am suspicious about your fetchReturn() function. If res.returnpurchase is undefined then it is setting whole form variable as undefined or if items in undefined then it is setting items as undefined which should be [] for using includes. Add check for this, if (res.returnpurchase == undefined || res.returnpurchase.items == undefined) this.form.items = []
Welcome, I updated the answer. If you issue solved than mark this as correct answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.