[ngDefaultControl]
Các điều khiển của bên thứ ba yêu cầu một ControlValueAccessorchức năng với các dạng góc cạnh. Nhiều người trong số họ, như Polymer <paper-input>, hoạt động giống như <input>phần tử gốc và do đó có thể sử dụng DefaultValueAccessor. Thêm một ngDefaultControlthuộc tính sẽ cho phép họ sử dụng chỉ thị đó.
<paper-input ngDefaultControl [(ngModel)]="value>
hoặc là
<paper-input ngDefaultControl formControlName="name">
Vì vậy, đây là lý do chính tại sao loại dầu này được giới thiệu.
Nó được gọi là ng-default-controlthuộc tính trong các phiên bản alpha của angle2 .
Vì vậy, ngDefaultControllà một trong những chọn lọc dùng cho DefaultValueAccessor chỉ thị:
@Directive({
selector:
'input:not([type=checkbox])[formControlName],
textarea[formControlName],
input:not([type=checkbox])[formControl],
textarea[formControl],
input:not([type=checkbox])[ngModel],
textarea[ngModel],
[ngDefaultControl]', <------------------------------- this selector
...
})
export class DefaultValueAccessor implements ControlValueAccessor {
Nó có nghĩa là gì?
Có nghĩa là chúng ta có thể áp dụng thuộc tính này cho phần tử (như thành phần polyme) không có bộ truy cập giá trị riêng của nó. Vì vậy, phần tử này sẽ lấy hành vi từ đó DefaultValueAccessorvà chúng ta có thể sử dụng phần tử này với các dạng góc.
Nếu không, bạn phải cung cấp cách triển khai của riêng mình ControlValueAccessor
ControlValueAccessor
Trạng thái tài liệu góc
ControlValueAccessor hoạt động như một cầu nối giữa API biểu mẫu Angular và một phần tử gốc trong DOM.
Hãy viết mẫu sau trong ứng dụng angle2 đơn giản:
<input type="text" [(ngModel)]="userName">
Để hiểu cách inputở trên của chúng ta sẽ hoạt động như thế nào, chúng ta cần biết các lệnh nào được áp dụng cho phần tử này. Ở đây góc đưa ra một số gợi ý về lỗi:
Từ chối Promise chưa được xử lý: Lỗi phân tích cú pháp mẫu: Không thể liên kết với 'ngModel' vì nó không phải là thuộc tính đã biết của 'input'.
Được rồi, chúng ta có thể mở SO và nhận được câu trả lời: nhập FormsModulevào @NgModule:
@NgModule({
imports: [
...,
FormsModule
]
})
export AppModule {}
Chúng tôi đã nhập nó và tất cả hoạt động như dự định. Nhưng điều gì đang xảy ra dưới mui xe?
FormsModule xuất cho chúng tôi các chỉ thị sau:
@NgModule({
...
exports: [InternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
})
export class FormsModule {}

Sau một số cuộc điều tra, chúng tôi có thể phát hiện ra rằng ba chỉ thị sẽ được áp dụng cho input
1) NgControlStatus
@Directive({
selector: '[formControlName],[ngModel],[formControl]',
...
})
export class NgControlStatus extends AbstractControlStatus {
...
}
2) NgModel
@Directive({
selector: '[ngModel]:not([formControlName]):not([formControl])',
providers: [formControlBinding],
exportAs: 'ngModel'
})
export class NgModel extends NgControl implements OnChanges,
3) DEFAULT_VALUE_ACCESSOR
@Directive({
selector:
`input:not([type=checkbox])[formControlName],
textarea[formControlName],
input:not([type=checkbox])formControl],
textarea[formControl],
input:not([type=checkbox])[ngModel],
textarea[ngModel],[ngDefaultControl]',
,,,
})
export class DefaultValueAccessor implements ControlValueAccessor {
NgControlStatuschỉ thao túng thị lớp thích ng-valid, ng-touched, ng-dirtyvà chúng ta có thể bỏ qua nó ở đây.
DefaultValueAccesstorcung cấp NG_VALUE_ACCESSORmã thông báo trong mảng nhà cung cấp:
export const DEFAULT_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DefaultValueAccessor),
multi: true
};
...
@Directive({
...
providers: [DEFAULT_VALUE_ACCESSOR]
})
export class DefaultValueAccessor implements ControlValueAccessor {
NgModelchỉ thị đưa vào NG_VALUE_ACCESSORmã thông báo khởi tạo đã được khai báo trên cùng một phần tử máy chủ.
export NgModel extends NgControl implements OnChanges, OnDestroy {
constructor(...
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {
Trong trường hợp của chúng tôi NgModelsẽ tiêm DefaultValueAccessor. Và bây giờ lệnh NgModel gọi setUpControlhàm chia sẻ :
export function setUpControl(control: FormControl, dir: NgControl): void {
if (!control) _throwError(dir, 'Cannot find control with');
if (!dir.valueAccessor) _throwError(dir, 'No value accessor for form control with');
control.validator = Validators.compose([control.validator !, dir.validator]);
control.asyncValidator = Validators.composeAsync([control.asyncValidator !, dir.asyncValidator]);
dir.valueAccessor !.writeValue(control.value);
setUpViewChangePipeline(control, dir);
setUpModelChangePipeline(control, dir);
...
}
function setUpViewChangePipeline(control: FormControl, dir: NgControl): void
{
dir.valueAccessor !.registerOnChange((newValue: any) => {
control._pendingValue = newValue;
control._pendingDirty = true;
if (control.updateOn === 'change') updateControl(control, dir);
});
}
function setUpModelChangePipeline(control: FormControl, dir: NgControl): void {
control.registerOnChange((newValue: any, emitModelEvent: boolean) => {
// control -> view
dir.valueAccessor !.writeValue(newValue);
// control -> ngModel
if (emitModelEvent) dir.viewToModelUpdate(newValue);
});
}
Và đây là cây cầu đang hoạt động:

NgModelthiết lập điều khiển (1) và dir.valueAccessor !.registerOnChangephương thức gọi . ControlValueAccessorlưu trữ lệnh gọi lại trong thuộc tính onChange(2) và kích hoạt lệnh gọi lại này khi inputsự kiện xảy ra (3) . Và cuối cùng updateControlhàm được gọi bên trong callback (4)
function updateControl(control: FormControl, dir: NgControl): void {
dir.viewToModelUpdate(control._pendingValue);
if (control._pendingDirty) control.markAsDirty();
control.setValue(control._pendingValue, {emitModelToViewChange: false});
}
nơi các lệnh gọi góc tạo thành API control.setValue.
Đó là một phiên bản ngắn về cách nó hoạt động.
@Input() ngModelvà@Output() ngModelChangecho ràng buộc hai chiều và tôi nghĩ rằng nó phải là đủ một cầu nối. Điều này trông giống như làm điều tương tự theo một cách hoàn toàn khác. Có lẽ tôi không nên đặt tên cho lĩnh vực của mìnhngModel?