addEventListener не является функцией: причины и решение

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Ошибка .addEventListener is not a function обычно указывает на то, что объект, к которому вы попытались применить метод, не является DOM-элементом либо DOM еще не был полностью загружен. Для устранения проблемы вам следует:

  • Удостовериться, что цель — корректный DOM-элемент, а не HTMLCollection или null.
  • Применить событие document.addEventListener('DOMContentLoaded', callback), чтобы гарантировать готовность всех DOM-элементов.

Вот пример кода:

JS
Скопировать код
// Дождитесь полного загрузки DOM!
document.addEventListener('DOMContentLoaded', () => {
  // Обращаться к кнопке можно только после полной загрузки страницы
  const button = document.getElementById('myButton');
  if (button) { // Проверяем наличие кнопки
    button.addEventListener('click', () => console.log('Кнопка нажата!'));
  }
});
Кинга Идем в IT: пошаговый план для смены профессии

Работа с отдельными элементами и коллекциями элементов

Необходимо отличать методы выбора элементов, такие как getElementById, возвращающий один элемент, и getElementsByClassName, возвращающий HTMLCollection. Для последнего требуется применять обработчики событий к каждому элементу коллекции по отдельности:

JS
Скопировать код
// Присваиваем обработчики отдельно каждой кнопке из коллекции
const buttons = document.getElementsByClassName('myButtons');
Array.from(buttons).forEach(button => {
  button.addEventListener('click', () => console.log('Кнопка нажата!'));
});

Если вам требуется конкретный элемент из коллекции, обратитесь к нему напрямую:

JS
Скопировать код
// Будем обрабатывать только первую кнопку из коллекции
document.getElementsByClassName('myButton')[0].addEventListener('click', showComment);

Корректная адресация элементов

При динамическом создании элементов, например, в функции showComment, убедитесь, что вы обращаетесь к правильному элементу, а новый элемент корректно вставлен в DOM:

JS
Скопировать код
function showComment() {
  // Создаём новый элемент textarea и включаем его в DOM
  let textarea = document.createElement('textarea');
  // Поместим его сразу за кнопкой
  this.parentNode.insertBefore(textarea, this.nextSibling);
}

// Каждая кнопка получает свой уникальный обработчик события
buttons.forEach(button => button.addEventListener('click', showComment));

Похожи на массивы, но не являются ими

Объекты, возвращаемые при помощи таких методов как getElementsByClassName или querySelectorAll, имеют некоторые признаки массивов, но ими не являются. Чтобы применить обработчики событий, представьте их в виде массива либо воспользуйтесь циклом for...of:

JS
Скопировать код
// Присваиваем обработчики каждой кнопке в псевдомассиве
let buttons = document.querySelectorAll('.myButton');
for (let button of buttons) {
  button.addEventListener('click', showComment);
}

Защита обработчиков событий от ошибок

Для предотвращения ошибки .addEventListener необходимо:

  • Проверить тип объекта перед использованием его в качестве обработчика события.
  • Гарантировать загрузку всех элементов при работе с динамически создаваемыми элементами.
  • Для динамически добавляемых элементов назначать обработчики событий после их создания и вставки в DOM.

Визуализация

Вы можете представить .addEventListener как нарезатель для пиццы (🍕), которым вы пытаетесь нарезать жидкий суп (🍲):

Markdown
Скопировать код
🍕 -> 🍕 = ✅ Пицца нарезана идеально (метод addEventListener применим к DOM-элементам)
🍕 -> 🍲 = ❌ Невозможно нарезать суп – эта идея абсурдна! (метод addEventListener не применим к объектам отличным от DOM)

Основной посыл: .addEventListener требует действительного DOM-объекта.

Причина ошибки: Применение метода к неподходящему объекту. Решение: Использовать .addEventListener только с DOM-элементами.

Работа с динамическим содержимым

Что касается элементов, динамически добавляемых в DOM, то нужно применять особый подход к назначению им обработчиков событий. Вот советы по этому поводу:

Верификация связывания с динамическими элементами

Убедитесь, что новым элементам, интегрированным в DOM, назначены обработчики событий:

JS
Скопировать код
// Динамически созданной кнопке назначаем обработчик
const newButton = document.createElement('button');
newButton.innerText = 'Нажми меня!';
newButton.addEventListener('click', showComment);
document.body.appendChild(newButton);

Использование делегирования событий

Поверьте обработку событий родительскому элементу – он сможет перехватывать и управлять событиями, генерируемыми вложенными элементами:

JS
Скопировать код
// Делегируем обработку нажатий кнопок родительскому элементу
document.addEventListener('click', function(event) {
  if (event.target.classList.contains('comment-button')) {
    showComment.call(event.target);
  }
});

Удаление обработчиков событий

Для оптимизации производительности или избегания утечек памяти воспользуйтесь removeEventListener, чтобы удалить неприменимые обработчики:

JS
Скопировать код
// После назначения каждому обработчику его можно убрать
button.addEventListener('click', showComment);
// Если кнопка больше не нужна, удаляем обработчик
button.removeEventListener('click', showComment);

Полезные материалы

  1. Метод EventTarget: addEventListener() – Справочник Web API | MDN
  2. Введение в события – Изучение веб-разработки | MDN
  3. Стандартные действия браузера
  4. Свойство Node: nodeType – Справочник Web API | MDN
  5. Function.prototype.bind() – JavaScript | MDN
  6. Делегирование событий
  7. javascript – В чем разница между call и apply? – Stack Overflow