HTMLFormTools/SchemaSure Example

HTML

<script src="https://cdn.rawgit.com/adamcarheden/schema-sure/master/SchemaSure.js"></script>
<script src="https://cdn.rawgit.com/adamcarheden/html-form-tools/master/html-form-tools.js"></script>
<h1>HTML Form Tools / Schema Sure Example</h1>

<p>
In 2017, the <a href='https://www.irs.gov/retirement-plans/plan-participant-employee/retirement-topics-ira-contribution-limits'>IRS</a> lets you contribute up to $5,500 to your Individual Retirement Accounts (IRA). People over 50 can contribute an additional $1000 for a total of $6,500.
</p>
<p>
There are two types of IRAs: Traditional and Roth. The contribution limits apply to the total contributions you make to all of your IRAs of either type. If you're over 70, you're not allowed to contribute to a Traditional IRA but you may still contribute to a Roth.
</p>
<p>
The form below calculates your total IRA contribution and lets you know if there's a problem with what you type. Note that it both formats your inputs with '$' and commas and prevents you from typing sensless values, such as non-numeric characters or an age of more than 2 digits (sorry, Methuselah, you'll need an accountant instead).
</p>

<table>
<tr id='r_age'>
	<td class='lbl'>How old are you?</td>
	<td id='c_age'><input id='age'/></td>
	<td class='err'></td>
</tr>
<tr id='r_traditional'>
	<td class='lbl'>Traditional IRA contribution: </td>
	<td id='c_tradditional'><input id='traditional'/></td>
	<td class='err'></td>
</tr>
<tr id='r_roth'>
	<td class='lbl'>Roth IRA Contribution: </td>
	<td id='c_roth'><input id='roth'/></td>
	<td class='err'></td>
</tr>
<tr id='r_limit'>
	<td class='lbl'>Combined Contribution Limit:</td>
	<td colspan='2' id='limit'></td>
</tr>
<tr id='r_total'>
	<td class='lbl'>Total IRA Contribution:</td>
	<td colspan='2' id='total'></td>
</tr>
<tr id='r_left'>
	<td class='lbl'>Amount Remaining:</td>
	<td colspan='2' id='left'></td>
</tr>

</table>

CSS

.err input {
	background-color: rgba(255,0,0,.15);
}
.err .err {
	font-style: italic;
	color: red;
}
.lbl {
	text-align: right;
}

JavaScript

var commafy = window['html-form-tools'].default.util.commafy

	// SchemaSure is a library for validating sets of JavaScript objects
	// We'll use it to define the back-end date represented by this form
	// https://github.com/adamcarheden/schema-sure
	var SchemaSure = window['SchemaSure'].default
	var schema = new SchemaSure()
	var numeric = function(val) {
		if (typeof val === 'undefined') return false
		if (val.toString().trim().length === 0) return false
		val = parseInt(val)
		if (isNaN(val)) return false
		return val
	}
	var ageLimit = function() {
		var age = numeric(this.age)
		var traditional = numeric(this.traditional)
		if (!(age && traditional)) return
		var max = 70
		if (age > max && traditional > 0) throw new Error("You may not contribute to a traditional IRA because you're older than "+max)
	}

	var IRA = schema.createClass('IRA', {
		age: { 
			validate: {
				'range': function() {
					var age = numeric(this.age)
					if (!age) return
					if (age < 0) throw new Error("you can't be less than 0 years old")
					if (age > 150) throw new Error(age+"? Ok, Methusela")
				},
				'age limit': ageLimit,
				'numeric': function() { return numeric(this.age) }
			}
		},
		traditional: {
			default: 0,
			validate: {
				'contribution limits': 'validateIRA',
				'age limit': ageLimit,
				'numeric': function() { return numeric(this.traditional) }
			}
		},
		roth: {
			default: 0,
			validate: {
				'contribution limits': 'validateIRA',
				'numeric': function() { return numeric(this.roth) }
			}
		},
		limit: { get: function() {	
			var age = numeric(this.age) || 0
			var max = 5500
			if (age > 50) max += 1000
			return max
		}},
		contribution: { get: function() { 
			var t = numeric(this.traditional) || 0
			var r = numeric(this.roth) || 0
			return t + r
		}},
		validateIRA: { value: function() {
			if (this.contribution > this.limit) throw new Error("You'll owe extra taxes	and penalties if the combined total of your traditional and roth IRA...