// Constants
const form = document.forms['bmr-calculator'];
const resultBmr = document.querySelector('#result-bmr');
const resultTdee = document.querySelector('#result-tdee');
// Forward declaration
const main = () => {
form.addEventListener('submit', e => calculate(e, {
bmr: resultBmr,
tdee: resultTdee
}));
setFormValues(form, {
mode: 'Imperial',
age: 18,
weight: 180, // 180 lbs
height: 60, // 6' 00"
activityLevel: 1 // Light activity
});
};
// Begin helper functions
const setFormValues = (form, values) =>
Object.entries(values).forEach(([name, value]) => {
form.elements[name].value = value;
});
const fieldMap = (form) => Object.fromEntries([...form.elements]
.map((input) => {
switch (input.tagName.toLowerCase()) {
case 'input':
const type = input.getAttribute('type');
switch (type) {
case 'number':
return [input.name, +input.value];
}
}
return [input.name, input.value];
})
.filter(([key]) => key));
// Begin calculator
const activityFactors = [ 1.2, 1.375, 1.55, 1.725, 1.9 ];
const calculateBmr = (mode, gender, age, weight, height) => {
const factor = gender === 'Female' ? -161 : 5;
switch (mode) {
case 'Metric':
return (10 * weight) + (6.25 * height) - (5 * age) + factor;
case 'Imperial':
return (4.536 * weight) + (15.88 * height) - (5 * age) + factor;
}
throw new Error(`Unknown mode "${mode}"`);
};
const calculateTdee = (bmr, activityLevel) => {
return bmr * activityFactors[+activityLevel]
};
const calculate = (e, hooks) => {
const form = e.target;
const fields = fieldMap(form);
const { mode, gender, age, weight, height, activityLevel } = fields;
const bmr = calculateBmr(mode, gender, age, weight, height);
const tdee = calculateTdee(bmr, activityLevel);
hooks.bmr.textContent = bmr.toFixed(2);
hooks.tdee.textContent = tdee.toFixed(2);
};
// Call main
main();
form
.results {
display: flex;
flex-direction: column;
width: 25vw;
}
.form-field,
.result-row {
display: grid;
grid-auto-flow: column;
grid-template-columns: 8em 1fr;
margin-bottom: 0.33em;
}
.form-field > label,
.result-row > label {
font-weight: bold;
}
.form-field > label:after,
.result-row > label:after {
content: ':';
}
<form name="bmr-calculator" onsubmit="return false;">
<div class="form-field">
<label>Mode</label>
<select name="mode">
<option value="Metric">Metric</option>
<option value="Imperial">Imperial</option>
</select>
</div>
<div class="form-field">
<label>Gender</label>
<select name="gender">
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</div>
<div class="form-field">
<label>Age</label>
<input type="number" min="0" name="age" />
</div>
<div class="form-field">
<label>Weight (kg/lbs)</label>
<input type="number" min="0.0" step="0.01" name="weight" />
</div>
<div class="form-field">
<label>Height (cm/in)</label>
<input type="number" min="0.0" step="0.01" name="height" />
</div>
<div class="form-field">
<label>Activity Level</label>
<select name="activityLevel">
<option value="0">Sedentary (Little or no exercise)</option>
<option value="1">Light Activity (1-3 days/week)</option>
<option value="2">Moderate Activity (3-5 days/week)</option>
<option value="3">Very Activity (6-7 days/week)</option>
<option value="4">Super Active (Physical job)</option>
</select>
</div>
<input type="submit" value="Calculate BMR" />
</form>
<hr />
<div class="results">
<div class="result-row">
<label>BMR</label>
<span id="result-bmr"></span>
</div>
<div class="result-row">
<label>TDEE</label>
<span id="result-tdee"></span>
</div>
</div>