Создание custom form field control (ControlValueAccessor)
- ControlValueAccessor - связующее звено между Angular forms API и нативным DOM элементом
- Чтобы Angular знал об новом field control необходимо зарегистрировать
NG_VALUE_ACCESSORпровайдер.
Интерфейс ControlValueAccessor
В компоненте должны реализовываться 3 обязательных метода и 1 один необязательный:
export interface ControlValueAccessor {
/**
* Записать значение в компонент (из ts в html), основная функция
*/
writeValue(obj: any): void;
/**
* Обработать значение из компонента (из html в ts), основная функция fn
*/
registerOnChange(fn: any): void;
/**
* Обработать, когда потрогали поле (потеря фокуса)
*/
registerOnTouched(fn: any): void;
/**
* Обработка недоступности
*/
setDisabledState?(isDisabled: boolean): void;
}
Регистрация NG_VALUE_ACCESSOR провайдера
Используется мультипровайдер с токеном NG_VALUE_ACCESSOR.
const NG_VALUE_ACCESSOR: InjectionToken<ControlValueAccessor>;
Функция forwardRef необходима потому, что в провайдере идёт обращение к классу, который еще не определен (объявлен ниже). Иначе ошибка (ERROR in : Cannot instantiate cyclic dependency! NgControl)
import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
...
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TyapkComponent),
multi: true
}]
}) export class TyapkComponent implements ControlValueAccessor {}
Custom control
Миниальный
import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-quantity-input',
template: `
<button
(click)="updateValue(+value - 10)"
[disabled]="disabled">--</button>
<button
(click)="updateValue(+value - 1)"
[disabled]="disabled">-</button>
<input
[ngModel]="value"
(ngModelChange)="updateValue($event)"
[disabled]="disabled"
type="number"
/>
<button
(click)="updateValue(+value + 1)"
[disabled]="disabled">+</button>
<button
(click)="updateValue(+value + 10)"
[disabled]="disabled">++</button>
`,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => QuantityInputComponent),
multi: true,
}],
})
export class QuantityInputComponent implements ControlValueAccessor {
value = 0;
disabled = false;
private onChange = (value: any) => {};
private onTouched = () => {};
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: () => {}): void {
this.onTouched = fn;
}
writeValue(outsideValue: number) {
// получить из Forms API
this.value = outsideValue;
}
setDisabledState(isDisabled: boolean) {
this.disabled = isDisabled;
}
updateValue(insideValue: number) {
this.value = insideValue; // html
this.onChange(insideValue); // уведомить Forms API
this.onTouched();
}
}
Супер простой компонент переключателя
@Component({
selector: 'toggle',
template: `{{ value }}`,
styles: [`
:host {
display: block;
height: 20px;
width: 285px;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 4px;
padding: 5px;
text-align: center;
}
:host(.disabled) {
opacity: 0.35;
pointer-events: none;
}
`],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ToggleComponent),
multi: true
}]
})
export class ToggleComponent implements ControlValueAccessor {
value: boolean;
disabled: boolean;
onChange = (value: boolean) => {};
onTouched = () => {};
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
@HostBinding('class.disabled')
get isDisabled() {
return this.disabled;
}
@HostListener('click')
click() {
this.writeValue(!this.value);
}
writeValue(value: boolean) {
this.value = value;
this.onChange(this.value);
}
setDisabledState(disabled: boolean) {
this.disabled = disabled;
}
}
Материал был взят с сайта: tyapk.ru
Помощь сайту
ЮMoney:
4100 1180 7209 833
Карта Сбербанк:
2202 2080 6183 7127
Лучшая практика проектирования больших Angular-приложений
Интеграция Keycloak - Angular: Практическое руководство по подключению приложения к системе управления идентификацией и доступом (IAM)
Расширенные операторы RxJs, которые вы знаете, но недостаточно хорошо
Angular Signals — использование функции untracked() для предотвращения отслеживания зависимостей
Установка Playwright в сочетании с TypeScript для приложений Angular
Angular Routing в Angular 17
Обнаружение локальных изменений в Angular 17
Появление нового функционала в Angular 16 и Angular 17
15 Angular директив на каждый день
Улучшение читаемости кода в проектах Angular: мастерство работы с Enum и лучшие практики
Изменяют ли автономные компоненты способ написания кода в Angular?
Angular Signals
От хорошего к великому: параметры входных данных, inputs в Angular
Angular Interceptor - перехватчик ошибок http
10 лучших UI библиотек для Angular
Инструкция по деплою Angular приложения на Github Pages
Что ждет нас в Angular 15?
Angular Swiper Image Touch Slider
Angular Interceptors - рабочий пример
Динамическое добавление элемента script в Angular
Создание custom form field control (ControlValueAccessor)
Angular тестирование component с помощью Jest
Route Resolving
Шпаргалка по Angular
Директивы ng-template, ngTemplateOutlet и ng-container
Маршрутизация Angular подробное руководство
Angular & Rxjs: Отписываться или не отписываться?
Кастомные элементы форм в Angular
Формы. Реактивный подход.
Формы. Шаблонный подход.
Формы в Angular
Subject
Observable. Subscribe и Unsubscribe
Route. Обновление шаблона
Route Resolving
Route передача статичных данных
Route. Контроль навигации с помощью сервиса
Route. Защита роутера
Route. Вынос настроек роутера
Route. Переключения и параметры
JavaScript операторы
Сервисы
Структурные директивы
Binding свойств директив
HostListener и HostBinding
Директива атрибута
Навигация. Передача данных событиями
События и жизненный цикл
ng-content
Инкапсуляция стилей и ссылки
Связывание свойств и событий
Компонент и модель
Директива ngFor
Angular CSS и Style
Динамические шаблоны в Angular
События
Компонент и данные
Шаблон и стили компонента
Создание компонентов в Angular
TypeScript, Bootstrap, Main.ts
Установка и первый запуск Angular
Руководство по Angular
Возможно, вам будет интересно
Динамические шаблоны в Angular
В данном руководстве рассмотрим двухстороннее связывание данных. Создание динамических шаблонов, меняющих свое состояние в зависимости от действий пользователя, с помощью двухстороннего связывания данных и директивы ngIf.
Angular Signals — использование функции untracked() для предотвращения отслеживания зависимостей
Для каждого изменения сигнала computed и effect функций, которые интересуются сигналом, будут пересчитаны и выполнены соответственно. Бывают случаи, когда мы не хотим, чтобы это перерасчет происходило для изменения сигнала.
Что ждет нас в Angular 15?
В Angular 15 запланировано обновление платформы TypeScript, стабилизация API-интерфейсов автономных компонентов, упрощение создания приложения и предложит новый способ составления логики пользовательского интерфейса.
Angular Routing в Angular 17
Angular Routing представляет собой важную функцию, которая дает возможность разработчикам создавать динамичные и гибкие SPA веб-приложения. Позволяя пользователям без проблем переходить между компонентами, она обеспечивает плавное взаимодействие. В данной статье мы рассмотрим основные принципы маршрутизации в Angular и методы эффективного использования её возможностей.