簡短的回答:您需要在某些類中實現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的源代碼,你會發現它們做的是相同的事情 - 它們對於不同類型的輸入只有一堆價值訪問器。 –