Javascript Angular 中的 ngDefaultControl 是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46465891/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is ngDefaultControl in Angular?
提问by Gherman
No, this is not a duplicate question. You see, there is a ton of questions and issues in SO and Github that prescribe that I add this directive to a tag that has [(ngModel)]directive and is not contained in a form. If I don't add it I get an error:
不,这不是一个重复的问题。您会看到,SO 和 Github 中有大量问题和问题规定我将此指令添加到具有[(ngModel)]指令但未包含在表单中的标签中。如果我不添加它,我会收到一个错误:
ERROR Error: No value accessor for form control with unspecified name attribute
Ok, error goes away if I put this attribute there. BUT, wait! Nobody knows what it does! And Angular's doc doesn't mention it at all. Why do I need a value accessor when I know that I don't need it? How is this attribute connected to value accessors? What does this directive do? What is a value acessor and how do I use it?
好的,如果我把这个属性放在那里,错误就会消失。可是等等!没有人知道它的作用!Angular 的文档根本没有提到它。当我知道我不需要它时,为什么我需要一个值访问器?这个属性如何连接到值访问器?这个指令有什么作用?什么是价值访问者,我该如何使用它?
And why does everybody keep doing things that they don't understand t all? Just add this line of code and it works, thank you, this is not the way to write good programs.
为什么每个人都继续做他们根本不了解的事情?添加这行代码就可以了,谢谢,这不是写好程序的方法。
And then. I read not one but twohuge guides about forms in Angular anda section about ngModel:
进而。我读的不是一本而是两本关于 Angular 表单的巨大指南,还有一节关于ngModel:
- https://angular.io/guide/forms
- https://angular.io/guide/reactive-forms
- https://angular.io/guide/template-syntax#ngModel
- https://angular.io/guide/forms
- https://angular.io/guide/reactive-forms
- https://angular.io/guide/template-syntax#ngModel
And you know what? Not a single mention of either value accessors or ngDefaultControl. Where is it?
你知道吗?没有提到值访问器或ngDefaultControl. 它在哪里?
回答by yurzui
[ngDefaultControl]
[ngDefaultControl]
Third party controls require a ControlValueAccessorto function with angular forms. Many of them, like Polymer's <paper-input>, behave like the <input>native element and thus can use the DefaultValueAccessor. Adding an ngDefaultControlattribute will allow them to use that directive.
第三方控件需要ControlValueAccessor使用 angular 表单才能运行。它们中的许多,如 Polymer 的<paper-input>,表现得像<input>原生元素,因此可以使用DefaultValueAccessor. 添加ngDefaultControl属性将允许他们使用该指令。
<paper-input ngDefaultControl [(ngModel)]="value>
or
或者
<paper-input ngDefaultControl formControlName="name">
So this is the main reason why this attrubute was introduced.
所以这就是引入这个属性的主要原因。
It was called ng-default-controlattribute in alpha versions of angular2.
它在 angular2 的 alpha 版本中被称为ng-default-control属性。
So ngDefaultControlis one of selectors for DefaultValueAccessordirective:
DefaultValueAccessor指令ngDefaultControl的选择器之一也是如此:
@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 {
What does it mean?
这是什么意思?
It means that we can apply this attribute to element(like polymer component) that doesn't have its own value accessor. So this element will take behaviour from DefaultValueAccessorand we can use this element with angular forms.
这意味着我们可以将此属性应用于没有自己的值访问器的元素(如聚合物组件)。所以这个元素将从中获取行为DefaultValueAccessor,我们可以将这个元素与角度形式一起使用。
Otherwise you have to provide your own implementation of ControlValueAccessor
否则,您必须提供自己的实现 ControlValueAccessor
ControlValueAccessor
控制值存取器
Angular docs states
Angular文档说明
A ControlValueAccessor acts as a bridge between the Angular forms API and a native element in the DOM.
ControlValueAccessor 充当 Angular 表单 API 和 DOM 中的原生元素之间的桥梁。
Let's write the following template in simple angular2 application:
让我们在简单的 angular2 应用程序中编写以下模板:
<input type="text" [(ngModel)]="userName">
To understand how our inputabove will behave we need to know which directives are applied to this element. Here angular gives out some hint with the error:
要了解我们input上面的行为,我们需要知道哪些指令应用于此元素。这里 angular 给出了一些错误提示:
Unhandled Promise rejection: Template parse errors: Can't bind to 'ngModel' since it isn't a known property of 'input'.
未处理的承诺拒绝:模板解析错误:无法绑定到“ngModel”,因为它不是“输入”的已知属性。
Okay, we can open SO and get the answer: import FormsModuleto your @NgModule:
好的,我们可以打开 SO 并得到答案:导入FormsModule到您的@NgModule:
@NgModule({
imports: [
...,
FormsModule
]
})
export AppModule {}
We imported it and all works as intended. But what's going on under the hood?
我们导入了它并且一切正常。但是引擎盖下发生了什么?
FormsModuleexports for us the following directives:
FormsModule为我们导出以下指令:
@NgModule({
...
exports: [InternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
})
export class FormsModule {}
After some investigation we can discover that three directives will be applied to our input
经过一些调查,我们可以发现三个指令将应用于我们的 input
1) NgControlStatus
1) NgControlStatus
@Directive({
selector: '[formControlName],[ngModel],[formControl]',
...
})
export class NgControlStatus extends AbstractControlStatus {
...
}
2) NgModel
2)吴模型
@Directive({
selector: '[ngModel]:not([formControlName]):not([formControl])',
providers: [formControlBinding],
exportAs: 'ngModel'
})
export class NgModel extends NgControl implements OnChanges,
3) DEFAULT_VALUE_ACCESSOR
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 {
NgControlStatusdirective just manipulates classes like ng-valid, ng-touched, ng-dirtyand we can omit it here.
NgControlStatus指令只是操纵类一样ng-valid,ng-touched,ng-dirty我们可以在这里省略。
DefaultValueAccesstorprovides NG_VALUE_ACCESSORtoken in providers array:
DefaultValueAccesstorNG_VALUE_ACCESSOR在 providers 数组中提供令牌:
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 {
NgModeldirective injects in constructor NG_VALUE_ACCESSORtoken that was declared on the same host element.
NgModel指令注入在NG_VALUE_ACCESSOR同一宿主元素上声明的构造函数令牌。
export NgModel extends NgControl implements OnChanges, OnDestroy {
constructor(...
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {
In our case NgModelwill inject DefaultValueAccessor. And now NgModel directive calls shared setUpControlfunction:
在我们的例子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);
});
}
And here is the bridge in action:
这是正在运行的桥梁:
NgModelsets up control (1)and calls dir.valueAccessor !.registerOnChangemethod. ControlValueAccessorstores callback in onChange(2)property and fires this callback when inputevent happens (3). And finally updateControlfunction is called inside callback (4)
NgModel设置控件(1)并调用dir.valueAccessor !.registerOnChange方法。ControlValueAccessor将回调存储在onChange(2)属性中,并在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});
}
where angular calls forms API control.setValue.
其中 angular 调用形成 API control.setValue。
That's a short version of how it works.
这是它如何工作的简短版本。


