Комментарии 11
Ничего непонятно, но очень интересно!
Можете написать статью в чём схожесть и отличие TUI от Ionic Framework?
Спасибо за комментарий.
Постараюсь в следующих публикациях понятней расписывать материал.
Вы можете ознакомится с демо на stackblitz
Если кратко то мы делаем удобней работу с внешней библиотекой компонентов
Спасибо за статью. Вопрос: как вы решили вопрос с валидаторами (и disabled стейтом) в обертках, в частности, если подразумевается, что они должны поддерживать и template (ngModel) и reactive (FormControl) формы? Каким образом планируете "поймать" их внутри обертки вне зависимости от типа формы? Как подразумевается выводить соответсвующий валидатору текст ошибки? Спасибо
P.S. Подход, полагаю, скорее про уменьшение бойлерплейта, чем уменьшение зависимости от внешней библиотеки. В коде обертки типы инпутов и в целом логика работы завязаны на taiga, то есть невозможно будет заменить taiga на что-то другое без переписывания обертки.
Спасибо за объёмный вопрос
В случае замены или обновления внешней ui-библиотеки, мы будем переписывать только модуль с обертками.
Для расширения функциональности оберток можем просто написать нужные директивы которые будут дизейблить поля, а можно и написать директивы которые в себе содержат все тайговые директивы - аля варианты
Ну и можно применить подход описанный тут -> Концепция директив-контроллеров для компонента в Angular (часть 1, часть 2)
Пользовательские сообщения валидации мы можем провайдить на уровне обертки (используя тайговский токен - TUI_VALIDATION_ERRORS).
У нас это просто директива которая на вход принимает словарь ошибок валидации и пробрасывает их в токен
Но в основном мы пользуемся реактивным подходом при работе с формами
Тогда, возможно, на уровне соглашения стоит использовать эту обертку только для реактивных форм. Не сочтите на придирки, но код ngOnInit метода в базовом классе кажется можно оптимизировать. Первой строкой идет early return в случае отсутствия ngContol директивы, то есть строка "this.control = new FormControl();" не достижима. В целом код по смыслу можно свести к
if (!this.ngControl) throw new Error('ngControl is undefined');
this.control = this.ngControl.control;
if (this.ngControl instanceof NgModel) { this.doSmthForNgModel(); }
И вот вопрос, что лучше сделать внутри "doSmthForNgModel": эксепшн что ngModel не поддерживается или попытаться его поддержать. В вашем текущем варианте кажется будет лишнее срабатывание ngModelChange когда значение ngModel меняется "снаружи", чтобы этого избежать надо проверять приватную переменную _pendingChange, чтобы "viewToModelUpdate" срабатывал только при изменении "изнутри" (из контрола taiga). Еще вопрос с корректностью работы updateOn фичи из ngModelOptions.
P.S. Делаем подобную обертку, но над Angular Material. Статья очень своевременно возникла, подтвердила, что не одни мы мыслим в эту сторону, концепт у нас аналогичный. Для себя склоняемся к варианту отказаться от поддержки ngModel.
Принял к сведенью (возможность сократить код в ngOnInit) - в выходные проверю
Пока нареканий в работе не было (про двойные вызовы метода ngModelChange) - в выходные проверю
Так как имеется возможность миграции других проектов в моно-репозиторий а в них может быть смешанная реализация форм решили оставить поддержку шаблонных форм и будем дорабатывать по мере необходимости
По мере улучшения концепта у нас в проекте буду актуализировать репозиторий на github
а чем вас ngModel смутил, из этой директивы всегда можно вытащить ту же реактивную форму, просто она неявно создается
да, задумка на первый взгляд классная - что бы ты не использовал, под капотом это будет FormControl и в целом унифицированное поведение, потому что все form control директивы экстендят NgControl. Но если вдаваться в детали, возникают нюансы. Как минимум в случае formControl/formControlName "внутри" будет использоваться тот же FormControl, что используется пользователем (назовем так разработчиков, использующих обертку) "снаружи". В этом случае отлично работает идея предложенной обертки, мы просто "перепрокидываем" FormControl ниже. Но в случае NgModel FormControl создается внутри директивы, пользователь с ним не работает, с ним работает сама NgModel. Из-за этого приходится делать, например, то, что можно найти в коде обертки в статье - подписываться на изменения FormControl, чтобы выкинуть событие ngModelChange, но это не совсем корректно, потому что этот FormControl используется в NgModel при изменениях в обоих направлениях (model -> view и view -> model), то есть когда пользователь будет выставлять значение ngModel (например просто при открытии формы) эта подписка в коде обертки будет выкидывать ngModelChange, что не является ожидаемым поведением и может иметь неочевидные сайд эффекты. Чтобы блокировать лишнее событие надо смотреть в приватные флаги NgModel, что выглядит немного костыльно. Также есть некоторые нюансы с валидаторами. И если к этому прибавить то, что мы в своем проекте тоже преимущественно используем реактивные формы, то между вариантами "ради 5% форм поддерживать костылями работу NgModel в обертке" и вариантом "переписать 5% форм и договориться вообще не использоваться NgModel" выбрали второй.
Вы не могли бы рассказать как именно можно обойти двойное обновление с помощью приватного флага? pending флаг всегда false.
что касается первого инициализирующего обновления то его можно отменить.
ngModel: NgModel | null = inject(NgModel, { optional: true });
this.formControl.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
if(this.ngModel?.model !== value){
this.ngModel?.viewToModelUpdate(value);
}
}
или пайпа pairwise()
stackblitz вместо тысячи слов https://stackblitz.com/edit/stackblitz-starters-zc4rek?file=src%2Fmain.ts
Тут 3 поля:
A - с оберткой из статьи
B - обертка из статьи с патчем
N - нативный инпут
Поле A кидает лишнее событие change при инициализации и если значение меняется "снаружи" (кнопка Set value), поля B и N ведут себя одинаково.
Плохо в патче то, что поле _pendingChange приватное...
начал глубже разбираться с работой форм
вот статья по теме может будет полезной/интересной
Работа с формами в Angular — модуль работы с формами и обертки полей