Cчётчик калорий JS
Посмотрите своими опытными глазами почему не отрабатывает JS. У меня ошибка вот такая вылазит: Uncaught ReferenceError: Cannot access 'CaloriesCounter' before initialization
const counterElements = document.querySelectorAll(".counter");
counterElements.forEach((elem) => {
const counter = new CaloriesCounter(elem);
counter.init();
});
const caloriesFormulaConstants = new Map([
["male", 5],
["female", -161],
]);
const physicalActivityRatios = new Map([
["min", 1.2],
["low", 1.375],
["medium", 1.55],
["high", 1.725],
["max", 1.9],
]);
class CaloriesCounter {
constructor(element) {
this.root = element;
this.form = this.root.querySelector(".counter-form");
this.elements = this.form.elements;
this.parameters = [...this.elements.parameters.elements];
this.genderInputs = this.form.elements.gender;
this.activityInputs = this.form.elements.activity;
this.ageInput = this.form.elements.age;
this.heightInput = this.form.elements.height;
this.weightInput = this.form.elements.weight;
this.calculateButton = this.form.elements["submit"];
this.resetButton = this.form.elements["reset"];
this.result = new Result(this.root);
this.handleInput = this.handleInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleReset = this.handleReset.bind(this);
}
handleInput(evt) {
const target = evt.target;
if (target.closest('[name="parameters"]')) {
target.value = formatInput(target);
}
this.calculateButton.disabled = !this.form.checkValidity();
this.resetButton.disabled = !this.parameters.some((input) => input.value);
}
handleSubmit(evt) {
evt.preventDefault();
const caloriesNorm = this.getCaloriesNorm();
const calories = {
norm: caloriesNorm,
minimal: this.getCaloriesMinimal(caloriesNorm),
maximal: this.getCaloriesMaximal(caloriesNorm),
};
this.result.show(calories);
}
handleReset() {
this.calculateButton.disabled = true;
this.resetButton.disabled = true;
this.result.hide();
}
addEventListeners() {
this.form.addEventListener("input", this.handleInput);
this.form.addEventListener("submit", this.handleSubmit);
this.form.addEventListener("reset", this.handleReset);
}
init() {
this.addEventListeners();
}
getActivityRatio() {
const activity = this.activityInputs.value;
return physicalActivityRatios.get(activity);
}
getCaloriesNorm() {
const weight = Number(this.weightInput.value);
const height = Number(this.heightInput.value);
const age = Number(this.ageInput.value);
const gender = this.genderInputs.value;
const caloriesNorm =
10 * weight +
6.25 * height -
5 * age +
caloriesFormulaConstants.get(gender);
const activityRatio = this.getActivityRatio();
return Math.round(caloriesNorm * activityRatio);
}
getCaloriesMinimal(caloriesNorm) {
return Math.round(caloriesNorm * 0.85);
}
getCaloriesMaximal(caloriesNorm) {
return Math.round(caloriesNorm * 1.15);
}
}
const formatNumber = (num) =>
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, `$1 `);
class Result {
constructor(element) {
this.counter = element;
this.root = this.counter.querySelector(".counter-result");
this.caloriesNormElem = this.root.querySelector("#calories-norm");
this.caloriesMinimalElem = this.root.querySelector("#calories-minimal");
this.caloriesMaximalElem = this.root.querySelector("#calories-maximal");
}
show(calories) {
this.caloriesNormElem.textContent = formatNumber(calories.norm);
this.caloriesMinimalElem.textContent = formatNumber(calories.minimal);
this.caloriesMaximalElem.textContent = formatNumber(calories.maximal);
this.root.classList.remove("counter-result-hidden");
}
hide() {
this.root.classList.add("counter-result-hidden");
this.caloriesNormElem.textContent = 0;
this.caloriesMinimalElem.textContent = 0;
this.caloriesMaximalElem.textContent = 0;
}
}
const LEAD_ZERO = /^0+/;
const NOT_NUMBERS = /[^\d]/g;
const formatInput = (input) =>
input.value.replace(NOT_NUMBERS, "").replace(LEAD_ZERO, "");
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Счетчик калорий</title>
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/normalize.css">
<script src="js/counter.js" defer></script>
</head>
<body class="page">
<main class="main">
<div class="container">
<article class="counter">
<h1 class="counter-title">Счётчик калорий</h1>
<form class="counter-form form" name="counter" action="#" method="post">
<div class="form-item">
<h2 class="form-title">Пол</h2>
<ul class="switcher">
<li class="switcher-item">
<input type="radio" name="gender" id="gender-male" value="male" checked required>
<label for="gender-male">Мужчина</label>
</li>
<li class="switcher-item">
<input type="radio" name="gender" id="gender-female" value="female" required>
<label for="gender-female">Женщина</label>
</li>
</ul>
</div>
<fieldset class="form-item form-parameters" name="parameters">
<legend class="visually-hidden">Физические параметры</legend>
<div class="inputs-group">
<div class="input">
<div class="input-title">
<label class="title" for="age">Возраст</label>
<span class="subtitle">лет</span>
</div>
<div class="input-value">
<input type="text" name="age" id="age" placeholder="0" inputmode="decimal" maxlength="3" required>
</div>
</div>
<div class="input">
<div class="input-title">
<label class="title" for="height">Рост</label>
<span class="subtitle">см</span>
</div>
<div class="input-value">
<input type="text" name="height" id="height" placeholder="0" inputmode="decimal" maxlength="3" required>
</div>
</div>
<div class="input">
<div class="input-title">
<label class="title" for="weight">Вес</label>
<span class="subtitle">кг</span>
</div>
<div class="input-value">
<input type="text" name="weight" id="weight" placeholder="0" inputmode="decimal" maxlength="3" required>
</div>
</div>
</div>
</fieldset>
<fieldset class="form-item">
<legend class="form-title">Физическая активность</legend>
<ul class="radios-group">
<li class="radio">
<div class="radio-button">
<input type="radio" name="activity" id="activity-minimal" value="min" checked required>
<label for="activity-minimal">Минимальная</label>
</div>
<p class="radio-description">Сидячая работа и нет физических нагрузок</p>
</li>
<li class="radio">
<div class="radio-button">
<input type="radio" name="activity" id="activity-low" value="low" required>
<label for="activity-low">Низкая</label>
</div>
<p class="radio-description">Редкие, нерегулярные тренировки, активность в быту</p>
</li>
<li class="radio">
<div class="radio-button">
<input type="radio" name="activity" id="activity-medium" value="medium" required>
<label for="activity-medium">Средняя</label>
</div>
<p class="radio-description">Тренировки 3-5 раз в неделю</p>
</li>
<li class="radio">
<div class="radio-button">
<input type="radio" name="activity" id="activity-high" value="high" required>
<label for="activity-high">Высокая</label>
</div>
<p class="radio-description">Тренировки 6-7 раз в неделю</p>
</li>
<li class="radio">
<div class="radio-button">
<input type="radio" name="activity" id="activity-maximal" value="max" required>
<label for="activity-maximal">Очень высокая</label>
</div>
<p class="radio-description">Больше 6 тренировок в неделю и физическая работа</p>
</li>
</ul>
</fieldset>
<div class="form-submit">
<button class="form-submit-button" name="submit" type="submit" disabled>
Рассчитать
</button>
<button class="form-reset-button" name="reset" type="reset" disabled>
<svg width="24" height="24" viewbox="0 0 24 24" fill="#FD3636" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4143 12.0002L18.7072 6.70725C19.0982 6.31625 19.0982 5.68425 18.7072 5.29325C18.3162 4.90225 17.6842 4.90225 17.2933 5.29325L12.0002 10.5862L6.70725 5.29325C6.31625 4.90225 5.68425 4.90225 5.29325 5.29325C4.90225 5.68425 4.90225 6.31625 5.29325 6.70725L10.5862 12.0002L5.29325 17.2933C4.90225 17.6842 4.90225 18.3162 5.29325 18.7072C5.48825 18.9022 5.74425 19.0002 6.00025 19.0002C6.25625 19.0002 6.51225 18.9022 6.70725 18.7072L12.0002 13.4143L17.2933 18.7072C17.4882 18.9022 17.7443 19.0002 18.0002 19.0002C18.2562 19.0002 18.5122 18.9022 18.7072 18.7072C19.0982 18.3162 19.0982 17.6842 18.7072 17.2933L13.4143 12.0002Z"/>
</svg>
<span>
Очистить поля и расчёт
</span>
</button>
</div>
</form>
<section class="counter-result counter-result-hidden">
<h2 class="form-title">Ваша норма калорий</h2>
<ul class="counter-result-list">
<li class="counter-result-item">
<h3><span id="calories-norm">3800</span>ккал</h3>
<p>поддержание веса</p>
</li>
<li class="counter-result-item">
<h3><span id="calories-minimal">3300</span>ккал</h3>
<p>снижение веса</p>
</li>
<li class="counter-result-item">
<h3><span id="calories-maximal">4000</span>ккал</h3>
<p>набор веса</p>
</li>
</ul>
</section>
</article>
</div>
</main>
</body>
</html>
Ответы (2 шт):
Автор решения: Алексей Шиманский
→ Ссылка
Попробуй класс объявить раньше, чем его создавать. Т.е. разместить над строкой counterElements.forEach((elem) => {