问题描述
我很难解决这个问题。我想创建一个可在Angular / Ionic应用程序中使用的自定义输入元素。如何将Angular属性与这些自定义元素一起使用,例如FormControlName。
<my-custom-stencil-input type="text" formControlName="firstName"></my-custom-stencil-input>
我在下面有以下代码,但是当我尝试使用FormControlName时显示错误。
import { Component,h,Prop } from '@stencil/core';
@Component({
tag: 'ba-text-input-one',styleUrl: './text-input-1.component.css',scoped: true,})
export class TextInputOne {
@Prop({reflect: true}) type: string;
@Prop({reflect: true}) placeholder: string;
@Prop({reflect: true}) formControlName: string;
render() {
return (
<div id="cmp">
<div id="icon-area">
<slot name="icon"></slot>
</div>
<input id="input-field" formControlName={this.formControlName} type={this.type} />
</div>
);
}
}
关于Stencil的文档对于如何实现此目的不是很彻底。
基本上,我想以Angular反应形式使用自己的自定义模板输入元素。
解决方法
我遇到了同样的问题,但我找到了解决方案:
首先,您不必在模板项目中创建 formControlName。
import { Component,Event,EventEmitter,h,Prop } from "@stencil/core";
@Component({
tag: 'my-custom-stencil-input',styleUrl: 'input.css',shadow: true
})
export class Input {
@Prop({reflect: true,mutable: true}) label: string;
@Prop({reflect: true,mutable: true}) value: string;
@Prop() type = 'text';
@Event() valueChanged: EventEmitter<string>;
private onInputChangeValue(event: Event) {
this.value = (event.target as HTMLInputElement).value;
this.valueChanged.emit(this.value);
}
render() {
return (
<div>
<label> {this.label} </label>
<input type= {this.type} value= {this.value} onInput= {this.onInputChangeValue.bind(this)}/>
</div>
)
}
}
然后,在 angular 项目中,您必须创建一个指令,因为您需要实现 ControlValueAccessor,它充当 Angular 表单 API 和 DOM 中的本机元素之间的桥梁。
import { Directive,forwardRef,HostBinding,HostListener } from '@angular/core';
import { ControlValueAccessor,NG_VALUE_ACCESSOR } from '@angular/forms';
@Directive({
selector: '[appAccessor]',providers: [
{
provide: NG_VALUE_ACCESSOR,useExisting: forwardRef(() => FormDirective),multi: true,},],})
export class FormDirective implements ControlValueAccessor {
@HostBinding('value') hostValue: any;
lastValue: any;
private onChange = (value: any) => {};
private onTouched = () => {};
writeValue(value: any) {
this.hostValue = this.lastValue = value == null ? '' : value;
}
registerOnChange(fn: (value: any) => void) {
this.onChange = fn;
}
registerOnTouched(fn: () => void) {
this.onTouched = fn;
}
@HostListener('valueChanged',['$event.detail'])
_handleInputEvent(value: any) {
if (JSON.stringify(value) !== JSON.stringify(this.lastValue)) {
this.lastValue = value;
this.onChange(value);
this.onTouched();
}
}
}
最后,以反应形式使用自定义元素(在本例中为输入):
<form [formGroup]="myFormGroup">
<my-custom-stencil-input label="Any label" appAccessor formControlName="control1" ></my-custom-stencil-input>
</form>
就是这样。