Pokemon IV Calculator

A live-updating calculator for Pokemon Individual Values.

HTML

<script src="https://cdn.rawgit.com/iAmMortos/JSConsole/master/console.min.js"></script>
<script src="https://rawgit.com/iAmMortos/PokeStatsJsObj/master/stats.js"></script>
<script src="https://rawgit.com/iAmMortos/PokemonNaturesJsObj/master/natures.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<body ng-app="ivCalculator">
  <form ng-controller="Calculator as calc">
    <!-- for debugging
    nature <input type="text" ng-model="calc.nature" /><br />
    nat_up <input type="text" ng-model="calc.nat_up" /><br />
    nat_down <input type="text" ng-model="calc.nat_down" /><br />
    -->
    <table>
      <tr>
        <td>Name:</td>
        <td><input type="text" id="pkmn_name" list="pkmn_names" ng-model="calc.pokemon" /></td>
      </tr>
      <tr>
        <td>Level:</td>
        <td><input type="number" ng-model="calc.level" number-field min-num="1" max-num="100" /></td>
      </tr>
      <tr>
        <td>Nature:</td>
        <td>
          <select ng-model="calc.nature">
            <option ng-repeat="nature in calc.natures.all" value="{{ nature }}">{{ calc.natures["getNatureStr"](nature) }}</option>
          </select>
        </td>
      </tr>
    </table>
    
    <table class="statTable">
      <tr>
        <td></td>
        <th>HP</th>
        <th>Atk</th>
        <th>Def</th>
        <th>SpAtk</th>
        <th>SpDef</th>
        <th>Spd</th>
        <th>Total</th>
      </tr>
      
      <tr>
        <th class="rowLabel">Base</th>
        <td ng-repeat="stat in ['hp', 'atk', 'def', 'spatk', 'spdef', 'spd']">
          <input type="text" ng-model="calc.base[stat]" number-field min-num="0" max-num="999" disabled />
        </td>
        <td>
          <input type="text" ng-model="calc.base.total" disabled />
        </td>
      </tr>
      
      <tr>
        <th class="rowLabel">EVs</th>
        <td ng-repeat="stat in ['hp', 'atk', 'def', 'spatk', 'spdef', 'spd']">
          <input type="text"...

CSS

body
{
  opacity: .3;
  font-family: sans-serif;
}

.statTable input
{
  width: 50px;
  text-align: center;
  border: solid 1px #666;
  border-radius: 5px;
}

.rowLabel
{
  text-align: right;
}

.natureUp
{
  background-color: #F99;
}

.natureDown
{
  background-color: #99F;
}

#hp_img
{
width: 483px;
height: 46px;
background-repeat: no-repeat;
background-image:...

JavaScript

(function(){
	var app = angular.module("ivCalculator", []);
    
  app.controller("Calculator", ["$scope", function($scope){
  	var _self = this;
    var pkmnNames = $("<datalist>").attr("id", "pkmn_names");
    
  	this.pokemon = "";
    this.stats = pkmn_stats;
    
    this.stats.forEach(function(elem){
    	pkmnNames.append($("<option>").attr("value", elem.name));
    });
    $("body").append(pkmnNames);
    
    this.level = 1;
    this.base = new Stats();
    this.actual = new Stats();
    this.evs = new Stats();
    this.ivs = new Stats();
    this.nature = "hardy";
    this.nat_up = "";
    this.nat_down = "";
    this.natures = pkmn_natures;
    
    //*
    $scope.$watch('calc.level', function(newValue, oldValue){
    	if (newValue === oldValue) return;
      _self.doActualStats();
    });
    //*/
    
    $scope.$watch('calc.nature', function(newValue, oldValue){
    	if (newValue === oldValue) return;
      var effect = _self.natures.getEffect(newValue);
      _self.nat_up = effect.up;
      _self.nat_down = effect.down;
      _self.doActualStats();
    });
    
    $scope.$watch('calc.pokemon', function(newValue, oldValue){
    	if (newValue === oldValue) return;
      _self.setBaseStats(newValue);
    });
    
    this.setBaseStats = function(name)
    {
    	var pkmn = { "id":"", "name":"", "type":"", "total":"0", "hp":"0", "atk":"0", "def":"0", "spatk":"0", "spdef":"0", "spd":"0" };
      for (var i = 0; i < _self.stats.length; i++)
      {
      	if (name === _self.stats[i].name)
        {
        	pkmn = _self.stats[i];
          break;
        }
			}
      _self.base.set(pkmn);
      _self.doActualStats();
    }
    
    this.doStats = function()
    {
    	_self.updateIV("hp");
      _self.updateIV("atk");
      _self.updateIV("def");
      _self.updateIV("spatk");
      _self.updateIV("spdef");
      _self.updateIV("spd");
      _self.ivs.total = _self.ivs.getTotal();
    };
    
    this.doActualStats = function()
    {
     ...