Angular中的NgDefaultControl是什么?

不,这不是重复的问题。你看,在SO和GitHub中有大量的疑问和问题,要求我将这个指令添加到一个[(ngModel)]指令的标记中,并且不包含在表单中。如果我不添加它,我会得到一个错误:

ERROR Error: No value accessor for form control with unspecified name attribute

好的,如果我把这个属性放在那里,错误就会消失。但是,等等!没人知道它是做什么的!Angular的医生根本没有提到这一点。当我知道我不需要值访问器时,为什么还需要它呢?此属性如何连接到值访问器?这个指令是做什么的?什么是值访问器以及如何使用它?

为什么每个人都在做他们根本不理解的事情?只要加上这行代码就可以了,谢谢,这不是写好程序的方法。

然后。我读了不是一个而是关于角度__形式的巨大指南ABC2关于__的一节ABC0:

  • https://angular.io/guide/forms.
  • https://angular.io/guide/reactive-forms.
  • https://angular.io/guide/template-syntax#ngmodel.

你知道吗?没有单独提及值访问器或ngDefaultControl。它在哪里?

82117 次浏览

[NgDefaultControl]

第三方控件需要ControlValueAccessor才能与角度形式一起工作。它们中的许多,如聚合物的<paper-input>,表现得像<input>天然元素,因此可以使用DefaultValueAccessor。添加ngDefaultControl属性将允许它们使用该指令。

<paper-input ngDefaultControl [(ngModel)]="value>

<paper-input ngDefaultControl formControlName="name">

所以这是引入这个属性的主要原因。

它被称为ng-default-control属性在Angular2的alpha版本中

因此,ngDefaultControlDefaultValueAccessor指令的选择器之一:

@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 {

它是什么意思?

这意味着我们可以将此属性应用于没有自己的值访问器的元素(如聚合物组件)。所以这个元素将采用DefaultValueAccessor的行为,我们可以使用这个元素的角度形式。

否则,您必须提供您自己的ControlValueAccessor的实现

ControlValue访问器

文档状态

ControlValueAccessor充当角度表单API之间的桥梁 和DOM中的本机元素。

让我们在简单的Angular2应用程序中编写以下模板:

<input type="text" [(ngModel)]="userName">

为了理解上面的input的行为,我们需要知道哪些指令应用于该元素。这里Angular给出了一些错误提示:

未处理的承诺拒绝:模板分析错误:无法绑定到 “ ngModel ”,因为它不是“ input ”的已知属性。

好的,我们可以打开SO并得到答案:将FormsModule导入您的@NgModule

@NgModule({
imports: [
...,
FormsModule
]
})
export AppModule {}

我们进口了它,一切都按计划进行。但引擎盖下发生了什么?

形式模块为我们导出以下指令:

@NgModule({
...
exports: [InternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
})
export class FormsModule {}

enter image description here

经过一些调查,我们可以发现三个指令将适用于我们的input

  1. NG控制状态

    @指令({ 选择器:'[FormControlName],[ngModel],[FormControl]', ... }) 导出类NgControlStatus扩展AbstractControlStatus{ ... }

  2. NG模型

    @指令({ 选择器:'[ngModel]:非([FormControlName]):非([FormControl])', 提供程序:[FormControlBinding], 导出:' ngModel ' }) 导出类NgModel扩展了NgControl实现OnChanges,

  3. 默认_值_访问器

    @指令({ 选择器: `INPUT:NOT([type=checkbox])[FormControlName], 文本区域[FormControlName], 输入:不([type=checkbox])[FormControl], 文本区域[表单控制], 输入:NOT([type=checkbox])[ngModel], 文本区域[ngModel],[ngDefaultControl], ,,, }) 导出类DefaultValueAccessor实现ControlValueAccessor{

NgControlStatus指令只是操作像ng-validng-touchedng-dirty这样的类,我们可以在这里省略它。


DefaultValueAccesstor在提供程序数组中提供NG_VALUE_ACCESSOR令牌:

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指令在构造函数中注入在同一主机元素上声明的ABC1标记__。

export NgModel extends NgControl implements OnChanges, OnDestroy {
constructor(...
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {

在我们的例子中,NgModel将注入DefaultValueAccessor。现在ngModel指令调用共享__abc2函数:

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);
});
}

这就是行动中的桥梁:

enter image description here

NgModel设置控制(1)并调用dir.valueAccessor !.registerOnChange方法。ControlValueAccessor将回调存储在onChange(2)属性中,并在input事件(3)发生时触发此回调。最后,在回调(4)中调用updateControl函数

function updateControl(control: FormControl, dir: NgControl): void {
dir.viewToModelUpdate(control._pendingValue);
if (control._pendingDirty) control.markAsDirty();
control.setValue(control._pendingValue, {emitModelToViewChange: false});
}

其中角度调用形成APIcontrol.setValue

这是它如何工作的一个简短版本。