|
1 | 1 | const kg = document.getElementById('kg'); const cm = document.getElementById('cm'); const out = document.getElementById('out'); |
2 | | -function bmi() { |
3 | | - const w = parseFloat(kg.value), h = parseFloat(cm.value) / 100; |
4 | | - if (!(w > 0 && h > 0)) { out.textContent = 'Enter valid numbers'; return; } const v = w / (h * h); let cat = v < 18.5 ? 'Underweight' : v < 25 ? 'Normal' : v < 30 ? 'Overweight' : 'Obese'; out.textContent = `BMI: ${v.toFixed(1)} (${cat})`; |
| 2 | +function validateWeight(raw) { |
| 3 | + if (!raw) return 'Please enter your weight (kg).'; |
| 4 | + const v = Number(raw); |
| 5 | + if (!Number.isFinite(v)) return 'Weight must be a number (e.g., 70).'; |
| 6 | + if (v <= 0) return 'Weight must be greater than 0 kg.'; |
| 7 | + if (v < 20 || v > 300) return 'Please enter a realistic weight (20–300 kg).'; |
| 8 | + return ''; |
5 | 9 | } |
6 | | -document.getElementById('form').addEventListener('submit', e => { e.preventDefault(); bmi(); }); |
7 | | -// TODOs: save history; chart; unit toggle; input validation states |
| 10 | + |
| 11 | +function validateHeight(raw) { |
| 12 | + if (!raw) return 'Please enter your height (cm).'; |
| 13 | + const v = Number(raw); |
| 14 | + if (!Number.isFinite(v)) return 'Height must be a number (e.g., 170).'; |
| 15 | + if (v <= 0) return 'Height must be greater than 0 cm.'; |
| 16 | + if (v < 50 || v > 250) return 'Please enter a realistic height (50–250 cm).'; |
| 17 | + return ''; |
| 18 | +} |
| 19 | + |
| 20 | +function clearCustomValidity() { |
| 21 | + kg.setCustomValidity(''); |
| 22 | + cm.setCustomValidity(''); |
| 23 | + kg.removeAttribute('aria-invalid'); kg.style.borderColor = ''; |
| 24 | + cm.removeAttribute('aria-invalid'); cm.style.borderColor = ''; |
| 25 | +} |
| 26 | + |
| 27 | +function markFieldInvalid(el) { |
| 28 | + if (!el) return; |
| 29 | + el.setAttribute('aria-invalid', 'true'); |
| 30 | + el.style.borderColor = '#ff6b6b'; |
| 31 | +} |
| 32 | + |
| 33 | +function clearFieldInvalid(el) { |
| 34 | + if (!el) return; |
| 35 | + el.removeAttribute('aria-invalid'); |
| 36 | + el.style.borderColor = ''; |
| 37 | +} |
| 38 | + |
| 39 | +form?.addEventListener('submit', e => { |
| 40 | + e.preventDefault(); |
| 41 | + if (!kg || !cm || !out) return; |
| 42 | + |
| 43 | + clearCustomValidity(); |
| 44 | + |
| 45 | + const weightRaw = (kg.value ?? '').trim(); |
| 46 | + const heightRaw = (cm.value ?? '').trim(); |
| 47 | + |
| 48 | + const wErr = validateWeight(weightRaw); |
| 49 | + const hErr = validateHeight(heightRaw); |
| 50 | + |
| 51 | + if (wErr) kg.setCustomValidity(wErr); |
| 52 | + if (hErr) cm.setCustomValidity(hErr); |
| 53 | + |
| 54 | + if (wErr && hErr) { |
| 55 | + markFieldInvalid(kg); |
| 56 | + markFieldInvalid(cm); |
| 57 | + } else { |
| 58 | + if (wErr) markFieldInvalid(kg); else clearFieldInvalid(kg); |
| 59 | + if (hErr) markFieldInvalid(cm); else clearFieldInvalid(cm); |
| 60 | + } |
| 61 | + |
| 62 | + if (!form.checkValidity()) { |
| 63 | + const firstInvalid = kg.validity.valid ? cm : kg; |
| 64 | + firstInvalid.reportValidity(); |
| 65 | + firstInvalid.focus(); |
| 66 | + out.textContent = 'You have invalid Details'; |
| 67 | + return; |
| 68 | + } |
| 69 | + |
| 70 | + const w = parseFloat(weightRaw); |
| 71 | + const heightCm = parseFloat(heightRaw); |
| 72 | + const h = heightCm / 100; |
| 73 | + const bmi = w / (h * h); |
| 74 | + const cat = bmi < 18.5 ? 'Underweight' : bmi < 25 ? 'Normal' : bmi < 30 ? 'Overweight' : 'Obese'; |
| 75 | + out.textContent = `BMI: ${bmi.toFixed(1)} (${cat})`; |
| 76 | + clearCustomValidity(); |
| 77 | +}); |
| 78 | + |
| 79 | +[kg, cm].forEach(el => { |
| 80 | + el?.addEventListener('input', () => { |
| 81 | + el.setCustomValidity(''); |
| 82 | + clearFieldInvalid(el); |
| 83 | + }); |
| 84 | +}); |
| 85 | + |
0 commit comments