[英]How To Use A Directive In A Custom Input With ControlValueAccessor Angular
I've been create a simple custom input
component in my angular app use ControlValueAccessor
.我已经在我的 angular 应用程序中使用
ControlValueAccessor
创建了一个简单的自定义input
组件。 So, when I want to create a form input
element, I don't have to call <input />
, only call <my-input>
.因此,当我想创建表单
input
元素时,不必调用<input />
,只需调用<my-input>
。
I have a problem, when I use <input />
, I can use myDirective
.我有一个问题,当我使用
<input />
,我可以使用myDirective
。 For example:例如:
<input type="text" class="form-control" formControlName="name" myDirective />
But, when I use my-input
, then I can't use myDirective
.但是,当我使用
my-input
,我不能使用myDirective
。 For example:例如:
<my-input formControlName="name" myDirective></my-input>
myDirective dosn't work in my-input
myDirective在我的输入中不起作用
This is my-input
component use ControlValueAccessor
code:这是
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;
}
}
Updated: myDirective
code:更新:
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, ''));
}
}
Is there a way for myDirective
to be used in the my-input
component?有没有办法在
my-input
组件中使用myDirective
?
Thanks in advance.提前致谢。
There're a problem with your directive.你的指令有问题。 Inject a NgControl and control this ngControl
注入一个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, ''));
}
}
You can see in stackblitz你可以在stackblitz中看到
NOTE: Don't forget include in the module declarations注意:不要忘记包含在模块声明中
@NgModule({
imports: [ BrowserModule, FormsModule,ReactiveFormsModule ],
declarations: [ AppComponent, MyInputComponent,MyDirective ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
According to the Angular Directives documentation:根据 Angular Directives 文档:
Decorator that marks a class as an Angular directive.
将类标记为 Angular 指令的装饰器。 You can define your own directives to attach custom behaviour to elements in the DOM.
您可以定义自己的指令来将自定义行为附加到 DOM 中的元素。
a decorator is a behaviour attached to an element to the DOM, so it will affect the element wich use the directive.装饰器是附加到 DOM 元素的行为,因此它会影响使用该指令的元素。
BUT (and is a big BUT for a reason - check notes), you can hack this behaviour using directive queries.但是(并且是一个很大的 BUT 是有原因的 - 检查注释),您可以使用指令查询来破解此行为。
BUT remember you must define specific directives which will work only with specific queries and cannot be used for any DOM element.但请记住,您必须定义特定指令,这些指令仅适用于特定查询,不能用于任何 DOM 元素。
The solution is based on the following:解决方案基于以下几点:
I want to define a directive which works on an element children, and not on the element itself.
我想定义一个指令,它适用于元素子元素,而不是元素本身。
You can use @ContentChildren and QueryList to check if you have some children with a specific directive.您可以使用@ContentChildren和 QueryList 来检查您是否有一些具有特定指令的孩子。
For example, I have a background directive applied to input parent and a CustomFormControlDirective to query the children:例如,我有一个后台指令应用于输入父级和一个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>
Of course this directive will apply the bg color to the parent div:当然,该指令会将 bg 颜色应用于父 div:
So how can we set this property to the children?那么我们如何将这个属性设置给孩子呢?
We have the children inside our contentChildren variable:我们的contentChildren变量中有孩子:
So we need to apply the desired background to our children element, we can loop trough the query results and try to apply the style:所以我们需要将所需的背景应用到我们的子元素,我们可以遍历查询结果并尝试应用样式:
[...]
_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;
});
}
}
[...]
And it will apply the style to childrens:它会将样式应用于儿童:
also if there are more than 1 children:如果有超过 1 个孩子:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.