如何在Stencil中创建自定义输入元素以与Angular / Ionic一起使用?

问题描述

我很难解决这个问题。我想创建一个可在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>

就是这样。