[javascript] Angular의 ngDefaultControl은 무엇입니까?

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

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

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

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

그리고. Angular의 양식에 대한 하나가 아니라 두 개의 거대한 가이드 와 다음에 대한 섹션을 읽었습니다 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 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.

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


답변