iftwMZ
iftwMZ

Reputation: 127

TypeError: Cannot set property 'key' of undefined

class Discount {
    discount;
    constructor() {
        this.key = '';
        this.code = '';
        this.discountValue = 0;
    }
    checkData(searchCode) {
        fetch('discount.json').then ((response) =>{
            return response.json()
        }).then ((obj)=>{
           Object.keys(obj).forEach(function(key) {
                obj[key].forEach((data)=> {
                  // console.log(data.code);
                   // console.log(obj[key]);
                    if (data.code === searchCode) {
                        console.log(key);
                        console.log(data.code);
                        console.log(data.discount);
                       this.key = key;
                       this.code = data.code;
                       this.discountValue = data.discount;
                    }
                });
           });

            console.log(this.key);
            console.log(this.code);
            console.log(this.discountValue);


        }).catch((error)=>{
            console.error('Wrong');
            console.error(error);
        });
    }


}


document.addEventListener("DOMContentLoaded", () =>{
    document.getElementById('calcDiscount').addEventListener('click', ()=>{
        const codeInput = document.getElementById('codeInput').value.toUpperCase();
        const myName = new Discount();

        myName.checkData(codeInput);
    });
});

    at main.js:20
    at Array.forEach (<anonymous>)
    at main.js:13
    at Array.forEach (<anonymous>)
    at main.js:12
(anonymous) @ main.js:34
Promise.catch (async)
checkData @ main.js:32
(anonymous) @ main.js:47

Why this code does not work? please help me, i can't understand. Please explain to me the solution of this problem if you know how. It's a discount, taking data from the json, it should return key, code and the value, but does not work.

Upvotes: 0

Views: 845

Answers (3)

random
random

Reputation: 7901

this inside the forEach loop i:e this.key = key, is not pointing to the Discount class instance.

The normal function as callback will create it's own this i:e Object.keys(obj).forEach(function(key) {

Instead use arrow based function, which do not have it's own this and will refer to the this from the outer immediate scope, which is pointing to the class instance.

Object.keys(obj).forEach(() => (key) {.

checkData(searchCode) {
    // here `this` points to the class instance
    fetch('discount.json').then ((response) =>{
        // this is retrieved from the outer scope, which is class instance
        return response.json()
    }).then ((obj)=>{
       // this is retrieved from the outer scope, which is class instance
       Object.keys(obj).forEach(function(key) {
           // The normal callback function, will create it's own this, so `this` won't point to the class instance.
            obj[key].forEach((data)=> {
                // Here, this refer to newly created `this` from the immediate enclosed function.
                if (data.code === searchCode) {
                    console.log(key);
                    console.log(data.code);
                    console.log(data.discount);
                   this.key = key;
                   this.code = data.code;
                   this.discountValue = data.discount;
                }
            });
       });

Upvotes: 1

Abhishek Kulkarni
Abhishek Kulkarni

Reputation: 1767

Try this below :

You need to use async await since the call is asynchrounous , the execution doesnt wait for your response and thats why you are getting undefined in your Object.keys(obj)

async checkData(searchCode) {
        await fetch('discount.json').then ((response) =>{
            return await response.json()
        }).then ((obj)=>{
           Object.keys(obj).forEach(function(key) {
                obj[key].forEach((data)=> {
                  // console.log(data.code);
                   // console.log(obj[key]);
                    if (data.code === searchCode) {
                        console.log(key);
                        console.log(data.code);
                        console.log(data.discount);
                       this.key = key;
                       this.code = data.code;
                       this.discountValue = data.discount;
                    }
                });
           });

            console.log(this.key);
            console.log(this.code);
            console.log(this.discountValue);


        }).catch((error)=>{
            console.error('Wrong');
            console.error(error);
        });
    }

Upvotes: 0

Sarthak Aggarwal
Sarthak Aggarwal

Reputation: 2312

Try Using ES6 arrow functions.

class Discount {
    discount;
    constructor() {
        this.key = '';
        this.code = '';
        this.discountValue = 0;
    }

    checkData = (searchCode) => {
        fetch('discount.json').then (res=>res.json()).then ((obj)=>{
           Object.keys(obj).forEach((key) => {
                obj[key].forEach((data)=> {
                  // console.log(data.code);
                   // console.log(obj[key]);
                    if (data.code === searchCode) {
                        console.log(key);
                        console.log(data.code);
                        console.log(data.discount);
                       this.key = key;
                       this.code = data.code;
                       this.discountValue = data.discount;
                    })
                });
           });

            console.log(this.key);
            console.log(this.code);
            console.log(this.discountValue);


        }).catch((error)=>{
            console.error('Wrong');
            console.error(error);
        });
    }


}

Upvotes: 0

Related Questions