简短的回答:您需要在某些类中实现ControlValueAccessor,并将其作为具有某个指令的ngModel的NG_VALUE_ACCESSOR提供。这个ControlValueAccessor和指令实际上可以是同一个类。
TL; DR 这不是很明显,但仍不是很复杂。以下是我的一个日期控件的框架。这个东西充当角1 ng模型的解析器/格式器对。
这一切都始于ngModel将所有NG_VALUE_ACCESSOR注入其本身。还有一堆默认提供程序,它们都被注入到ngModel构造函数中,但ngModel可以区分默认值访问器和用户提供的默认值访问器。所以它选择一个与之合作。大致看起来像这样:如果有用户的价值访问者,那么它将被挑选出来,否则它会退回到默认选择。之后,完成初始设置。
控制值访问器应该订阅输入元素上的“输入”或其他类似事件以处理来自输入元素的输入事件。
当外部更改值时,ngModel在初始化期间拾取的value访问器上调用writeValue()方法。此方法负责呈现显示值,该值将作为字符串显示给用户输入到输入中。
在某些时候(通常在模糊事件上),控件可以被标记为已触摸。这也是显示的。
请注意:下面的代码不是真正的生产代码,它没有经过测试,它可能包含一些差异或不准确,但总的来说,它显示了这种方法的整体思路。
import {
Directive,
Input,
Output,
SimpleChanges,
ElementRef,
Renderer,
EventEmitter,
OnInit,
OnDestroy,
OnChanges,
forwardRef
} from '@angular/core';
import {Subscription, Observable} from 'rxjs';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
const DATE_INPUT_VALUE_ACCESSOR_PROVIDER = [
{provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DateInputDirective), multi: true}
];
@Directive({
// [date-input] is just to distinguish where exactly to place this control value accessor
selector: 'input[date-input]',
providers: [DATE_INPUT_VALUE_ACCESSOR_PROVIDER],
host: { 'blur': 'onBlur()', 'input': 'onChange($event)' }
})
export class DateInputDirective implements ControlValueAccessor, OnChanges {
@Input('date-input')
format: string;
model: TimeSpan;
private _onChange: (value: Date) => void =() => {
};
private _onTouched:() => void =() => {
};
constructor(private _renderer: Renderer,
private _elementRef: ElementRef,
// something that knows how to parse value
private _parser: DateParseTranslator,
// something that knows how to format it back into string
private _formatter: DateFormatPipe) {
}
ngOnInit() {
}
ngOnChanges(changes: SimpleChanges) {
if (changes['format']) {
this.updateText(this.model, true);
}
}
onBlur =() => {
this.updateText(this.model, false);
this.onTouched();
};
onChange = ($event: KeyboardEvent) => {
// the value of an input - don't remember exactly where it is in the event
// so this part may be incorrect, please check
let value = $event.target.value;
let date = this._parser.translate(value);
this._onChange(date);
};
onTouched =() => {
this._onTouched();
};
registerOnChange = (fn: (value: Date) => void): void => {
this._onChange = fn;
};
registerOnTouched = (fn:() => void): void => {
this._onTouched = fn;
};
writeValue = (value: Date): void => {
this.model = value;
this.updateText(value, true);
};
updateText = (date: Date, forceUpdate = false) => {
let textValue = date ? this._formatter.transform(date, this.format) : '';
if ((!date || !textValue) && !forceUpdate) {
return;
}
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', textValue);
}
}
然后在HTML模板:
<input date-input="DD/MM/YYYY" [(ngModel)]="myModel"/>
感谢。它工作的一种享受。我希望不必处理特定的输入元素('event.target.value'),以便它可以与ngModel支持的任何类型的输入兼容。也许可以通过获取现有的默认ControlValueAccessor并在提供给NgModel之前对其进行封装。基于你的代码,我提出了这个变异日期,[GIST](https://gist.github.com/christiaan-lombard/31c5e3ccbd55f9ce523d64f9bf48b5f5) – christiaan
你不能那样做。如果你看看ng2的源代码,你会发现它们做的是相同的事情 - 它们对于不同类型的输入只有一堆价值访问器。 –