0
votes

I'm trying to calculate total bill (sum of all product*usage) from an object of customerProduct data and display the bill amount. I'm calling a computed method to perform this. The customerProduct data is fetched from a get api call in the created() method.

Issue: In the initial render, console shows the following error: [Vue warn]: Error in render: "TypeError: Cannot read property 'PRICE' of undefined". Is this because the computation is taking some time and meanwhile when the template html code renders, the customerProductData is not fetched properly? Also, can using watch property help here?

Computed method to calculate total bill:

computed:{
    billAmount(){
        var billAmountWithoutDiscount = 0;
        if(typeof(this.customerProductData[0].PRICE) == undefined){
            return 0.0
        }
        else{
            for(let i=0;i<this.customerProductData.length;i++){
                billAmountWithoutDiscount += this.customerProductData[i].PRICE * this.customerProductData[i].USAGE;
            }
            return Number((100.0 - this.customerMetaData.discount)*billAmountWithoutDiscount/100).toLocaleString();    
        }   
    } 
}

GET api call:

 methods:{
    async init(){
        const response = await axios.get("/subscribe/getPresalesPricingMetaData/"+this.customerName)
        this.customerProductData = response.data;
        // console.log(response.data)
        this.getCustomerMetaData();
    },
}

customerProduct object:

customerProductData:[
0: {
    'PRICE': 10,
    'USAGE': 2000
},
1: {
    'PRICE': 30,
    'USAGE': 230
},
2: {
    'PRICE': 50,
    'USAGE': 200
},
3: {
    'PRICE': 30,
    'USAGE': 1000
},
]

The discount value:

customerMetaData:{
'discount': 2.2
}
3

3 Answers

1
votes

Here is an updated code. Try once.

new Vue({
		el: '#app',
		data: {
			message: "sample mesage",
			customerProductData:[
				{
				    'PRICE': 10,
				    'USAGE': 2000,
				    'CONSUMPTION': 100
				},
				{
				    'PRICE': 30,
				    'USAGE': 230,
				    'CONSUMPTION': 200
				},
				{
				    'PRICE': 50,
				    'USAGE': 200,
				    'CONSUMPTION': 300
				},
				{
				    'PRICE': 30,
				    'USAGE': 1000,
				    'CONSUMPTION': 400
				},
			],
			customerMetaData: {
				'discount': 2.2
			}
		},
		computed: {
			billAmount(){
		        let billAmountWithoutDiscount = 0;
		        if(typeof(this.customerProductData[0].PRICE) == undefined){
		            return 0.0
		        } else {
		            for(let i=0;i<this.customerProductData.length;i++){
		                billAmountWithoutDiscount += this.customerProductData[i].PRICE * this.customerProductData[i].CONSUMPTION;
		            }
		            return Number((100.0 - this.customerMetaData.discount) * billAmountWithoutDiscount / 100).toLocaleString();    
		        }   
		    }
		},
		methods:{
		    async init(){
		    	let that = this;
		        axios.get("/subscribe/getPresalesPricingMetaData/"+this.customerName).then(function(response){
		        	that.customerProductData = response.data;
		        	that.getCustomerMetaData();
		        })
		    },
		}
	});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
	<h1>{{ billAmount }}</h1>
</div>
0
votes

my first guess is to use method instead of computed

0
votes

The issue was indeed that the GET api call was taking time, hence the customerProductData was not getting populated. So when the computed method was called, it did not have any data to work with.

Now if you read the computed method carefully, I actually wrote the code to deal with the above situation using an if statement to return 0 if the customerProductData was not populated. This didn't work because the condition used was incorrect.

if(typeof(this.customerProductData[0].PRICE) == undefined)

Since, there is no data in customerProductData, the initial access of this.customerProductData[0] itself fails, so the PRICE property never gets accessed i.e. not returning undefined

Solution: Check if index 0 exists or not in customerProductData

computed:{
    billAmount(){
        var billAmountWithoutDiscount = 0;
        if(!this.customerProductData.hasOwnProperty(0)){
            return 0.0
        }
        else{
            for(let i=0;i<this.customerProductData.length;i++){
                billAmountWithoutDiscount += this.customerProductData[i].PRICE * this.customerProductData[i].CONSUMPTION;
            }
            return Number((100.0 - this.customerMetaData.discount)*billAmountWithoutDiscount/100).toLocaleString();    
        }   
    } 
}