Jesse Berman
Jesse Berman

Reputation: 63

Getting an error message when I try to remove a JSON object from a JavaScript Array

So I'm trying to build a relatively simple app that would take a group of 8 predetermined celebrities, display two at a time at random, and allow the user to pick which one they prefer until there is only one left. I've managed to get almost everything working correctly on the JavaScript side, but every once in a while I get an error message that can crash the application, and I can't figure out how to fix it. I'd really appreciate any help the community can provide.

I've gone over the code looking for problems in logic that could be causing the error, and I've tried using console.logs to identify it, but the error seems to stop the console.logs themselves from displaying when it occurs.

You can find the GitHub repository here:

https://github.com/jesberman/Celeb-Mash-Prototype

And the live site (with errors) here:

https://jesberman.github.io/Celeb-Mash-Prototype/

An important part of the code is organized as a series of if statements, which I'll display below:

if(initialPicValue1 === initialPicValue2 && initialPicValue2 === celebArrayLength){
    initialPicValue2 -= 1;
}
if (initialPicValue1 === initialPicValue2){
    initialPicValue2 += 1;
}
if(initialPicValue1 === initialPicValue2 && initialPicValue1 === 0){
    initialPicValue2 += 1;
}
if (celebArrayLength === 1){
    return alert("Congrats! Your Favorite Celeb is " + celebArray[0].name);
}

I'm looking to get through all of the objects in the array cleanly without any problems, until only one is left. However, I sometimes will randomly get the following error:

Uncaught TypeError: Cannot read property 'picture' of undefined at pressButton1 (logic.js:128) at HTMLButtonElement.onclick (index.html:21)

Upvotes: 1

Views: 117

Answers (1)

Rob Kwasowski
Rob Kwasowski

Reputation: 2780

I can see that you are getting an error on the line:

console.log(celebArray[initialPicValue2].picture);

The problem is that you have an array of celebrities, celebArray, and when you click one of the buttons you are accessing an index within that array. The error happens when you get down to only one celebrity left in the array, it tries to access an index that isn't there. So to avoid the error you have to take the first block of code in the pressButton function before if (celebArrayLength === 1) and put it in an if statement of:

if (celebArray.length > 1) {
  // do something
}

And then when it runs if (celebArrayLength === 1) and finds there is only one celebrity remaining you could hide the buttons by doing the following because now the game is over.

if (celebArrayLength === 1) {
  $('button').hide()
  return alert("Congrats! Your Favorite Celeb is " + celebArray[0].name);
}

In your code you have a function for each button but I've simplified it so now there is the one function that gets run for both buttons and you pass in the number of the button like so <button id="button1" onclick="pressButton(1)"> and then you have a function like this function pressButton(e).

So then in that function it has the number of the button in the variable e and you can get the number of the other button by removing e from an array [1,2] and then using the remaining number:

var arr = [1,2] // a list with the numbers of the buttons
arr.splice(e-1, 1) // we remove the one that was pressed
var other = arr[0] // the one left is the other one

I tidied up a few other things like that. Hopefully you can see what I've done. It's generally better to not duplicate functions so that it's easier to just edit one function when you want to change something, and then you don't have to worry about forgetting to do it to both.

So this is my version which fixes your problem. I've linked the images to where they are online, but I've kept the relative links but just commented.

var celebArray = [
    {
        name: "Tom Hanks",
        // picture: "assets/images/tomHanks.jpg"
        picture: "https://jesberman.github.io/Celeb-Mash-Prototype/assets/images/tomHanks.jpg"
    },
    {
        name: "Benedict Cumberbatch",
        // picture: "assets/images/benedictCumberbatch.jpg"
        picture: "https://jesberman.github.io/Celeb-Mash-Prototype/assets/images/benedictCumberbatch.jpg"
    },
    {
        name: "Charlize Theron",
        // picture: "assets/images/charlizeTheron.jpg"
        picture: "https://jesberman.github.io/Celeb-Mash-Prototype/assets/images/charlizeTheron.jpg"
    },
    {
        name: "Evangeline Lilly",
        // picture: "assets/images/evangelineLilly.jpg"
        picture: "https://jesberman.github.io/Celeb-Mash-Prototype/assets/images/evangelineLilly.jpg"
    },
    {
        name: "Katee Sackhoff",
        // picture: "assets/images/kateeSackhoff.jpg"
        picture: "https://jesberman.github.io/Celeb-Mash-Prototype/assets/images/kateeSackhoff.jpg"
    },
    {
        name: "Robert Downey Jr.",
        // picture: "assets/images/robertDowneyJr.jpg"
        picture: "https://jesberman.github.io/Celeb-Mash-Prototype/assets/images/robertDowneyJr.jpg"
    },
    {
        name: "Rose Leslie",
        // picture: "assets/images/roseLeslie.jpg"
        picture: "https://jesberman.github.io/Celeb-Mash-Prototype/assets/images/roseLeslie.jpg"
    },
    {
        name: "Denzel Washington",
        // picture: "assets/images/denzelWashington.jpg"
        picture: "https://jesberman.github.io/Celeb-Mash-Prototype/assets/images/denzelWashington.jpg"
    },
];

function picValues() {
  var initialPicValues = {}
  celebArrayLength = celebArray.length;
  initialPicValues[1] = Math.floor((Math.random() * celebArrayLength));
  var keys = Object.keys(celebArray)
  keys.splice(initialPicValues[1], 1)

  var rnd_2 = Math.floor((Math.random() * keys.length));
  initialPicValues[2] = keys[rnd_2]

  return initialPicValues
}

var celebArrayLength = celebArray.length;
var initialPicValues = picValues(celebArray)

function loadPics() {
  $("#picture1").css("background-image","url(" + celebArray[initialPicValues[1]].picture + ")");
  $("#picture2").css("background-image","url(" + celebArray[initialPicValues[2]].picture + ")");
}

loadPics();
console.log("Initial Array:");
console.log(celebArray);

function pressButton(e) {

  if (celebArrayLength > 1) {

    var arr = [1,2] // a list with the numbers of the buttons
    arr.splice(e-1, 1) // we remove the one that was pressed
    var other = arr[0] // the one left is the other one

    console.log("Initial Pic "+other+" Value");
    console.log(initialPicValues[other]);
    console.log("Celeb Being Removed");
    console.log(celebArray[initialPicValues[other]].picture);
    celebArray.splice(initialPicValues[other], 1);

    initialPicValues = picValues(celebArray)

  }

  if (celebArrayLength === 1) {
    $('button').hide()
    return alert("Congrats! Your Favorite Celeb is " + celebArray[0].name);
  }

  console.log("Celeb To Be Removed:")
  console.log(celebArray[initialPicValues[other]].picture);
  console.log('celebArrayLength', celebArrayLength)
  loadPics()

  console.log("Array After Button Press:");
  console.log(celebArray);

}
#main-div {
    padding-top: 50px;
    padding-right:10%; 
    padding-left: 10%; 
    background-color: gold; 
    width: 100%; 
    height: 700px;
}

#header-div {
    text-align: center; 
    background-color: green; 
    height: 100px; 
    width: 80%;
}

#left-div {
    display: inline-block; 
    background-color: red; 
    width: 40%; 
    height: 400px;
}

#picture1 {
    background-repeat: no-repeat; 
    width: 100%; 
    height: 300px;
}

#button1 {
    position: relative; 
    left: 40%;
}

#right-div {
    display: inline-block; 
    background-color: blue; 
    width: 40%; 
    height: 400px;
}

#picture2 {
    background-repeat: no-repeat; 
    width: 100%; 
    height: 300px;
}

#button2 {
    position: relative; 
    left: 40%;
}
<!DOCTYPE html>

<head>
    <title>
        Celeb Mash
    </title>
    <link rel="stylesheet" href="assets/css/style.css">
    <script src="https://code.jquery.com/jquery.js"></script>
</head>

<body>
    <div id="main-div">
        <div id="header-div">
            <h2>
                Pick The Celeb You Like More
            </h2>
        </div>
        <div id="left-div">
            <div id="picture1">
            </div>
            <button id="button1" onclick="pressButton(1)">
                Submit
            </button>
        </div>
        <div id="right-div">
            <div id="picture2">
            </div>
            <button id="button2" onclick="pressButton(2)">
                Submit
            </button>
        </div>

    </div>
    <!-- <script src="assets/javascript/logic.js"> -->
    </script>
</body>

</html>

Upvotes: 1

Related Questions