不,这不是重复的问题。你看,在SO和Github中有很多问题和问题,它们规定我应该将这个指令添加到一个带有[(ngModel)]
指令的标记中,而不是包含在一个表单中。如果我不加它,我会得到一个错误:
ERROR Error: No value accessor for form control with unspecified name attribute
好的,如果我把这个属性放在那里,错误就会消失。但是等等!没人知道它是干什么的!而格朗的医生根本没提过。当我知道我不需要它时,为什么我需要一个值访问器?这个属性是如何连接到值访问器的?这个指令是做什么的?什么是值访问器,我如何使用它?
为什么每个人都在做他们根本不理解的事情?只需添加这一行代码就可以了,谢谢,这不是编写好程序的方法。
然后。我阅读的不是一本,而是两本关于角形的巨大指南和一节关于ngModel
的文章。
你知道吗?没有一次提到值访问器或ngDefaultControl
。它在哪里?
发布于 2017-09-28 09:44:07
ngDefaultControl
第三方控件要求ControlValueAccessor
具有角形式的功能。它们中的许多,如聚合物的<paper-input>
,行为像<input>
本机元素,因此可以使用DefaultValueAccessor
。添加一个ngDefaultControl
属性将允许他们使用该指令。
<paper-input ngDefaultControl [(ngModel)]="value>
或
<paper-input ngDefaultControl formControlName="name">
这就是为什么这个阿特鲁布特被引入的主要原因。
它被称为ng-default-control
属性在angular2的alpha版本中。
因此,ngDefaultControl
是DefaultValueAccessor指令的选择器之一:
@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
实现。
ControlValueAccessor
ControlValueAccessor充当角度窗体API和DOM中的本机元素之间的桥梁。
让我们在简单的angular2应用程序中编写以下模板:
<input type="text" [(ngModel)]="userName">
为了了解上面的input
的行为,我们需要知道应用到这个元素的是哪些指令。在这里,角给出了一些提示与错误:
未处理的承诺拒绝:模板解析错误:无法绑定到“ngModel”,因为它不是“输入”的已知属性。
好的,我们可以打开它并得到答案:将FormsModule
导入您的@NgModule
@NgModule({
imports: [
...,
FormsModule
]
})
export AppModule {}
我们导入了它,所有的工作都是按预期进行的。但引擎盖下面是怎么回事?
FormsModule为我们导出以下指令:
@NgModule({
...
exports: [InternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
})
export class FormsModule {}
经过一些调查,我们可以发现三个指令将应用于我们的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
指令只操作ng-valid
、ng-touched
、ng-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
指令注入在同一个主机元素上声明的构造函数NG_VALUE_ACCESSOR
令牌。
export NgModel extends NgControl implements OnChanges, OnDestroy {
constructor(...
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {
在我们的例子中,NgModel
将注入DefaultValueAccessor
。现在,NgModel指令调用共享setUpControl
函数:
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);
});
}
这是起作用的桥梁:
NgModel
设置控件(1)并调用dir.valueAccessor !.registerOnChange
方法。ControlValueAccessor
将回调存储在ControlValueAccessor
属性中,并在input
事件发生(3)时触发此回调。最后,在回调内部调用updateControl
函数(4)
function updateControl(control: FormControl, dir: NgControl): void {
dir.viewToModelUpdate(control._pendingValue);
if (control._pendingDirty) control.markAsDirty();
control.setValue(control._pendingValue, {emitModelToViewChange: false});
}
其中角调用形成API control.setValue
。
这是它工作原理的一个简短版本。
https://stackoverflow.com/questions/46465891
复制相似问题