0

I'm trying to create a budget controller.
When I try to push an item into an array, I get this error:

Uncaught TypeError: Cannot read property 'length' of undefined

The error is on line 33, which begins:

if(data.allItems[type].length >0){

What's going wrong?

Here's the complete code:

var budgetController = (function(){

//function constructor
var Expense = function(id, description, value){
    this.id = id;
    this.description = description;
    this.value = value;
};

var Income = function(id, description, value){
    this.id = id;
    this.description = description;
    this.value = value;
};


var data = {
    allItems : {
        exp: [],
        inc: []
    },
    totals: {
        exp: 0,
        inc: 0
    }
    
};

return{
    addItem: function(type, des, val){
        var newItem, ID;
        //create new id
        if(data.allItems[type].length >0){
            ID = data.allItems[type][data.allItems[type].length - 1].id + 1;
        } else{
            ID = 0;
        }
        
        //create new item based off of inc or exp type
        if(type === 'exp'){
            newItem = new Expense(ID, des, val);
        } else if(type === 'inc'){
            newItem = new Income(ID, des, val);
        }

        //push onto data structure
        data.allItems[type].push(newItem);

        //return the new element
        return newItem;
    },

    testing: function(){
        console.log(data);
    }
}; 
})();
3
  • 3
    what is the error? Commented Aug 25, 2020 at 2:32
  • totally forgot to put that in lol. The error is Uncaught TypeError: Cannot read property 'length' of undefined Commented Aug 25, 2020 at 2:36
  • 3
    The error tells you that data.allItems[type] is undefined, not an array like you expect. To figure out why, use the tips from this article to figure out what is going on. Specifically, you should add console.log(type) and console.log(data.allItems[type]) to see their values. Commented Aug 25, 2020 at 2:40

2 Answers 2

4

Probably data.allItems[type] is undefined because you used with variable type a property which is not defined. Just add a console.log(type, data.allItems[type]); before this line and look for the output.

Sign up to request clarification or add additional context in comments.

3 Comments

I put that console.log in and I'm still getting the error :(
Sure you get the error, this is just for getting more information why you get it. Use the Developer Tools and look at the output of the console. You can start them in most browsers by press F12.
I got it to work. Just removed the console.log compleatly and tested it by running budgetcontrol.testing(). Thank you!
1

Check first if data.allItems[type] exists.

if(data.allItems[type] && data.allItems[type].length > 0){
    ID = data.allItems[type][data.allItems[type].length - 1].id + 1;
} else{
    ID = 0;
}

It looks like the internals of your budgetController really depends on the fact that the arguments a) exist and b) are of a certain type (or value) in order to continue to function correctly.

In this case you might want to guard against allowing budgetController to proceed, with some error handling to stop execution if the arguments provided are unexpected.

var budgetController = (function() {

  //function constructor
  var Expense = function(id, description, value) {
    this.id = id;
    this.description = description;
    this.value = value;
  };

  var Income = function(id, description, value) {
    this.id = id;
    this.description = description;
    this.value = value;
  };

  var data = {
    allItems: {
      exp: [],
      inc: []
    },
    totals: {
      exp: 0,
      inc: 0
    }

  };

  return {
    addItem: function(type, des, val) {
      if (!Object.keys(data.allItems).includes(type)) {
        throw new Error(`Whoops! type must be one of ${Object.keys(data.allItems).join(', ')}`)
      }
      if (!des) {
        throw new Error(`Whoops! des is required`)
      }
      if (!val) {
        throw new Error(`Whoops! val is required`)
      }
      var newItem, ID;
      //create new id
      if (data.allItems[type].length > 0) {
        ID = data.allItems[type][data.allItems[type].length - 1].id + 1;
      } else {
        ID = 0;
      }

      //create new item based off of inc or exp type
      if (type === 'exp') {
        newItem = new Expense(ID, des, val);
      } else if (type === 'inc') {
        newItem = new Income(ID, des, val);
      }

      //push onto data structure
      data.allItems[type].push(newItem);

      //return the new element
      return newItem;
    },

    testing: function() {
      console.log(data);
    }
  };
})();


var myBudgetController = budgetController
myBudgetController.addItem('unacceptable type value', 'desc', 1)

1 Comment

This will work but it could produce later errors if type was set by accident to the wrong value and so the OP get's a wrong value because of wrong assumptions. So better take a look at the value of type and add your improvement additionally.

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.