Эта статья — перевод оригинальной статьи Ollie Williams "What’s New With Forms in 2022?"
Также я веду телеграм канал “Frontend по-флотски”, где рассказываю про интересные вещи из мира разработки интерфейсов.
Вступление
Браузеры постоянно добавляют новые функции HTML, JavaScript и CSS. Вот несколько полезных дополнений к работе с формами, которые вы могли пропустить…
requestSubmit()
Safari 16 станет последним браузером, в котором будет добавлена поддержка requestSubmit.
Прежде чем мы рассмотрим, как работает .requestSubmit(), давайте напомним себе, как программная отправка формы с помощью JavaScript работает при использовании метода .submit(). Отправка формы с помощью submit() не вызывает событие submit. Таким образом, в следующем коде форма отправляется, функция preventDefault() не запускается, и в консоль ничего не записывается:
const form = document.forms[0];
form.addEventListener('submit', function(event) {
// code to submit the form goes here
event.preventDefault();
console.log('form submitted!');
});
document.querySelector('.btn').addEventListener('click', function() {
form.submit();
})
.submit() также будет игнорировать любую валидацию HTML формы. Учитывая следующую разметку, форма будет отправлена, когда инпут пуст, даже если инпут имеет атрибут required:
<form>
<label for="name">Name</label>
<input required name="name" id="name" type="text">
</form>
.requestSubmit() — это альтернативный способ отправки формы с использованием JavaScript, но, в отличие от .submit(), валидация HTML-формы предотвратит отправку формы. Если все данные, введенные в форму, проходят проверку, будет запущено событие submit, что означает «form submitted!» будет выведено в консоль в следующем примере:
form.addEventListener('submit', function(event) {
event.preventDefault();
console.log('form submitted!');
});
document.querySelector('.btn').addEventListener('click', function() {
form.requestSubmit();
})
Вы можете добиться того же самого эффекта, щелкнув на кнопку отправки формы, но requestSubmit, возможно, является более элегантным решением.
Свойство submitter события submit
Свойство SubmitEvent.submitter получило полную кросс-браузерную поддержку с выпуском Safari 15.4. Это свойство только для чтения указывает элемент <button> или <input type="submit">, который вызвал отправку формы.
<form>
<button name="foo" value="bar" type="submit">Bar</button>
<button name="foo" value="baz" type="submit">Baz</button>
</form>
Если у вас есть несколько кнопок отправки или входных данных, каждая из которых имеет свое значение, на сервер будет отправлено только значение кнопки или ввода, которое было нажато для отправки формы, а не оба значения. Ничего нового. Новым является то, что прослушиватель событий для события отправки теперь имеет доступ к свойству event.submitter. Вы можете использовать это, чтобы добавить класс к кнопке или вводу, который инициировал отправку формы, например, или чтобы получить его значение или любой другой из его HTML-атрибутов.
document.forms[0].addEventListener('submit', function(event) {
event.preventDefault();
console.log(event.submitter.value);
console.log(event.submitter.formaction);
event.submitter.classList.add('spinner-animation');
})
Событие formdata
В этом нет ничего нового, но кросс-браузерная поддержка была достигнута только с выпуском Safari 15. Основной вариант использования события formdata — позволить кастомным элементам участвовать в отправке форм. Однако за пределами веб-компонентов он все еще может быть полезен.
Вы добавляете прослушиватель событий formdata в форму, с которой хотите взаимодействовать:
document.querySelector('form').addEventListener('formdata', handleFormdata);
Событие запускается как обычной отправкой HTML-формы, так и появлением new FormData().event.formData содержит все отправляемые данные.
function handleFormdata(event) {
for (const entry of event.formData.values()) {
console.log(entry);
}
}
Коллбэк для прослушивания событий formdata запускается перед отправкой данных на сервер, что дает вам возможность добавить или изменить отправляемые данные.
function handleFormdata(event) {
event.formData.append('name', 'John');
}
Вы могли бы изменить или добавить FormData внутри обработчика события отправки, но formdata позволяет вам отделить логику. Это также альтернатива использованию скрытых входных данных в разметке вашей формы в тех случаях, когда вы отправляете форму «по старинке», то есть полагаетесь на встроенную функциональность HTML для отправки формы, а не на собственную.
showPicker() для input элемента
showPicker() поддерживается начиная с Chrome 99, Firefox 101 и в готовящейся к выпуску Safari 16. Для input элемента, атрибутом type которого является Date, Month, Week, Time, datetime-local, color или file, showPicker() предоставляет программный способ отображения пользовательского интерфейса выбора. Для ввода цвета и файла всегда можно было программно отобразить средство выбора, вызвав .click на инпуте:
document.querySelector('input[type="color"]').click();
Этот подход не работает для ввода даты, поэтому был добавлен этот новый API. .showPicker() также будет работать с входными данными цвета и файла, но нет никакого реального преимущества в его использовании по сравнению с .click().
Inert атрибут
Всегда можно было заблокировать несколько инпутов одновременно, заключив их в fieldset с атрибутом disabled:
<form action="">
<fieldset disabled>
<label for="email">email</label>
<input name="email" id="email" type="email">
<label for="age">age</label>
<input name="age" id="age" type="number">
<button>Submit</button>
</fieldset>
</form>
Inert — это новый атрибут HTML. Он работает не только с формами, но формы, безусловно, являются ключевым вариантом использования. В отличие от атрибута disabled, inert можно применить к самому элементу формы. Все в форме будет недоступно для фокусировки и кликов. Когда дело доходит до вспомогательных технологий, inert аналогичен установке aria-hidden="true". В отличие от атрибута disabled, inert по умолчанию не применяет никаких стилей, но их легко добавить самостоятельно:
form[inert] {
opacity: .2;
}
<form inert action="">
<label for="email">email</label>
<input name="email" id="email" type="email">
<label for="age">age</label>
<input name="age" id="age" type="number">
<button>Submit</button>
</form>
Это еще не все…
Большой проблемой является стилизация элементов <select>, о которой разработчики мечтали десятилетиями. Похоже, скоро это станет реальностью с введением selectmenu.
Но это пока! Недавние обновления обеспечивают полную поддержку браузерами функций, которых мы так долго ждали, что делает их наиболее подходящими для использования в продакшене.
TAZAQ
Большой проблемой является стилизация элементов <select>
Да как бы нет, уже все понаписали кастомные селекты и нормально живут
Aleksandr-JS-Developer
Ага, кроме меня. Особенно круто когда "макет уже согласован, пили как хочешь". — Но это же нарушение нашего style guide, — кричу я, яростно водя мышкой над грёбанным селектом. — У нас такого нет, я пол дня потрачу на эту штуковину! Но тщетно кричу: никто меня не слышит, кроме уже натренированных соседей. Ну псих орёт иногда по утрам, что с него взять? А дизайнер по сторону Figma, наблюдая на моим курсором, тихо, как бы в пустоту, прошепчет: — Я и не думал, что ему настолько понравится...
nin-jin
Нативные селекты лучше вообще не использовать, чтобы ваше приложение не встало колом, когда в табличке потребуется нарисовать десяток-другой селектов с сотней другой опшенов, что потребует тысячу-другую невидимых дом-элементов.
danilovmy
Даже мысль о подобном юзабилити говорит о небольшом опыте разработки. Я серьезно. Это же не панель самолёта. Хотя и в этом случае можно много что упростить. Но гнев контент менеджера заполняющего подобные таблицеформы велик. И боль его непередаваема.
nin-jin
И что же не так с этим юзабилити?
fransua
А добавлять список option по ховеру/клику/фокусу оставляет желать лучшего? Как будто там можно хоть бесконечный скролл замутить.
У обычного селекта есть преимущество - открывается в нужную сторону в зависимости от положения на экране, а не в окне.
nin-jin
Успехов вам с асинхронной загрузкой вариантов по тапу, поиску нужного пункта по подстроке, отображению чего-либо помимо строки текста и тд, и тп.
fransua
Понятно что это не вундервафля и оч урезанный по возможностям контрол.
Но изначальная проблема с тысячами невидимых option решаема, или Вы не знаете?
nin-jin
Это первый шаг по костылям. Потом надо отслеживать закрытие селекта, чтобы эти тысячи опшенов удалять. Потом учесть, что опшен для текущего значения должен рендериться сразу и не удаляться. Когда вы решите все эти проблемы, у вас получится кастомный контрол, который зачем-то использует внутри нативный, и как следствие наследует от него все остальные 100500 его недостатков.
TAZAQ
А что там забыл нативный селект? Обычно в такие вещи вставляют инпут, но и то только для поиска или для отправки данных через сабмит