I've searched a while, can't find this... I'm looking for a way to present two choices for values, then to have a result immediately appear based on those choice. IE... The first choice is an option between 1, 2, 3, 4, or 5 players... and the second choice is an option between 1, 5, 10, 25, or 50 workouts. In the following textarea (or whatever) I'd like a price or a set of prices (based on the combinations, not a math formula) to appear as the choices are made and again when they're toggled.

Here's my start. Any help will do.

<style type="text/css">
 select {
  font-family: verdana, Arial, san-serif;
  font-size:    26px;
 }
</style>


<select name="options" size="1">
 <option value="1">1</option>
 <option value="2">2</option>
 <option value="3">3</option>
 <option value="4">4</option>
 <option value="4">5</option>
 <option value="4">6</option>
 <option value="4">7</option>
 <option value="4">8</option>
 <option value="4">9</option>
 <option value="4">10</option>
 <option value="4">11</option>
 <option value="4">12</option>
</select> player(s)<br>

<select name="options" size="1">
 <option value="1">1</option>
 <option value="2">5</option>
 <option value="3">10</option>
 <option value="4">25</option>
 <option value="4">50</option>
</select> workout(s)<br><hr>


<font size=5>$90</font> per player for each workout.<br>
<font size=5>$450</font> per player for all workouts.<br>
<font size=5>$450</font> total.

Maybe something like the following:

<FORM NAME="Calc">

<TABLE BORDER=6>

<TR>

<TD height=50 width=200 bgcolor="#000000"><center><select name="Input2" /> 
           <OPTION value="1">1 Player</OPTION>
           <OPTION value="2">2 Players</OPTION>
           <OPTION value="3">3 Players</OPTION>
           <OPTION value="4">4 Players</OPTION>
           <OPTION value="5">5 Players</OPTION>
           <OPTION value="6">6 Players</OPTION>
           <OPTION value="7">7 Players</OPTION>
           <OPTION value="8">8 Players</OPTION>
           <OPTION value="9">9 Players</OPTION>
           <OPTION value="10">10 Players</OPTION>
           <OPTION value="11">11 Players</OPTION>
           <OPTION value="12">12-15 Players</OPTION>

        </SELECT>
</center>
</TD>




<TD width="300" align="center" bgcolor="#000000">

<font color="#ffffff">$

<input type="text" name="Input" size="10" />



</TD>


</tr><tr>
<TD width="500" height=50 colspan=2 align="center" bgcolor="#000000">

<INPUT TYPE="button" NAME="one" VALUE=" 1 Workout " OnClick="Calc.Input2.value += 'Carrots '; Calc.Input.value += '+30'; Calc.Input.value = eval(Calc.Input.value)" />

<INPUT TYPE="button" NAME="four" VALUE=" 5 Workouts " OnClick="Calc.Input2.value += 'Eggs '; Calc.Input.value += '+200'; Calc.Input.value = eval(Calc.Input.value)" />

<INPUT TYPE="button" NAME="seven" VALUE=" 10 Workouts " OnClick="Calc.Input2.value += 'Bananas '; Calc.Input.value += '+70'; Calc.Input.value = eval(Calc.Input.value)" />

<INPUT TYPE="button" NAME="four" VALUE=" 25 Workouts " OnClick="Calc.Input2.value += 'Eggs '; Calc.Input.value += '+200'; Calc.Input.value = eval(Calc.Input.value)" />

<INPUT TYPE="button" NAME="seven" VALUE=" 50 Workouts " OnClick="Calc.Input2.value += 'Bananas '; Calc.Input.value += '+70'; Calc.Input.value = eval(Calc.Input.value)" />

</TD>

</TR>

</TABLE>

</FORM>

And I'd want the values to be predetermined, not mathematical based, so that I could offer deals and special offers.

Jonsan,

Reading between the lines here, I think you want something that is part algorithmic and part lookup (to accommodate a discount structure).

Therefore, the rate per player per workout is to be discovered by lookup, but the other two values are to be calculated, based on the lookup value.

If I'm right, then the code will be something like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
select {
  font-family: verdana, Arial, san-serif;
  font-size: 26px;
}
#prices {
  font-size: 12pt;
}
#prices span {
  font-size: 18pt;
}
</style>

<script type='text/javascript'>
onload = function() {
	var playersMenu = document.selections.players;
	var workoutsMenu = document.selections.workouts;
	var ppr = document.getElementById("perPlayerRate");
	var ppt = document.getElementById("perPlayerTotal");
	var tot = document.getElementById("total");

	if(playersMenu && workoutsMenu && ppr && ppt && tot) {
		playersMenu.onchange = workoutsMenu.onchange = function () {
			var players = parseInt(playersMenu[playersMenu.selectedIndex].value);
			var w = workoutsMenu[workoutsMenu.selectedIndex].value.split('@');
			var workouts = parseInt(w[0]);
			var rate = parseFloat(w[1]);
			ppr.innerHTML = rate.toFixed(2);
			ppt.innerHTML = (workouts * rate).toFixed(2);
			tot.innerHTML = (players * workouts * rate).toFixed(2);
		}
	}
	playersMenu.onchange();
}
</script>
</head>

<body>

<form name="selections">
<select name="players">
 <option value="1">1</option>
 <option value="2">2</option>
 <option value="3">3</option>
 <option value="4">4</option>
 <option value="5">5</option>
 <option value="6">6</option>
 <option value="7">7</option>
 <option value="8">8</option>
 <option value="9">9</option>
 <option value="10">10</option>
 <option value="11">11</option>
 <option value="12">12</option>
</select> player(s)<br>

<select name="workouts">
 <option value="1@90">1</option>
 <option value="5@85">5</option>
 <option value="10@80">10</option>
 <option value="25@70">25</option>
 <option value="50@60">50</option>
</select> workout(s)<br>
</form>

<hr>

<div id="prices">
	<div><span>$</span><span id="perPlayerRate">0</span> per player for each workout.</div>
	<div><span>$</span><span id="perPlayerTotal">0</span> per player for all workouts.</div>
	<div><span>$</span><span id="total">0</span> total.</div>
</div>

</body>
</html>

Note how the discount structure is coded in the option-values of the workouts menu.

Airshow

Jonsan, <OPTION value="12">12-15 Players</OPTION> would be no good. It would allow "rate per player per workout" to be looked up but without a specifying a definate number of players.

Airshow

Jonsan, <OPTION value="12">12-15 Players</OPTION> would be no good. It would allow "rate per player per workout" to be looked up but without a specifying a definate number of players.

Airshow

That is amazing, and I can definitely work with that. What would be perfect is if I could just call one of 50 different values whenever a combination is selected. The math could be used in regards to figuring out the per player for each workout, per player for all workouts, and total bit...

I'm trying to have a system that entices them to get more workouts with more people. Here's my real example: http://www.epicbasketball.com/p/pricing.html

If what I speak of is impossible/impractical/difficult, I can definitely work with what you've given me. Thanks a ton.

Jonsan,

There's nothing impossible there but with a number of "packages" (solo, crew, etc.) we have to approach things slightly differently from before - namely by defining all the data in javascript rather than in the HTML.

I've had a play and come up with the following:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
select {
  font-family: verdana, Arial, san-serif;
  font-size: 26px;
}
#prices {
  font-size: 12pt;
}
#prices span {
  font-size: 18pt;
}
.border {
	border: 1px solid #000;
}
.padding {
	padding: 3px;
}
.right {
	text-align: right;
}
</style>

<script type='text/javascript'>
var PRICING = function(){//NAMESPACE pattern
	var packages = {};
	var breakpoints = [];

	function setBreakpoints(b) {
		breakpoints = b;
	}
	function addPackage(name, prices, description) {
		packages[name] = {prices:prices, description:description};
	}
	function getDescription(package) {
		return packages[package.toUpperCase()].description;
	}
	
	function getPricePerItem(package, w) {
		package = package.toUpperCase();//make the package string case insensitive
		var w = ( !w || isNaN(w) || w<1 ) ? 1 : Math.round(w);//sanitize w (number of workouts)
		for(var i=0; i<breakpoints.length; i++) {
			if(w < breakpoints[i]) { break; }
		}
		if(packages[package.toUpperCase()]) {
			var p = (packages[package].prices[i-1]) ? packages[package].prices[i-1] : null;
			return {w:w, breakpoint:breakpoints[i-1], price:p};
		}
		return {package:package, breakpoint:b, price:null};
	}
	function printPricingTable(containerID, pckgs){
		var container = document.getElementById(containerID);
		if(!container) { return; }
		var table = document.createElement('table');
		table.className = 'border';
		container.appendChild(table);
		var row, cell, priceObj;
		row = table.insertRow(0);
		cell = row.insertCell(0);
		for(var j=0; j<breakpoints.length; j++) {
			cell = row.insertCell(j+1);
			cell.className = 'border padding';
			cell.innerHTML = breakpoints[j] + "+";
		}
		for(var i=0; i<pckgs.length; i++) {
			row = table.insertRow(i+1);
			cell = row.insertCell(0);
			cell.className = 'border padding';
			cell.innerHTML = pckgs[i] + '<br><span style="color:gray;font-size:9pt;">' + getDescription(pckgs[i]) + '</span>';
			for(var j=0; j<breakpoints.length; j++) {
				cell = row.insertCell(j+1);
				cell.className = 'border padding right';
				priceObj = getPricePerItem(pckgs[i], breakpoints[j]);
				cell.innerHTML = priceObj.price ? "$" +  priceObj.price : '-';
			}
		}
	}
	return {
		setBreakpoints: setBreakpoints,
		addPackage: addPackage,
		getDescription: getDescription,
		getPricePerItem: getPricePerItem,
		printPricingTable: printPricingTable
	};
}();

onload = function() {
	// ********************************************
	// ******* Here, establish all the data *******
	// ********************************************
	PRICING.setBreakpoints([1,5,10,25,50]);
	PRICING.addPackage('SOLO', [90,88,85,83,80], '1 Player'),
	PRICING.addPackage('CREW', [27,25,24,23,21], '2-4 Players'),
	PRICING.addPackage('EPIC', [null,null,null,null,15], '1 Member in a 9-12 Player group'),
	PRICING.addPackage('SQUAD',[17,14,13,12,11], '5-8 Players'),
	PRICING.addPackage('TEAM', [13,11,10,9,8], '9-15 Player')
	// ********************************************
	// ********************************************

	PRICING.printPricingTable('pricingTable', ['SOLO', 'CREW', 'EPIC', 'SQUAD', 'TEAM']);
	
	var playersMenu = document.selections.players;
	var workoutsMenu = document.selections.workouts;
	var packageMenu = document.selections.package;
	var packageDescr = document.getElementById("packageDescr");
	var ppr = document.getElementById("perPlayerRate");
	var ppt = document.getElementById("perPlayerTotal");
	var tot = document.getElementById("total");
	var cache = {};
	if(playersMenu && workoutsMenu && packageMenu && ppr && ppt && tot) {
		playersMenu.onchange = workoutsMenu.onchange = packageMenu.onchange = function () {
			var package = packageMenu[packageMenu.selectedIndex].value;
			packageDescr.innerHTML = PRICING.getDescription(package);
			if(package=='EPIC') {
				cache.playersMenuIndex = playersMenu.selectedIndex;
				cache.workoutsMenuIndex = workoutsMenu.selectedIndex;
				playersMenu.selectedIndex = 0;
				workoutsMenu.selectedIndex = 4;
				playersMenu.disabled = true;
				workoutsMenu.disabled = true;
			}
			else {
				if(cache.playersMenuIndex >= 0) {
					playersMenu.selectedIndex = cache.playersMenuIndex;
					cache.playersMenuIndex = -1;
				}
				if(cache.workoutsMenuIndex >= 0) {
					workoutsMenu.selectedIndex = cache.workoutsMenuIndex;
					cache.workoutsMenuIndex = -1;
				}
				playersMenu.disabled = false;
				workoutsMenu.disabled = false;
			}
			var players = parseInt(playersMenu[playersMenu.selectedIndex].value);
			var workouts = parseInt(workoutsMenu[workoutsMenu.selectedIndex].value);
			var priceObj = PRICING.getPricePerItem(package,workouts);
			var rate = priceObj.price;
			ppr.innerHTML = (rate) ? rate.toFixed(2) : '-';
			ppt.innerHTML = (rate) ? (workouts * rate).toFixed(2) : '-';
			tot.innerHTML = (rate) ? (players * workouts * rate).toFixed(2) : '-';
		}
	}
	playersMenu.onchange();
}
</script>
</head>

<body>

<form name="selections">
<select name="package">
 <option value="SOLO">SOLO</option>
 <option value="CREW">CREW</option>
 <option value="EPIC">EPIC</option>
 <option value="SQUAD">SQUAD</option>
 <option value="TEAM">TEAM</option>
</select> Package<br>

<div id="packageDescr"></div>

<select name="workouts">
 <option value="1">1</option>
 <option value="5">5</option>
 <option value="10">10</option>
 <option value="25">25</option>
 <option value="50">50</option>
</select> workout(s)<br>

<select name="players">
 <option value="1">1</option>
 <option value="2">2</option>
 <option value="3">3</option>
 <option value="4">4</option>
 <option value="5">5</option>
 <option value="6">6</option>
 <option value="7">7</option>
 <option value="8">8</option>
 <option value="9">9</option>
 <option value="10">10</option>
 <option value="11">11</option>
 <option value="12">12</option>
</select> player(s)<br>
</form>

<hr>

<div id="prices">
	<div><span>$</span><span id="perPlayerRate">0</span> per player for each workout.</div>
	<div><span>$</span><span id="perPlayerTotal">0</span> per player for all workouts.</div>
	<div><span>$</span><span id="total">0</span> total.</div>
</div>

<hr>

<div id="pricingTable"></div>

</body>
</html>

You will see that I have lumped a lot the complexity together in a javascript "namespace" called "PRICING", which is loaded with your data at lines 94-99.

Once loaded with data, PRICING becomes a glorified 2-dimensional lookup table, queried by calling PRICING.getPricePerItem(package, workouts) , where:

  • package: is "SOLO", "CREW" etc.
  • workouts: is the number of workouts.

PRICING.getPricePerItem returns an object containing the following properties:

  • .price: is the price per item (ie price per player).
  • .w: is the number of workouts actually used (after range checking) to lookup the price
  • .breakpoint: is the discounting breakpoint in which w lies.

.w and .breakpoint are included for completeness in case they are ever needed.

Also included is a utility method PRICING.printPricingTable(containerID, pckgs) , where:

  • containerID: is the id of an HTML element in which the table is to be displayed
  • pckgs: an array of package names ["SOLO", "CREW", etc.], each of which will become a line entry in the table.

PRICING.printPricingTable is intended to allow the data to be inspected. The standard of presentation is unlikely to be good enough for production use.

The onload function contains examples of how PRICING might be used:

  1. to implement a pricing query as specified by a set of pulldown menus (similar to the code in the previous post above). You will see that your EPIC package requires some exception handling.
  2. to print out the data table

Your requirement is probably different but the examples should give you enough of a clue to see how PRICING (or something very much like it) might be used.

Airshow

commented: Nice lecture. Thanks Airshow - Zero13 +6
commented: Amazing +1

You're unreal. Thank you so much. No way I could've done this without you. Much appreciated.

Is there an easy way for me to only let them select a certain number of players based on which package they select? IE If they pick SQUAD, only the 5, 6, 7, and 8 options would be available to choose....

Not necessary, though. Thanks again.

Jonsan,

Is there an easy way for me to only let them select a certain number of players based on which package they select? IE If they pick SQUAD, only the 5, 6, 7, and 8 options would be available to choose....

I realise that is a shortcoming of the code I posted above, so I have prepared an improved version.

Manipulating the "players" menu is rather difficult with standard javascript but much easier with the jquery lib. The code below uses jquery throughout.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
select {
  font-family: verdana, Arial, san-serif;
  font-size: 26px;
}
#prices {
  font-size: 12pt;
}
#prices span {
  font-size: 18pt;
}
.border {
	border: 1px solid #000;
}
.padding {
	padding: 3px;
}
.right {
	text-align: right;
}
</style>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<!-- NOTE: Use own, locally served clpy of jquery in live production environment -->
<script type='text/javascript'>
var PRICING = function(){//NAMESPACE pattern
	var packages = {};//object of package objects, indexed by name
	var packages_array = [];//array of package names
	var breakpoints = [];

	function setBreakpoints(b) {
		breakpoints = b;
	}
	function addPackage(name, prices, description, values) {
		packages[name] = {prices:prices, description:description, values:values};
		packages_array.push(name);
	}
	function getDescription(package) {
		return packages[package.toUpperCase()].description;
	}
	function getValues(package) {
		return packages[package.toUpperCase()].values;
	}
	
	function getPricePerItem(package, w) {
		package = package.toUpperCase();//make the package string case insensitive
		var w = ( !w || isNaN(w) || w<1 ) ? 1 : Math.round(w);//sanitize w (number of workouts)
		for(var i=0; i<breakpoints.length; i++) {
			if(w < breakpoints[i]) { break; }
		}
		if(packages[package.toUpperCase()]) {
			var p = (packages[package].prices[i-1]) ? packages[package].prices[i-1] : null;
			return {w:w, breakpoint:breakpoints[i-1], price:p};
		}
		return {package:package, breakpoint:b, price:null};
	}
	function printPricingTable(containerID, pckgs){
		pckgs = (!pckgs) ? packages_array : pckgs;
		var $container = $("#"+containerID);
		var $table = $('<table>').addClass('border').appendTo($container);
		var $row, price;
		$row = $("<tr>").appendTo($table);
		$("<td>").appendTo($row);
		for(var j=0; j<breakpoints.length; j++) {
			$("<td>").appendTo($row).addClass('border padding').html(breakpoints[j] + "+");
		}
		for(var i=0; i<pckgs.length; i++) {
			$row = $("<tr>").appendTo($table);
			$("<td>").appendTo($row).addClass('border padding').html(pckgs[i] + '<br><span style="color:gray;font-size:9pt;">' + getDescription(pckgs[i]) + '</span>');
			for(var j=0; j<breakpoints.length; j++) {
				price = getPricePerItem(pckgs[i], breakpoints[j]).price;
				$("<td>").appendTo($row).addClass('border padding right').html(price ? "$" +  price : '-');
			}
		}
	}
	return {
		setBreakpoints: setBreakpoints,
		addPackage: addPackage,
		getDescription: getDescription,
		getValues: getValues,
		getPricePerItem: getPricePerItem,
		printPricingTable: printPricingTable
	};
}();

$(document).ready(function() {
	// ********************************************
	// ******* Here, establish all the data *******
	// ********************************************
	PRICING.setBreakpoints([1,5,10,25,50]);
	PRICING.addPackage('SOLO', [90,88,85,83,80], '1 Player', [1]),
	PRICING.addPackage('CREW', [27,25,24,23,21], '2-4 Players', [2,3,4]),
	PRICING.addPackage('EPIC', [null,null,null,null,15], '1 Member in a 9-12 Player group', [1]),
	PRICING.addPackage('SQUAD',[17,14,13,12,11], '5-8 Players', [5,6,7,8]),
	PRICING.addPackage('TEAM', [13,11,10,9,8], '9-15 Players', [9,10,11,12,13,14,15])
	// ********************************************
	// ********************************************

	PRICING.printPricingTable('pricingTable');

	var $playersMenu = $('[name="players"]');
	var $workoutsMenu = $('[name="workouts"]');
	var $packageMenu = $('[name="package"]');
	var $packageDescr = $("#packageDescr");
	var $ppr = $("#perPlayerRate");
	var $ppt = $("#perPlayerTotal");
	var $tot = $("#total");
	var cache = {};

	//shuffle all "players" options into a dummy select element.
	var $dummyMenu = $("<select>");
	$playersMenu.find("option").each(function() {
		$(this).appendTo($dummyMenu);
	});
	
	//function to constrain the "players" menu in response to the current package selection.
	function setPlayersMenu() {
		var package = $packageMenu.val();
		var values = PRICING.getValues(package);
		//first remove any previously cloned "players" options
		$playersMenu.find("option").each(function() {
			$(this).remove();
		});
		//now selectively clone options from the dummy menu.
		$dummyMenu.find("option").each(function(){
			var $opt = $(this);
			if($.inArray( Number($opt.attr('value')),values) > -1) {
				$opt.clone().appendTo($playersMenu);	
			}
		});
		$playersMenu.val(values[0]);//otherwise last appended option is selected.
	}

	function menuChange() {
		var package = $packageMenu.val();
		$packageDescr.html(PRICING.getDescription(package));
		if(package=='EPIC') {
			cache.workoutsMenuVal = $workoutsMenu.val();
			$workoutsMenu.val('50');
			$workoutsMenu.attr('disabled',true);
		}
		else {
			if(cache.workoutsMenuVal) {
				$workoutsMenu.val(cache.workoutsMenuVal);
				cache.workoutsMenuVal = null;
			}
			$workoutsMenu.attr('disabled',false);
		}
		var players = Number($playersMenu.val());
		var workouts = Number($workoutsMenu.val());
		var rate = PRICING.getPricePerItem(package,workouts).price;
		$ppr.html((rate) ? rate.toFixed(2) : '-');
		$ppt.html((rate) ? (workouts * rate).toFixed(2) : '-');
		$tot.html((rate) ? (players * workouts * rate).toFixed(2) : '-');
	}
	$packageMenu.change(setPlayersMenu);
	$().add($packageMenu).add($playersMenu).add($workoutsMenu).change(menuChange);
	setPlayersMenu();
	menuChange();
});
</script>
</head>

<body>

<form name="selections">
<select name="package">
 <option value="SOLO">SOLO</option>
 <option value="CREW">CREW</option>
 <option value="EPIC">EPIC</option>
 <option value="SQUAD">SQUAD</option>
 <option value="TEAM">TEAM</option>
</select> Package<br>

<div id="packageDescr"></div>

<select name="workouts">
 <option value="1">1</option>
 <option value="5">5</option>
 <option value="10">10</option>
 <option value="25">25</option>
 <option value="50">50</option>
</select> workout(s)<br>

<select name="players">
 <option value="1">1</option>
 <option value="2">2</option>
 <option value="3">3</option>
 <option value="4">4</option>
 <option value="5">5</option>
 <option value="6">6</option>
 <option value="7">7</option>
 <option value="8">8</option>
 <option value="9">9</option>
 <option value="10">10</option>
 <option value="11">11</option>
 <option value="12">12</option>
 <option value="13">13</option>
 <option value="14">14</option>
 <option value="15">15</option>
</select> player(s)
</form>

<hr>

<div id="prices">
	<div><span>$</span><span id="perPlayerRate">0</span> per player for each workout.</div>
	<div><span>$</span><span id="perPlayerTotal">0</span> per player for all workouts.</div>
	<div><span>$</span><span id="total">0</span> total.</div>
</div>

<hr>

<div id="pricingTable"></div>

</body>
</html>

I have played with this quite a bit and it seems to be robust but could be better commented than I have had time for.

Please note the comment against the jquery script (download then serve own copy of jquery). http://docs.jquery.com/Downloading_jQuery

Airshow

commented: thanks +13
commented: PERFECT +1

Surreal and perfect. I've already implemented this (http://www.epicbasketball.com/p/pricing.html), but will touch it up as time goes by. This is something I'll start within a year or so, and you've given more me of a chance to actualize my dream. I couldn't thank you more. I'm gonna make, and revisit it (and you) if anything ever comes into fruition monetarily. Thanks a ton!

.

Page looks good.

Good luck with your project, Jonsan. I hope the code serves you well.

Airshow

Before I ask another forum, I thought I'd just ask the source. Although changing the prices in the code is easy, I can't figure out the math enough to alter the formula. I'd like for the total price per workout to be more uniform. For example, if it's 2-4 players, I'd need them paying $92. So if 2 players are selected, it should be $46 each. If 3, it would be $30.66. And 4 would yield $23 each.

I've outlined my pricing on a spreadsheet if you (or anyone else) could look it over. I actually break it down by how much I'd like per player regardless of package chosen, but I wouldn't mind the same price being paid for any number of players within a given package.

https://spreadsheets.google.com/spreadsheet/pub?key=0AmWD_Na4J_4BdENpSVc4d1hjRDFMMTJxbTRKUDlXZ3c&output=html&chrome=false

My goal is to entice them subtly to get more kids in my program and to buy more workouts because of the gradual, yet noticeable, reduction in price.

Z per player for each workout.
Y per player for all workouts.
X total.

I'd need X to be a given number, then Y and Z to be dependent on X.

And no worries, you've helped more than enough. I can easily go elsewhere if you're time is slim. Thanks again.

Jonsan,

I have had a good look and have a few observations:

  • The text and spreadsheet appear to impose different requirements. In particular, the text says "if it's 2-4 players, I'd need them paying $92" but the spreadsheet gives different prices for 2,3,4 players.
  • The discount structure as depicted in the spreadsheet appears to negate the need for packages (SOLO, CREW etc.) As it stands, each line entry in the table stands in its own right, without breakpoints.
  • The pricing structure as depicted in the spreadsheet appears to be upside down. Does the "volume discount" for number of players work in the wrong sense?

If I have understood correctly, I think these requirements can't be accommodated without major changes to what already exists. As far as I can tell, it's more than a simple tweak of the math.

Airshow

Sorry about that. Your point was exactly what I was trying to say that I'm okay with. I should've made the spreadsheet reflect that. Each package having its own price never entered my mind until I saw your first post, but I like it a lot. I've altered the spreadsheet at https://spreadsheets.google.com/spreadsheet/pub?hl=en_US&hl=en_US&key=0AmWD_Na4J_4BdENpSVc4d1hjRDFMMTJxbTRKUDlXZ3c&output=html

Just as the math is now, I only get $56 or less for one workout, and that's bad when the gym cost that much. I just need a certain total for each, then have the price per individual based off of that. And again, I can try asking elsewhere. Thanks for all your help.

Jonsan,

That's a relief. The changes are minimal. Structurally all the html and javascript stay the same.

It's just a question of specifying price-per-workout in the data, rather than price per-player-per-workout, then dividing all through by the selected number of players in the math at lines 156-158, which all looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
select {
  font-family: verdana, Arial, san-serif;
  font-size: 26px;
}
#prices {
  font-size: 12pt;
}
#prices span {
  font-size: 18pt;
}
.border {
	border: 1px solid #000;
}
.padding {
	padding: 3px;
}
.right {
	text-align: right;
}
</style>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<!-- NOTE: Use own, locally served copy of jquery in live production environment -->
<script type='text/javascript'>
var PRICING = function(){//NAMESPACE pattern
	var packages = {};//object of package objects, indexed by name
	var packages_array = [];//array of package names
	var breakpoints = [];

	function setBreakpoints(b) {
		breakpoints = b;
	}
	function addPackage(name, prices, description, values) {
		packages[name] = {prices:prices, description:description, values:values};
		packages_array.push(name);
	}
	function getDescription(package) {
		return packages[package.toUpperCase()].description;
	}
	function getValues(package) {
		return packages[package.toUpperCase()].values;
	}
	
	function getPricePerItem(package, w) {
		package = package.toUpperCase();//make the package string case insensitive
		var w = ( !w || isNaN(w) || w<1 ) ? 1 : Math.round(w);//sanitize w (number of workouts)
		for(var i=0; i<breakpoints.length; i++) {
			if(w < breakpoints[i]) { break; }
		}
		if(packages[package.toUpperCase()]) {
			var p = (packages[package].prices[i-1]) ? packages[package].prices[i-1] : null;
			return {w:w, breakpoint:breakpoints[i-1], price:p};//price is $ per workout (all players)
		}
		return {package:package, breakpoint:b, price:null};
	}
	function printPricingTable(containerID, pckgs){
		pckgs = (!pckgs) ? packages_array : pckgs;
		var $container = $("#"+containerID);
		var $table = $('<table>').addClass('border').appendTo($container);
		var $row, price;
		$row = $("<tr>").appendTo($table);
		$("<td>").appendTo($row);
		for(var j=0; j<breakpoints.length; j++) {
			$("<td>").appendTo($row).addClass('border padding').html(breakpoints[j] + "+");
		}
		for(var i=0; i<pckgs.length; i++) {
			$row = $("<tr>").appendTo($table);
			$("<td>").appendTo($row).addClass('border padding').html(pckgs[i] + '<br><span style="color:gray;font-size:9pt;">' + getDescription(pckgs[i]) + '</span>');
			for(var j=0; j<breakpoints.length; j++) {
				price = getPricePerItem(pckgs[i], breakpoints[j]).price;
				$("<td>").appendTo($row).addClass('border padding right').html(price ? "$" +  price : '-');
			}
		}
	}
	return {
		setBreakpoints: setBreakpoints,
		addPackage: addPackage,
		getDescription: getDescription,
		getValues: getValues,
		getPricePerItem: getPricePerItem,
		printPricingTable: printPricingTable
	};
}();

$(document).ready(function() {
	// ********************************************
	// ******* Here, establish all the data *******
	// ********************************************
	PRICING.setBreakpoints([1,5,10,25,50]);
	PRICING.addPackage('SOLO', [90,88,86,84,82], '1 Player', [1]),
	PRICING.addPackage('CREW', [96,94,92,90,88], '2-4 Players', [2,3,4]),
	PRICING.addPackage('EPIC', [null,null,null,null,75], '1 Member', [1]),
	PRICING.addPackage('SQUAD',[104,102,100,98,96], '5-8 Players', [5,6,7,8]),
	PRICING.addPackage('TEAM', [118,116,114,112,110	], '9-15 Players', [9,10,11,12,13,14,15])
	// ********************************************
	// ********************************************

	PRICING.printPricingTable('pricingTable');

	var $playersMenu = $('[name="players"]');
	var $workoutsMenu = $('[name="workouts"]');
	var $packageMenu = $('[name="package"]');
	var $packageDescr = $("#packageDescr");
	var $ppr = $("#perPlayerRate");
	var $ppt = $("#perPlayerTotal");
	var $tot = $("#total");
	var cache = {};

	//shuffle all "players" options into a dummy select element.
	var $dummyMenu = $("<select>");
	$playersMenu.find("option").each(function() {
		$(this).appendTo($dummyMenu);
	});
	
	//function to constrain the "players" menu in response to the current package selection.
	function setPlayersMenu() {
		var package = $packageMenu.val();
		var values = PRICING.getValues(package);
		//first remove any previously cloned "players" options
		$playersMenu.find("option").each(function() {
			$(this).remove();
		});
		//now selectively clone options from the dummy menu.
		$dummyMenu.find("option").each(function(){
			var $opt = $(this);
			if($.inArray( Number($opt.attr('value')),values) > -1) {
				$opt.clone().appendTo($playersMenu);	
			}
		});
		$playersMenu.val(values[0]);//otherwise last appended option is selected.
	}

	function menuChange() {
		var package = $packageMenu.val();
		$packageDescr.html(PRICING.getDescription(package));
		if(package=='EPIC') {
			cache.workoutsMenuVal = $workoutsMenu.val();
			$workoutsMenu.val('50');
			$workoutsMenu.attr('disabled',true);
		}
		else {
			if(cache.workoutsMenuVal) {
				$workoutsMenu.val(cache.workoutsMenuVal);
				cache.workoutsMenuVal = null;
			}
			$workoutsMenu.attr('disabled',false);
		}
		var players = Number($playersMenu.val());
		var workouts = Number($workoutsMenu.val());
		var rate = PRICING.getPricePerItem(package,workouts).price;//price per workout
		$ppr.html((rate) ? (rate/players).toFixed(2) : '-');//per player rate
		$ppt.html((rate) ? (workouts * rate/players).toFixed(2) : '-');//per player total
		$tot.html((rate) ? (workouts * rate).toFixed(2) : '-');//total for all workouts
	}
	$packageMenu.change(setPlayersMenu);
	$().add($packageMenu).add($playersMenu).add($workoutsMenu).change(menuChange);
	setPlayersMenu();
	menuChange();
});
</script>
</head>

<body>

<form name="selections">
<table cellpadding="5" width="950" bgcolor="#000000">
<tr>
<td width="20%" valign="top" style="text-align:center;color:#FFF;">
<select name="package" style="margin-top:15px; background-color:#000; color:#FFF;">
 <option value="SOLO">SOLO</option>
 <option value="CREW">CREW</option>
 <option value="EPIC">EPIC</option>
 <option value="SQUAD">SQUAD</option>
 <option value="TEAM">TEAM</option>
</select><br>
<div id="packageDescr"></div>

</td><td width="20%" style="text-align:center;" valign="top">

<select name="players" style="margin-top:15px; background-color:#000; color:#FFF;">
 <option value="1">1</option>
 <option value="2">2</option>
 <option value="3">3</option>
 <option value="4">4</option>
 <option value="5">5</option>
 <option value="6">6</option>
 <option value="7">7</option>
 <option value="8">8</option>
 <option value="9">9</option>
 <option value="10">10</option>
 <option value="11">11</option>
 <option value="12">12</option>
 <option value="13">13</option>
 <option value="14">14</option>
 <option value="15">15</option>
</select> player(s)
 
</td><td width="20%" style="text-align:center;" valign="top">

<select name="workouts" style="margin-top:15px; background-color:#000; color:#FFF;">
 <option value="1">1</option>
 <option value="5">5</option>
 <option value="10">10</option>
 <option value="25">25</option>
 <option value="50">50</option>
</select> workout(s)

</td><td width="40%" valign="top">
 
<div id="prices" style="color:#ffffff;">
	<div><span>$</span><span id="perPlayerRate">0</span> per player for each workout.</div>
	<div><span>$</span><span id="perPlayerTotal">0</span> per player for all workouts.</div>
	<div><span>$</span><span id="total">0</span> total.</div>
</div>

</td></tr></table>
</form>

<hr>

<div id="pricingTable"></div>

</body>
</html>

I've left the "EPIC" package in there unmolested except for assuming a per workout rate of $75 at line 97 (easily changed).

Hope this correctly reflects your requirement.

Airshow

Picture perfect. Just had to make that one change you mentioned on EPIC. I'd be nowhere without you. Cheers!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.