#angular #typescript #controlvalueaccessor
#angular #typescript #controlvalueaccessor
Вопрос:
Я пытаюсь создать директиву только для регистра. Я создал следующий код, но у меня возникла проблема при попытке создать FormGroup.value. Директива изменяет значение визуально (с помощью _Renderer2), но FormControl по-прежнему имеет исходное значение, и при получении данных из формы с помощью FormGroup.value значения указаны в нижнем регистре. Возможно ли это исправить? Спасибо
<form [formGroup]="formGroup">
<mat-form-field>
<input placeholder="Street" formControlName="streetName" matInput uppercase>
</mat-form-field>
</form>
import { Directive, ElementRef, Optional, Renderer2, Self } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/forms';
@Directive({
selector: "textarea[uppercase], input[uppercase]",
host: {
'(input)': 'writeValue($event.target.value)',
'(blur)': 'onTouched()',
}
})
export class UppercaseDirective implements ControlValueAccessor {
onChange = (_: any) => {
console.log("onChange", _)
};
onTouched = () => {
console.log("onTouched")
};
constructor(private _renderer: Renderer2, private _elementRef: ElementRef, @Optional() @Self() public ngControl: NgControl) {
ngControl.valueAccessor = this;
}
writeValue(value: any): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'value', this.transformValue(value));
}
registerOnChange(fn: (_: any) => {}): void {
this.onChange = fn;
}
registerOnTouched(fn: () => {}): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}
private transformValue(value: string): string {
return typeof value === 'string'
? value?.toUpperCase()
: value;
}
}
Комментарии:
1. Это имеет смысл, вы меняете DOM так, что angular не распознает это. Я не уверен, как вам помочь, поскольку прошло около 9 месяцев с тех пор, как я в последний раз использовал angular, но я думаю, что вам нужно попытаться получить сам «элемент управления формой»
2. Директивы изменяют только то, что мы видим в DOM, они фактически не изменяют само значение.
Ответ №1:
Вы смешиваете понятия пользовательского элемента управления формой и директивы. Я не знаю, есть ли другой подход, но, если вы хотите создать директиву, которая преобразует один ввод, вы можете получить его, создав HTMLEvent . Некоторым нравится
@Directive({
selector: "[toUpperCase]"
})
export class ToUpperCaseDirective implements AfterViewInit {
constructor(private elementRef: ElementRef) {}
@HostListener("input", ["$event"]) onKeyDown(event: KeyboardEvent) {
this.setUpper();
}
ngAfterViewInit() {
setTimeout(() => {
this.setUpper();
});
}
setUpper() {
const target = this.elementRef.nativeElement;
let pos = target.selectionStart; //get the position of the cursor
target.value = target.value.toUpperCase();
var evt = document.createEvent("HTMLEvents");
evt.initEvent("input", false, true);
this.elementRef.nativeElement.dispatchEvent(evt);
target.selectionStart = target.selectionEnd = pos; //return the position
}
}
ПРИМЕЧАНИЕ: На самом деле я не рассматриваю директиву как хороший подход к проблеме ввода в верхнем регистре. Для меня лучше просто использовать css
<input style="text-transform:uppercase">
Затем, когда мы хотим проверить значение, преобразуйте значение, используя верхний регистр.
Комментарии:
1. Спасибо за ответ. Делать это с помощью CSS для меня бесполезно, потому что это просто визуальное изменение, когда я получаю данные из formgroup.value, они в нижнем регистре. Я проверю вашу директиву