아니요, 중복 질문이 아닙니다. SO 및 Github에는이 지시문을 지시문이 [(ngModel)]
있고 양식에 포함되지 않은 태그에 추가하도록 규정하는 수많은 질문과 문제가 있습니다 . 추가하지 않으면 오류가 발생합니다.
ERROR Error: No value accessor for form control with unspecified name attribute
좋아,이 속성을 거기에 넣으면 오류가 사라집니다. 하지만 기다려! 그것이 무엇을하는지 아무도 모릅니다! 그리고 Angular의 문서는 그것을 전혀 언급하지 않습니다. 값 접근자가 필요하지 않다는 것을 알고 있는데 왜 필요한가요? 이 속성은 값 접근 자와 어떻게 연결됩니까? 이 지침은 무엇을합니까? Value Acessor는 무엇이며 어떻게 사용합니까?
그리고 왜 모두가 이해하지 못하는 일을 계속하는 걸까요? 이 코드 줄을 추가하면 작동합니다. 감사합니다. 이것은 좋은 프로그램을 작성하는 방법이 아닙니다.
그리고. Angular의 양식에 대한 하나가 아니라 두 개의 거대한 가이드 와 다음에 대한 섹션을 읽었습니다 ngModel
.
- https://angular.io/guide/forms
- https://angular.io/guide/reactive-forms
- https://angular.io/guide/template-syntax#ngModel
그리고 그거 알아? 값 접근 자 또는 ngDefaultControl
. 어디 있어요?
답변
[ngDefaultControl]
타사 컨트롤을 사용하려면 ControlValueAccessor
각도 형식으로 작동 해야 합니다. Polymer와 같이 그들 중 다수는 기본 요소 <paper-input>
처럼 작동 <input>
하므로 DefaultValueAccessor
. ngDefaultControl
속성을 추가하면 해당 지시문을 사용할 수 있습니다.
<paper-input ngDefaultControl [(ngModel)]="value>
또는
<paper-input ngDefaultControl formControlName="name">
그래서 이것이이 attrubute가 소개 된 주된 이유입니다.
angular2의 알파 버전에서는ng-default-control
속성 이라고 합니다 .
그래서 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
Angular 문서 상태
ControlValueAccessor는 Angular 양식 API와 DOM의 기본 요소 사이의 다리 역할을합니다.
간단한 angular2 애플리케이션에서 다음 템플릿을 작성해 보겠습니다.
<input type="text" [(ngModel)]="userName">
input
위의 동작 방식을 이해하려면 이 요소에 어떤 지시문이 적용되는지 알아야합니다. 여기서 angular는 오류에 대한 힌트를 제공합니다.
처리되지 않은 약속 거부 : 템플릿 구문 분석 오류 : ‘입력’의 알려진 속성이 아니므로 ‘ngModel’에 바인딩 할 수 없습니다.
좋아요, 우리는 SO를 열고 답을 얻을 수 있습니다 : import FormsModule
to your @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
메서드를 호출 합니다. (2) 속성에 ControlValueAccessor
콜백을 저장 하고 이벤트가 발생할 때이 콜백을 실행 합니다 (3) . 마지막으로 함수는 콜백 내부에서 호출됩니다. (4)onChange
input
updateControl
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
.
작동 방식의 짧은 버전입니다.