'How to use two dropdown menus to select variables for JavaScript

I have to make an alert that pops up after two options to fight that gives the results of the fight (script.js was provided).

When I select the two contestants, I can not figure out how to get the function to use the data in the script based on which two were selected.

Right now, when I click the button, I just get

"contestant_1 vs contestant_2"

And an error in the console saying

Uncaught TypeError: contestant_1.attack_power is not a function

var mario_world = {
  mario: {
    name:"Mario",
    description:"Small and jumpy. Likes princesses.",
    celebration: "Mario wins and does a little dance",
    height: 10,
    weight: 3,
    speed: 12,
    attack_power: function() {
      return this.weight * this.speed;
    }
  },

  bowser: {
    name:"Bowser",
    description:"Big and green, Hates princesses.",
    celebration: "Bowser wins and does a big roar",
    height: 16,
    weight: 6,
    speed: 4,
    boost: 0,
    attack_power: function() {
      return this.weight * (this.speed + this.boost);
    }
  },

  luigi: {
    name: "Luigi",
    desciption: "Mario's Brother. Wears green.",
    celebration: "Luigi wins and gives a thumbs up",
    height: 13,
    weight: 3,
    speed: 12,
    attack_power: function() {
      return this.weight * this.speed;
    }
  },

  peach: {
    name:"Princess Peach",
    description: "Always getting captured",
    celebration: "Peach wins and twirls around",
    height: 13,
    weight: 2,
    speed: 16,
    attack_power: function() {
      return this.weight * this.speed;
    }
  },


  boss_battle: function(contestant_1, contestant_2) {
    alert(contestant_1.name + " vs " + contestant_2.name);
    if (contestant_1.attack_power() > contestant_2.attack_power()) {
      alert(contestant_1.celebration);
    } else {
      alert(contestant_2.celebration);
    }
  }
}
<form>
  <select name="contestant_1" id="contestant_1">
    <option value="mario_world_mario">Mario</option>
    <option value="mario_world.luigi" selected="">Luigi</option>
    <option value="mario_world.peach">Peach</option>
    <option value="mario_world.bowser">Bowser</option>
  </select>
  <select name="contestant_2" id="contestant_2">
    <option value="mario_world.mario">Mario</option>
    <option value="mario_world.luigi">Luigi</option>
    <option value="mario_world.peach">Peach</option>
    <option value="mario_world.bowser" selected>Bowser</option>
  </select>
  <input type="button" value="Battle" onclick="mario_world.boss_battle(contestant_1, contestant_2);">
</form>


Solution 1:[1]

The arguments you're passing to the boss_battle function (contestant_1, contestant_2) are strings, and you cannot use them to access the object properties.

Consider passing the names directly in your select options, and then accessing the various properties of this

var mario_world = {
  mario: {
    name:"Mario",
    description:"Small and jumpy. Likes princesses.",
    celebration: "Mario wins and does a little dance",
    height: 10,
    weight: 3,
    speed: 12,
    attack_power: function() {
      return this.weight * this.speed;
    }
  },

  bowser: {
    name:"Bowser",
    description:"Big and green, Hates princesses.",
    celebration: "Bowser wins and does a big roar",
    height: 16,
    weight: 6,
    speed: 4,
    boost: 0,
    attack_power: function() {
      return this.weight * (this.speed + this.boost);
    }
  },

  luigi: {
    name: "Luigi",
    desciption: "Mario's Brother. Wears green.",
    celebration: "Luigi wins and gives a thumbs up",
    height: 13,
    weight: 3,
    speed: 12,
    attack_power: function() {
      return this.weight * this.speed;
    }
  },

  peach: {
      name:"Princess Peach",
    description: "Always getting captured",
    celebration: "Peach wins and twirls around",
    height: 13,
    weight: 2,
    speed: 16,
    attack_power: function() {
      return this.weight * this.speed;
    }
  },


  boss_battle: function(contestant_1, contestant_2) {
    alert(this[contestant_1.value].name + " vs " + this[contestant_2.value].name);
    if (this[contestant_1.value].attack_power() > this[contestant_2.value].attack_power()) {
      alert(this[contestant_1.value].celebration);
    } else {
      alert(this[contestant_2.value].celebration);
    }
  }
}
<form>
<select name="contestant_1" id="contestant_1">
  <option value="mario">Mario</option>
  <option value="luigi" selected="">Luigi</option>
  <option value="peach">Peach</option>
  <option value="bowser">Bowser</option>
</select>
 <select name="contestant_2" id="contestant_2">
  <option value="mario">Mario</option>
  <option value="luigi">Luigi</option>
  <option value="peach">Peach</option>
  <option value="bowser" selected>Bowser</option>
</select>
<input type="button" value="Battle" onclick="mario_world.boss_battle(contestant_1, contestant_2);">
</form>

Solution 2:[2]

There simply seems to be a bit of a misunderstanding of how objects work. You declared your object with a key attack_power, and assigned it to an anonymous function. To get the value from a key-value pair in an object, you simply have to reference the key attached to the object.

For example, if you have the object:

const obj = {
  fruit: 'apple'
}

to get the value of 'fruit' from obj, your code would be

const value = obj.fruit;

The same goes for functions assigned to a key in an object. To get the value (in this case, a returned value from a function) associated with the key, simply reference the key attached to the object.


Your code should instead look like this:

if (contestant_1.attack_power > constestant_2.attack_power) {
  alert(contestant_1.celebration);
} else {
  alert(contestant_2.celebration);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 GrafiCode
Solution 2 Peter Mortensen