[英]How To Use A Directive In A Custom Input With ControlValueAccessor Angular
我已经在我的 angular 应用程序中使用ControlValueAccessor
创建了一个简单的自定义input
组件。 因此,当我想创建表单input
元素时,不必调用<input />
,只需调用<my-input>
。
我有一个问题,当我使用<input />
,我可以使用myDirective
。 例如:
<input type="text" class="form-control" formControlName="name" myDirective />
但是,当我使用my-input
,我不能使用myDirective
。 例如:
<my-input formControlName="name" myDirective></my-input>
myDirective在我的输入中不起作用
这是my-input
组件使用ControlValueAccessor
代码:
import { Component, forwardRef } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
@Component({
selector: 'my-input',
templateUrl: './my-input.component.html',
styleUrls: ['./my-input.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MyInputComponent ),
multi: true
}
]
})
export class MyInputComponent implements ControlValueAccessor {
onChange: () => void;
onTouched: () => void;
value: string;
writeValue(value: string): void {
this.value = value ? value : '';
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
}
更新: myDirective
代码:
import { Directive, HostListener } from '@angular/core';
import { FormControlName } from '@angular/forms';
@Directive({
selector: '[myDirective]'
})
export class MyDirective{
constructor(private formControlName: FormControlName) { }
@HostListener('input', ['$event'])
onInputChange() {
this.formControlName.control.setValue(this.formControlName.value.replace(/[^0-9]/g, ''));
}
}
有没有办法在my-input
组件中使用myDirective
?
提前致谢。
你的指令有问题。 注入一个NgControl并控制这个 ngControl
export class MyDirective{
constructor(private control: NgControl) { } //<--inject NgControl
@HostListener('input', ['$event'])
onInputChange() {
this.control.control.setValue(this.control.value.replace(/[^0-9]/g, ''));
}
}
你可以在stackblitz中看到
注意:不要忘记包含在模块声明中
@NgModule({
imports: [ BrowserModule, FormsModule,ReactiveFormsModule ],
declarations: [ AppComponent, MyInputComponent,MyDirective ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
根据 Angular Directives 文档:
将类标记为 Angular 指令的装饰器。 您可以定义自己的指令来将自定义行为附加到 DOM 中的元素。
装饰器是附加到 DOM 元素的行为,因此它会影响使用该指令的元素。
但是(并且是一个很大的 BUT 是有原因的 - 检查注释),您可以使用指令查询来破解此行为。
但请记住,您必须定义特定指令,这些指令仅适用于特定查询,不能用于任何 DOM 元素。
解决方案基于以下几点:
我想定义一个指令,它适用于元素子元素,而不是元素本身。
您可以使用@ContentChildren和 QueryList 来检查您是否有一些具有特定指令的孩子。
例如,我有一个后台指令应用于输入父级和一个CustomFormControlDirective来查询子级:
import {
Directive,
ElementRef,
Input,
ContentChildren,
ViewChildren,
QueryList
} from "@angular/core";
@Directive({
selector: "[customformcontrol]"
})
export class CustomFormControlDirective {
constructor(public elementRef: ElementRef) {}
}
@Directive({
selector: "[backgroundColor]",
queries: {
contentChildren: new ContentChildren(CustomFormControlDirective),
viewChildren: new ViewChildren(CustomFormControlDirective)
}
})
export class BackgroundColorDirective {
@Input()
set backgroundColor(color: string) {
this.elementRef.nativeElement.style.backgroundColor = color;
}
@ContentChildren(CustomFormControlDirective, { descendants: true })
contentChildren: QueryList<CustomFormControlDirective>;
viewChildren: QueryList<CustomFormControlDirective>;
constructor(private elementRef: ElementRef) {}
ngAfterContentInit() {
// contentChildren is set
console.log("%o", this.contentChildren);
}
}
[...]
<div backgroundColor="red">
<input customformcontrol />
</div>
当然,该指令会将 bg 颜色应用于父 div:
那么我们如何将这个属性设置给孩子呢?
我们的contentChildren变量中有孩子:
所以我们需要将所需的背景应用到我们的子元素,我们可以遍历查询结果并尝试应用样式:
[...]
_backgroundColor = null;
@Input()
set backgroundColor(color: string) {
/// save the bg color instead of apply style
this._backgroundColor = color;
}
ngAfterContentInit() {
if (this.contentChildren.length) {
/// then loop through childrens to apply style
this.contentChildren.forEach(customFormControl => {
customFormControl.elementRef.nativeElement.style.backgroundColor = this._backgroundColor;
});
}
}
[...]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.