input
単純な要素が与えられた場合、私はこれを行うことができます:
<input [(ngModel)]="name" /> {{ name }}
これは私のカスタム要素では機能しません:
<my-selfmade-combobox [(ngModel)]="name" values="getValues()" required></my-selfmade-combobox>
どうすれば実装できますか?
input
単純な要素が与えられた場合、私はこれを行うことができます:
<input [(ngModel)]="name" /> {{ name }}
これは私のカスタム要素では機能しません:
<my-selfmade-combobox [(ngModel)]="name" values="getValues()" required></my-selfmade-combobox>
どうすれば実装できますか?
[(ngModel)]="item"
の省略形です[ngModel]="item" (ngModelChange)="item = $event"
つまり、たとえば、コンポーネントに双方向バインド プロパティを追加する場合は、
<app-my-control [(myProp)]="value"></app-my-control>
コンポーネントで行う必要があるのは、追加するだけです
@Input()
myProp: string;
// Output prop name must be Input prop name + 'Change'
// Use in your component to write an updated value back out to the parent
@Output()
myPropChange = new EventEmitter<string>();
は@Input
書き込みを処理し、新しい値を親に書き戻すには、呼び出すthis.myPropChange.emit("Awesome")
だけです (値が変更されるたびに更新されるようにしたい場合は、プロパティのセッターに発行を配置できます)。
ここで、どのように/なぜ機能するかについてのより詳細な説明を読むことができます。
名前を使用したい場合ngModel
( で要素にバインドする追加のディレクティブがあるためngModel
)、またはこれがFormControl
コンポーネントではなく要素用である場合 (別名、 で使用するためngForm
)、 で遊ぶ必要がありますControlValueAccessor
。独自のものを作成するための詳細な説明FormControl
と、それが機能する理由については、こちらを参照してください。
あなたが本当に必要な場合(アプローチとは異なり、[(ngModel)]
サポートしています)、このリンクがあなたの質問に答えると思います:ngForm
[(myProp)]
これを実現するには、次の 2 つのことを実装する必要があります。
ControlValueAccessor
の間のブリッジを実装するカスタムngModel
ngControl
前のリンクは完全なサンプルを提供します...
共有コンポーネントに入力用に 1 回実装したngModel
ので、それを非常に簡単に拡張できます。
わずか 2 行のコード:
providers: [createCustomInputControlValueAccessor(MyInputComponent)]
extends InputComponent
import { Component, Input } from '@angular/core';
import { InputComponent, createCustomInputControlValueAccessor } from '../../../shared/components/input.component';
@Component({
selector: 'my-input',
templateUrl: './my-input-component.component.html',
styleUrls: ['./my-input-component.scss'],
providers: [createCustomInputControlValueAccessor(MyInputComponent)]
})
export class MyInputComponent extends InputComponent {
@Input() model: string;
}
<div class="my-input">
<input [(ngModel)]="model">
</div>
import { Component, forwardRef, ViewChild, ElementRef, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
export function createCustomInputControlValueAccessor(extendedInputComponent: any) {
return {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => extendedInputComponent),
multi: true
};
}
@Component({
template: ''
})
export class InputComponent implements ControlValueAccessor, OnInit {
@ViewChild('input') inputRef: ElementRef;
// The internal data model
public innerValue: any = '';
// Placeholders for the callbacks which are later provided
// by the Control Value Accessor
private onChangeCallback: any;
// implements ControlValueAccessor interface
writeValue(value: any) {
if (value !== this.innerValue) {
this.innerValue = value;
}
}
// implements ControlValueAccessor interface
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
// implements ControlValueAccessor interface - not used, used for touch input
registerOnTouched() { }
// change events from the textarea
private onChange() {
const input = <HTMLInputElement>this.inputRef.nativeElement;
// get value from text area
const newValue = input.value;
// update the form
this.onChangeCallback(newValue);
}
ngOnInit() {
const inputElement = <HTMLInputElement>this.inputRef.nativeElement;
inputElement.onchange = () => this.onChange();
inputElement.onkeyup = () => this.onChange();
}
}
ステップ 1:providers
以下のプロパティを追加します。
@Component({
selector: 'my-cool-element',
templateUrl: './MyCool.component.html',
styleUrls: ['./MyCool.component.css'],
providers: [{ // <================================================ ADD THIS
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MyCoolComponent),
multi: true
}]
})
ステップ 2:実装ControlValueAccessor
:
export class MyCoolComponent implements ControlValueAccessor {
private _value: string;
// Whatever name for this (myValue) you choose here, use it in the .html file.
public get myValue(): string { return this._value }
public set myValue(v: string) {
if (v !== this._value) {
this._value = v;
this.onChange(v);
}
}
constructor() {}
onChange = (_) => { };
onTouched = () => { };
writeValue(value: any): void {
this.myValue = value;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
throw new Error("Method not implemented.");
}
}
ステップ 3: html で、必要なコントロールをバインドしますmyValue
。
<my-cool-element [(value)]="myValue">
<!-- ..... -->
</my-cool-element>