[ngDefaultControl]
Các điều khiển của bên thứ ba yêu cầu một ControlValueAccessor
chứ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 ngDefaultControl
thuộ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-control
thuộc tính trong các phiên bản alpha của angle2 .
Vì vậy, ngDefaultControl
là 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ừ đó DefaultValueAccessor
và 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 FormsModule
và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 {
NgControlStatus
chỉ thao túng thị lớp thích ng-valid
, ng-touched
, ng-dirty
và chúng ta có thể bỏ qua nó ở đây.
DefaultValueAccesstor
cung cấp NG_VALUE_ACCESSOR
mã 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 {
NgModel
chỉ thị đưa vào NG_VALUE_ACCESSOR
mã 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 NgModel
sẽ tiêm DefaultValueAccessor
. Và bây giờ lệnh NgModel gọi setUpControl
hà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:

NgModel
thiết lập điều khiển (1) và dir.valueAccessor !.registerOnChange
phương thức gọi . ControlValueAccessor
lư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 input
sự kiện xảy ra (3) . Và cuối cùng updateControl
hà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() ngModel
và@Output() ngModelChange
cho 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
?