if (inputs[el].value == "") el++;
if (inputs[el].value.match(/[А-я]/)) {
Давайте представим, что пустое значение имеет последний элемент. Делаете свой
++, а затем пытаетесь элемент обработать - следующий, которого НЕТ. А раз его нет, значит он
undefined, а у
undefined никакого
value быть не может, как и любых других свойств. Если не хотите обрабатывать пустой элемент - выполняйте
прерывание текущей итерации цикла вместо вот этих вот стрёмных манипуляций со счётчиком (кстати, а какого чёрта
el? - весьма странное имя для счётчика цикла, он же представляет не сам элемент, а его индекс в коллекции).
Это если говорить про заявленную в вопросе проблему в виде "cannot read property". Но кроме неё присутствует и ряд других косяков (сильно к коду не приглядывался, так что возможно есть ещё, помимо нижеперечисленного), не столь очевидных, но также способных стать причиной неправильной работы формы:
А вообще, есть мнение, что стоит придать этой валидации чуть более пристойный вид. Сделаем объект, содержащий функции для проверки значений, ключами будут имена полей:
const validators = {
date: val => /^\d{4}$/.test(val),
course: val => /^[1-6]$/.test(val),
__default: val => /[а-яё]/i.test(val),
};
При переборе элементов достаём функцию, передаём ей значение элемента. Ну и всё - больше не надо никаких магических чисел, цепочки из условных операторов, дублирования кода добавления класса:
const formValidator = el =>
inputs.length === Array.prototype.reduce.call(
inputs,
(acc, n) => {
const isValid = (validators[n.name] || validators.__default)(n.value);
(!el || el === n) && n.classList.toggle('invalid-input', !isValid);
return acc + isValid;
},
0
);
Обратите внимание на то, что у
formValidator появился параметр - элемент, который был подвергнут редактированию. Если указан, то только у него будет переключаться класс. Т.е., теперь можно пустое значение рассматривать как некорректное, но пока пользователь элемент не трогал, не подсвечивать его (подозреваю, что именно этого поведения вы стремились добиться в попытке не обрабатывать пустые элементы). Откуда брать элемент, который пользователь редактировал? - да из объекта события:
document.querySelector('.form').addEventListener('input', e => {
btnSubmit.disabled = !formValidator(e.target);
});