Angular의 ngDefaultControl은 무엇입니까?


102

아니요, 중복 질문이 아닙니다. SO 및 Github에는이 지시문을 지시문이 [(ngModel)]있고 양식에 포함되지 않은 태그에 추가하도록 규정하는 수많은 질문과 문제가 있습니다 . 추가하지 않으면 오류가 발생합니다.

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

좋아,이 속성을 거기에 넣으면 오류가 사라집니다. 하지만 기다려! 그것이 무엇을하는지 아무도 모릅니다! 그리고 Angular의 문서는 그것을 전혀 언급하지 않습니다. 값 접근자가 필요하지 않다는 것을 알고 있는데 왜 필요한가요? 이 속성은 값 접근 자와 어떻게 연결됩니까? 이 지침은 무엇을합니까? Value Acessor는 무엇이며 어떻게 사용합니까?

그리고 왜 모두가 이해하지 못하는 일을 계속하는 걸까요? 이 코드 줄을 추가하면 작동합니다. 감사합니다. 이것은 좋은 프로그램을 작성하는 방법이 아닙니다.

그리고. Angular의 양식에 대한 하나가 아니라 두 개의 거대한 가이드 와 다음에 대한 섹션을 읽었습니다 ngModel.

그리고 그거 알아? 값 접근 자 또는 ngDefaultControl. 어디 있어요?

답변:


180

[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 FormsModuleto 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)onChangeinputupdateControl

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.

작동 방식의 짧은 버전입니다.


난 그냥 만들어 @Input() ngModel@Output() ngModelChange결합 양방향과 나는 충분히 다리해야한다 생각했다. 이것은 완전히 다른 방식으로 같은 일을하는 것처럼 보입니다. 내 분야에 이름을 붙이면 안 ngModel될까요?
Gherman

2
이 구성 요소를 각진 형태와 함께 사용하지 않으면 다음과 같이 양방향 바인딩을 생성 @Input() value; @Output() valueChange: EventEmitter<any> = new EventEmitter();한 다음 사용할 수 있습니다.[(value)]="someProp"
yurzui

1
그게 바로 제가하던 일입니다. 하지만 내 "값"의 이름을 지어 ngModelAngular가 내게 오류를 던지고 ControlValueAccessor로 요청하기 시작했습니다.
Gherman

vue 및 React에서 ngDefaultControl에 해당하는 사람이 있습니까? 내 말은, 컨트롤 값 접근자를 사용하여 각도로 사용자 정의 입력 구성 요소를 만들고 Angular 요소의 웹 구성 요소로 래핑했습니다. 같은 프로젝트에서 ngDefaultControl을 사용하여 각도 양식으로 작업해야했습니다. 하지만 Vue와 React에서 작동하게하려면 어떻게해야합니까? 또한 네이티브 JS에서?
Kavinda Jayakody 19 년

사용자 지정 구성 요소에서 ngDefaultControl을 사용하고 있지만 한 가지 문제로 어려움을 겪고 있습니다. formBuilder 뷰 (사용자 정의 입력 구성 요소) 내에서 formControl의 기본값을 설정하면 업데이트되지 않고 모델 만 업데이트됩니다. 내가 뭘 잘못하고 있죠?
Igor Janković
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.