【问题标题】:How can I create a custom input element in Stencil to work with Angular/Ionic?如何在 Stencil 中创建自定义输入元素以使用 Angular/Ionic?
【发布时间】:2020-09-15 20:55:24
【问题描述】:

想弄清楚这一点,我头疼不已。我想创建一个可以在 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 反应形式使用我自己的自定义 Stencil 输入元素。

【问题讨论】:

  • 在您的示例中,您实际上是将formControlName 添加到input 元素,而不是my-custom-stencil-input。另外,您是否生成了Angular bindings
  • 如何生成 Angular 绑定? ValueAccessorConfigs 没有很好地解释。

标签: angular ionic-framework angular-reactive-forms stenciljs


【解决方案1】:

我遇到了同样的问题,但我找到了解决方案:

首先,您不必在模板项目中创建 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>

就是这样。

【讨论】:

    猜你喜欢
    • 2019-09-23
    • 2019-03-23
    • 1970-01-01
    • 2020-11-13
    • 1970-01-01
    • 1970-01-01
    • 2020-11-28
    • 2021-09-05
    • 1970-01-01
    相关资源
    最近更新 更多