[ngDefaultControl]
Steuerungen von Drittanbietern erfordern eine ControlValueAccessorFunktion mit eckigen Formen. Viele von ihnen, wie Polymers <paper-input>, verhalten sich wie das <input>native Element und können daher das verwenden DefaultValueAccessor. Durch Hinzufügen eines ngDefaultControlAttributs können sie diese Anweisung verwenden.
<paper-input ngDefaultControl [(ngModel)]="value>
oder
<paper-input ngDefaultControl formControlName="name">
Dies ist der Hauptgrund, warum dieser Attribut eingeführt wurde.
In Alpha-Versionen von angle2 wurde es ng-default-controlAttribut genannt .
So ngDefaultControlist einer der Selektoren für die DefaultValueAccessor- Direktive:
@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 {
Was heißt das?
Dies bedeutet, dass wir dieses Attribut auf Elemente (wie Polymerkomponenten) anwenden können, die keinen eigenen Wertzugriff haben. Dieses Element übernimmt also das Verhalten von DefaultValueAccessorund wir können dieses Element mit eckigen Formen verwenden.
Andernfalls müssen Sie Ihre eigene Implementierung von bereitstellen ControlValueAccessor
ControlValueAccessor
Angular Docs Zustände
Ein ControlValueAccessor fungiert als Brücke zwischen der Angular Forms-API und einem nativen Element im DOM.
Schreiben wir die folgende Vorlage in einer einfachen Angular2-Anwendung:
<input type="text" [(ngModel)]="userName">
Um zu verstehen, wie sich unser inputoben genanntes Verhalten verhält, müssen wir wissen, welche Anweisungen auf dieses Element angewendet werden. Hier gibt Winkel einen Hinweis mit dem Fehler:
Nicht behandelte Ablehnung von Versprechungen: Fehler beim Analysieren von Vorlagen: Kann nicht an 'ngModel' gebunden werden, da dies keine bekannte Eigenschaft von 'input' ist.
Okay, wir können SO öffnen und die Antwort erhalten: Importieren FormsModulein Ihre @NgModule:
@NgModule({
imports: [
...,
FormsModule
]
})
export AppModule {}
Wir haben es importiert und alles funktioniert wie vorgesehen. Aber was ist unter der Haube los?
FormsModule exportiert für uns folgende Richtlinien:
@NgModule({
...
exports: [InternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
})
export class FormsModule {}

Nach einigen Untersuchungen können wir feststellen, dass drei Richtlinien auf unsere angewendet werden 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 {
NgControlStatusRichtlinie nur manipuliert Klassen mögen ng-valid, ng-touched, ng-dirtyund wir können es hier weglassen.
DefaultValueAccesstorstellt NG_VALUE_ACCESSORToken im Provider-Array bereit :
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 {
NgModelDie Direktive fügt ein Konstruktortoken ein NG_VALUE_ACCESSOR, das auf demselben Hostelement deklariert wurde.
export NgModel extends NgControl implements OnChanges, OnDestroy {
constructor(...
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {
In unserem Fall NgModelwird injizieren DefaultValueAccessor. Und jetzt ruft die NgModel-Direktive die gemeinsame setUpControlFunktion auf:
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);
});
}
Und hier ist die Brücke in Aktion:

NgModelrichtet die Steuerung (1) ein und ruft die dir.valueAccessor !.registerOnChangeMethode auf. ControlValueAccessorspeichert den Rückruf in der Eigenschaft onChange(2) und löst diesen Rückruf aus, wenn ein inputEreignis eintritt (3) . Und schließlich wird die updateControlFunktion innerhalb des Rückrufs aufgerufen (4).
function updateControl(control: FormControl, dir: NgControl): void {
dir.viewToModelUpdate(control._pendingValue);
if (control._pendingDirty) control.markAsDirty();
control.setValue(control._pendingValue, {emitModelToViewChange: false});
}
Wobei Winkelaufrufe API bilden control.setValue.
Das ist eine kurze Version davon, wie es funktioniert.
@Input() ngModelund@Output() ngModelChangefür bidirektionale Bindung gemacht und ich dachte, es sollte genug eine Brücke sein. Das sieht so aus, als würde man dasselbe auf eine ganz andere Art und Weise tun. Vielleicht sollte ich mein Feld nicht benennenngModel?