Angular 学习笔记 (Custom Accessor + Mat FormField + Custom select)
custom form control 之前就写过了,这里简单写一下.
创建一个组件实现 ControlValueAccessor 接口
@Component({
providers: [
{ provide: NG_VALUE_ACCESSOR, multi: true, useExisting: MyInputComponent },
],
})
export class MyInputComponent implements ControlValueAccessor {}
实现 writeValue, model -> view 的时候被调用的,这里实现如何更新 view. 如果时 OnPush 记得要 markForCheck
writeValue(value: any): void {
console.log('writeValue');
this.cdr.markForCheck();
this.value = value;
}
实现 registerOnChange 方法. view -> model 内部通过调用这个方法向外输出值
private onChangeFn: (value: any) => void;
registerOnChange(fn: MyInputComponent['onChangeFn']): void {
this.onChangeFn = fn;
}
实现 registerOnTouched 方法, view -> model, 当内部 touched 了通知外部
private onTouchedFn: () => void;
registerOnTouched(fn: MyInputComponent['onTouchedFn']): void {
console.log('registerOnTouched');
this.onTouchedFn = fn;
}
实现 setDisabledState 方法, model -> view, 当外部设定 disabled 后, 内部更新 view
setDisabledState(isDisabled: boolean): void {
console.log('setDisabledState');
this.cdr.markForCheck();
this.disabled = isDisabled;
}
执行的顺序是 ngOnInit-> DoCheck -> writeValue-> registerOnChange -> registerOnTouched -> setDisabledState -> ngAfterContentInit ...
实现好了 customer accessor 现在我们来把它放进 mat form filed 里
refer https://material.angular.io/guide/creating-a-custom-form-field-control
要做到这一点, 组件必须实现 MatFormFieldControl 里面有 14 个接口要实现的.
@Directive()
export abstract class MatFormFieldControl<T> {
value: T | null;
readonly stateChanges: Observable<void>;
readonly id: string;
readonly placeholder: string;
readonly ngControl: NgControl | null;
readonly focused: boolean;
readonly empty: boolean;
readonly shouldLabelFloat: boolean;
readonly required: boolean;
readonly disabled: boolean;
readonly errorState: boolean;
readonly controlType?: string;
readonly autofilled?: boolean;
abstract setDescribedByIds(ids: string[]): void;
abstract onContainerClick(event: MouseEvent): void;
}
还需要提供 provider, 这里要注意 : 由于我们的组件本身就是 value accessor 所以我们需要动一点手脚, 删除 provide NG_VALUE_ACCESSOR 改用 ngControl.valueAccessor = this 的方式去做.
@Component({
providers: [
{ provide: MatFormFieldControl, useExisting: MyInputComponent },
// { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: MyInputComponent },
],
})
export class MyInputComponent implements MatFormFieldControl<Value> {
constructor(
@Optional() @Self() public ngControl: NgControl, ) {
if (ngControl != null) {
ngControl.valueAccessor = this;
}
}
}
其它部分都很好理解.
stateChanges 是用来通知 form field 要 mark for check 的, 当我们内部修改后,要通知它就用这个.
要记得释放
ngOnDestroy() {
this.stateChanges.complete();
this.focusMonitor.stopMonitoring(this.hostElement.nativeElement);
}
其它的都是一些属性. 一般上会使用 getter setter 去维护更新,比如
public get focused(): boolean {
return this._focused;
}
public set focused(v: boolean) {
this._focused = v;
this.stateChanges.next();
}
private _focused: boolean;
比如
get empty() {
return this.value === '';
} get shouldLabelFloat() {
return this.focused || !this.empty;
}
关于 focus 通常使用 monitor 来监听
focusMonitor.monitor(hostElement.nativeElement, true).subscribe(origin => {
this.focused = origin === null ? false : true;
});
onContainerClick(event: MouseEvent) {
// if ((event.target as Element).tagName.toLowerCase() != 'input') {
// this.elRef.nativeElement.querySelector('input').focus();
// }
}
<input matInput placeholder="Email" [formControl]="emailFormControl"
[errorStateMatcher]="matcher">
最新文章
- stm8s103串口
- OC中面向对象2
- filter的详细配置
- elk实战分析nginx日志文档
- JavaWeb总结--Servlet 工作原理解析
- SQLServer中在视图上使用索引(转载)
- HDU 5311 Hidden String (暴力)
- background image position问题
- Jackson ObjectMapper类
- html5中的meta标签
- Timer 的学习
- 剑指offer 4.树 重建二叉树
- 从零开始学安全(十四)●Windows Server 2012 R2 本地搭建FTP服务器
- Python编程:从入门到实践(选记)
- oracle中 trunc 处理日期的用法
- HTML和CSS标签常用命名规则
- [转]TDD之Dummy Stub Fake Mock
- 虚函数与bind 实现设计模式的练习
- 查看apk包名和Activity名
- Hibernate之一对一关联映射