Самописная шина из 20 строк кода может быть лучше NgRx или postboy для проекта на 15 компонентов. Но когда система разрастается до 200+ акторов — ищите решения с типизацией.
Если отбросить в сторону проблемы event-driven, то всю статью можно сократить до нескольких строк:
Ребята, у нас есть «кафка*» в браузере. Вот как она работает:
Можно использовать CustomEvent как есть, но получится «многословно» и с подсказками в IDE будет не очень, поэтому формируем реестр событий с единым API и храним их в одном месте. Api, например, такой:
interface PriceChangedEventPayload {
productId: string;
newPrice: number;
}
export class PriceChangedEvent extends CustomEvent<PriceChangedEventPayload> {
init: CustomEventInit<PriceChangedEventPayload>;
// избавляемся от бойлерплейта при создании событий
constructor(detail: PriceChangedEventPayload) {
const init = { detail }
super('onPriceChanged', init);
this.init = init;
// избавляемся от бойлерплейта при отправке событий
dispatchEvent(this);
}
}
// Добавляем подсказки для IDE и Typescript-а
declare global {
interface WindowEventMap {
onPriceChange: PriceChangedEvent;
}
}
Ну и пользуемся:
// где-то в одном месте
addEventListener('onPriceChange', (event) => {
// ...
});
// где-то в другом месте
import { PriceChangedEvent } from 'registry'
if (priceWasChanged) {
// Создание экземпляра сразу диспатчит событие
new PriceChangedEvent({ productId, newPrice });
}
Так это ведь девтулзы, там много чего можно принудительно включить/выключить, чтобы потестить какое-то поведение. Как только девтулзы закрываются, это больше не работает.
Такая инструкция говорит браузеру выбрать оформление в соответствии с оформлением на уровне ОС. Если на уровне ОС установлена темная тема, будет выбрано оформление dark, и наоборот.
С одним аргументом она ограничивает использование цветовой схемы. Если указать так:
:root {
color-scheme: light;
}
То при изменении темы на уровне ОС, ui никак реагировать не будет, а оформление всегда будет light. Пример тут https://codepen.io/s5604/pen/vEErMvL
В этом случае оформление будет зависеть от состояния чекбокса, а при изменении темы на уровне ОС, ui реагировать не будет. Пример тут https://codepen.io/s5604/pen/jEEKoLQ
Нужно еще учитывать особенность Safari, он не применит этот шрифт к некоторым элементам внутри веб-компонентов (если они используются), я обхожу это так:
Почему если в generateDataSets увеличить количество итераций до 110, то наш нейрончик будет думать что правильный ответ 157, а если до 120 то вообще выдаст NaN. От чего это зависит? Как подобрать правильное количество данных?
Кажется что плюсы интернациализации теряются, когда нам надо поставить кастомные сообщения
В каком-то смысле да. Но все познается в сравнении. Если не задать текст ошибки, будет использоваться дефолтный, он не идеален, но лучше чем ничего + интернациализация из коробки. Но для сравнения, давайте возьмем какую-то альтернативу, например что-то типа zod/yup, (они очень похоже). Я не буду воспроизводить пример выше полностью, потому что это долго, возьмем одно свойство:
Как добавить интернациализацию для такой валидации? Можно взять что-то вроде i18n, или прям завести словарик если языков нужно поддерживать два или три. То же справедливо и для решения предложенном в статье.
Преимущества встроенного API для валидации, не столько в сообщениях об ошибках, хотя и в этом оно выигрывает. Например, что будет если для схемы выше в поле емэйл мы введем "mymail@myhost.com", если согласно условию, можно вводить адреса только вида @habr.com, что нам скажет zod или yup в этом случае? Невалидный емэйл? Но он валиден, просто не на хабре а на myhost.
Constraint Validation API предлагает более гибкий способ менять текст ошибки. В статье к это демонстрируется, например – будет одна ошибка если введенный текст вообще не емэйл и другая если он не заканчивается на habr.com.
Так же немного сбивает с толку PaymentForm
PaymentForm это «стейт», можно было его сделать как угодно – хуки, редакс, зустанд и т.д. Я реализовал на удобном для меня инструменте. FormValidator служит совсем другой цели, и он может работать с любой формой и любым количеством полей.
Если бы мы использовали zod/yup, то нам точно также нужно было бы использовать какое-то состояние (стейт). В примере ниже formSchema описывает схему валидации, но нам нужно откуда-то взять объект и скормить ей, чтобы проверить валиден он или нет:
const formSchema = object({
sum: number().required().positive().integer(),
email: string().email(),
password: string().min(5).max(12),
passwordCopy: string().min(5).max(12),
});
// псевдокод
function Form() {
const [form, setForm] => useState({
sum: 0,
email: '',
password: '',
passwordCopy: '',
})
function onChange(event) {
form[event.target.name] = event.target.value;
const errors = userSchema.validate(form);
if (errors) {
// делаем что-то если есть ошибки
} else {
// делаем что-то если ошибок нет
}
}
// ...
}
Что пользователям с ограниченными возможностями будет сложно заполнить вашу форму. В ней возраст это текстовое поле в котором нужно вводить числа, а ридерами оно определяется как поле для ввода номера телефона.
Очень просто - попытка отформатировать число приведёт вас к необходимости отказа не только от нативной валидации, но даже и от нативного поля ввода числа.
И приведет к такому accessibility. Спасибо, не надо.
Я это объяснил читателям статьи: «Чтобы продемонстрировать работу с текстами ошибок, добавим простую схему...».
Покажите же нам хороший пример, а не отмахивайтесь от типичных требований к подобным контролам.
В первую очередь, это демонстрация возможностей а не полностью готовое решение. А кроме того, почему вы решили, что это «хороший пример»? А что если я на калькуляторе что-то посчитал, получил 1,25e7 и хочу это скопировать и вставить в форму? Почему вы считаете хорошим примером отобрать у меня эту возможность?
именно это я и называю кашей, когда проверки пишутся прямо в сеттере в несколько этажей if
Слабый аргумент. Особенно без рабочего примера как альтернативы.
валидация формы из 10 полей наверное будет с 3 экрана кода
Еще выше в комментариях есть пример с валидацией четырех полей, кода там меньше, чем в этом примере с валидацией двух.
Неужели нужно не просто короткий пример накидывать для понимания общей концепции, а что-то полностью готовое? Мне нужно прямо вынести код валидации в какой-то отдельныйй класс/функцию чтобы продемонстрировать вам, что дублировать этот код в каждом методе не нужно? Как-то это грустно.
Я пользуюсь не сафари а хромом. Проверил и в мозиле – та же история.
А что она забыла в конце?
Так работает input. Такое поведение ожидают все пользователи. Так вообще много чего работает, даже ячейки в экселе. Если в поле ввода есть какой-то текст, то когда мы на него переключаемся, каретка оказывается в конце и можно продолжить печатать.
Но можно поддержать и эти хоткеи, конечно
Это не хотелки, а базовое поведение инпутов с типом number, range и всех что со временем связаны.
Есть инпут – это источник данных. Когда в нем данные изменяются, он меня об этом колбэком уведомляет. В своем коде я буквально пишу – если мне данные нравятся – я их присваиваю PaymentForm по ключу paymentSum, если не нравятся – не присваиваю. Это значит что в инпуте может быть одно, а в PaymentForm другое. Правильно это или нет, вопрос другой, но я ведь сам кодом написал что хочу так. К чему у тебя претензия?
Ты вот любишь язвить, а представь что с тобой все общались также. Например, в ответ на этот твой комментарий, я бы тебе ответил не по сути, а всякую фигню. Ну типа того что в твоем решении текст выделяется только слева направо, с справа налево нет. Про то, что при фокусировки табом, каретка у тебя перескакивает в начало а не конец инпута. Что в твоем инпуте типа number при нажимании стрелок вверх и вниз меняется не значение, а скачет каретка в конец и начало. Я бы мог так сделать, но зачем? Точно также, я не понимаю зачем ты докапываешься до несущественных мелочей, прекрасно понимая, что это легко поправить. Что твой комментарий полезного принес? Что ты им хотел сказать?
Ура, может так появится нормальный интерфейс в приложении Яндекс Такси!
Если отбросить в сторону проблемы event-driven, то всю статью можно сократить до нескольких строк:
Ребята, у нас есть «кафка*» в браузере. Вот как она работает:
Можно использовать CustomEvent как есть, но получится «многословно» и с подсказками в IDE будет не очень, поэтому формируем реестр событий с единым API и храним их в одном месте. Api, например, такой:
Ну и пользуемся:
*Конечно это не кафка, но:
Формат сообщения = единственный контракт
Издатель не знает подписчиков
Брокер гарантирует доставку
Так это ведь девтулзы, там много чего можно принудительно включить/выключить, чтобы потестить какое-то поведение. Как только девтулзы закрываются, это больше не работает.
Об элементах внутри shadowDom. Я ловил в элементе label и в плейсхолдеров в инпутах.
Такая инструкция говорит браузеру выбрать оформление в соответствии с оформлением на уровне ОС. Если на уровне ОС установлена темная тема, будет выбрано оформление
dark, и наоборот.С одним аргументом она ограничивает использование цветовой схемы. Если указать так:
То при изменении темы на уровне ОС, ui никак реагировать не будет, а оформление всегда будет
light. Пример тут https://codepen.io/s5604/pen/vEErMvLКод из моего примера этим манипулирует:
В этом случае оформление будет зависеть от состояния чекбокса, а при изменении темы на уровне ОС, ui реагировать не будет. Пример тут https://codepen.io/s5604/pen/jEEKoLQ
Не так уж и заметно:
prefer-color-scheme с 30 июля 2019 г.
color-scheme c 7 апреля 2020 г.
Нужно еще учитывать особенность Safari, он не применит этот шрифт к некоторым элементам внутри веб-компонентов (если они используются), я обхожу это так:
Позволяет.
Добавляем checkbox
И еще немного CSS
Нужно также иметь ввиду, что любое переключение темы через CSS/JS всегда будет конкурировать с настройкой ОС, что не всегда хорошо.
Почему если в generateDataSets увеличить количество итераций до 110, то наш нейрончик будет думать что правильный ответ 157, а если до 120 то вообще выдаст NaN. От чего это зависит? Как подобрать правильное количество данных?
P.s. Спасибо за статью
В каком-то смысле да. Но все познается в сравнении. Если не задать текст ошибки, будет использоваться дефолтный, он не идеален, но лучше чем ничего + интернациализация из коробки. Но для сравнения, давайте возьмем какую-то альтернативу, например что-то типа zod/yup, (они очень похоже).
Я не буду воспроизводить пример выше полностью, потому что это долго, возьмем одно свойство:
Как добавить интернациализацию для такой валидации? Можно взять что-то вроде i18n, или прям завести словарик если языков нужно поддерживать два или три. То же справедливо и для решения предложенном в статье.
Преимущества встроенного API для валидации, не столько в сообщениях об ошибках, хотя и в этом оно выигрывает. Например, что будет если для схемы выше в поле емэйл мы введем "mymail@myhost.com", если согласно условию, можно вводить адреса только вида @habr.com, что нам скажет zod или yup в этом случае? Невалидный емэйл? Но он валиден, просто не на хабре а на myhost.
Constraint Validation API предлагает более гибкий способ менять текст ошибки. В статье к это демонстрируется, например – будет одна ошибка если введенный текст вообще не емэйл и другая если он не заканчивается на habr.com.
PaymentForm это «стейт», можно было его сделать как угодно – хуки, редакс, зустанд и т.д. Я реализовал на удобном для меня инструменте. FormValidator служит совсем другой цели, и он может работать с любой формой и любым количеством полей.
Если бы мы использовали zod/yup, то нам точно также нужно было бы использовать какое-то состояние (стейт). В примере ниже formSchema описывает схему валидации, но нам нужно откуда-то взять объект и скормить ей, чтобы проверить валиден он или нет:
Слишком громкое заявление конечно ))
Мой любимый пример «помощи» LLM. Так она мне тест на класс с приватными свойствами накидала ))
Что пользователям с ограниченными возможностями будет сложно заполнить вашу форму. В ней возраст это текстовое поле в котором нужно вводить числа, а ридерами оно определяется как поле для ввода номера телефона.
И приведет к такому accessibility. Спасибо, не надо.
Предлагаете всем пользоваться вашим калькулятором?
Я это объяснил читателям статьи: «Чтобы продемонстрировать работу с текстами ошибок, добавим простую схему...».
В первую очередь, это демонстрация возможностей а не полностью готовое решение. А кроме того, почему вы решили, что это «хороший пример»? А что если я на калькуляторе что-то посчитал, получил 1,25e7 и хочу это скопировать и вставить в форму? Почему вы считаете хорошим примером отобрать у меня эту возможность?
Для копии пароля в схеме не задан текст ошибки, показывается дефолтный от браузера.
Я не силен в регулярках, паттерн был \w@habr.com, поменял на *@habr.com, теперь нормально.
А если я хочу ввести 1,223,58? Опять же, можешь отрегулировать под свой вкус.
Это как-то относится к тебе валидации?
Нет, ты ввел 3e3 а это 3000. Ввел бы 333, было бы 333. А ввел бы 2e1, было бы 20.
Ну понятно...))
Пожалуйста https://habr.com/ru/articles/906534/
Слабый аргумент. Особенно без рабочего примера как альтернативы.
Еще выше в комментариях есть пример с валидацией четырех полей, кода там меньше, чем в этом примере с валидацией двух.
Неужели нужно не просто короткий пример накидывать для понимания общей концепции, а что-то полностью готовое? Мне нужно прямо вынести код валидации в какой-то отдельныйй класс/функцию чтобы продемонстрировать вам, что дублировать этот код в каждом методе не нужно? Как-то это грустно.
Я и поправил это
Я пользуюсь не сафари а хромом. Проверил и в мозиле – та же история.
Так работает input. Такое поведение ожидают все пользователи. Так вообще много чего работает, даже ячейки в экселе. Если в поле ввода есть какой-то текст, то когда мы на него переключаемся, каретка оказывается в конце и можно продолжить печатать.
Это не хотелки, а базовое поведение инпутов с типом number, range и всех что со временем связаны.
Вообще не понимаю к чему ты это.
Есть инпут – это источник данных. Когда в нем данные изменяются, он меня об этом колбэком уведомляет. В своем коде я буквально пишу – если мне данные нравятся – я их присваиваю PaymentForm по ключу paymentSum, если не нравятся – не присваиваю. Это значит что в инпуте может быть одно, а в PaymentForm другое. Правильно это или нет, вопрос другой, но я ведь сам кодом написал что хочу так. К чему у тебя претензия?
Ты вот любишь язвить, а представь что с тобой все общались также. Например, в ответ на этот твой комментарий, я бы тебе ответил не по сути, а всякую фигню. Ну типа того что в твоем решении текст выделяется только слева направо, с справа налево нет. Про то, что при фокусировки табом, каретка у тебя перескакивает в начало а не конец инпута. Что в твоем инпуте типа number при нажимании стрелок вверх и вниз меняется не значение, а скачет каретка в конец и начало. Я бы мог так сделать, но зачем? Точно также, я не понимаю зачем ты докапываешься до несущественных мелочей, прекрасно понимая, что это легко поправить. Что твой комментарий полезного принес? Что ты им хотел сказать?