programing

Angular4 - 폼 제어를 위한 값 접근기 없음

starjava 2023. 4. 2. 09:40
반응형

Angular4 - 폼 제어를 위한 값 접근기 없음

커스텀 요소가 있습니다.

<div formControlName="surveyType">
  <div *ngFor="let type of surveyTypes"
       (click)="onSelectType(type)"
       [class.selected]="type === selectedType">
    <md-icon>{{ type.icon }}</md-icon>
    <span>{{ type.description }}</span>
  </div>
</div>

formControlName을 추가하려고 하면 다음 오류 메시지가 나타납니다.

오류:이름이 'survey'인 폼 제어에 대한 값 액세스자가 없습니다.타입'

ngDefaultControl선택이 . 할지 .어떻게 해야 할지 모르겠어요

누군가 카드 전체를 클릭하면 FormControl에 '타입'이 푸시되도록 이 FormControl에 클릭을 바인딩하고 싶습니다.가능합니까?

하시면 됩니다.formControlName를 실장하는 지시에 한합니다.

인터페이스의 실장

따라서 원하는 작업을 수행하려면 구현 컴포넌트를 작성해야 합니다.즉, 다음 3가지 기능을 구현해야 합니다.

  • writeValue(Angular에 모델에서 뷰로 값을 쓰는 방법을 알려 줍니다.)
  • registerOnChange되었을 때
  • registerOnTouched(컴포넌트가 터치이벤트를 수신했을 때 호출되는 핸들러를 설정해, 컴포넌트의 포커스가 설정되어 있는지를 확인하는 데 도움이 됩니다).

프로바이더 등록

이 는 Angular에게 이 을 .ControlValueAccessor(인터페이스는 TypeScript가 JavaScript로 컴파일될 때 코드에서 삭제되므로 절단되지 않습니다).프로바이더를 등록하면 됩니다.

공급자는 기존 을 제공하고 사용해야 합니다.여기도 필요합니다.주의:NG_VALUE_ACCESSOR멀티 프로바이더여야 합니다.

를 들어Component인 MyControl Component로 에 다음 .@Component★★★★★★★★★★★★★★★★★★:

providers: [
  { 
    provide: NG_VALUE_ACCESSOR,
    multi: true,
    useExisting: forwardRef(() => MyControlComponent),
  }
]

사용.

구성 요소를 사용할 준비가 되었습니다.템플릿 기반 폼에서는ngModel이제 바인딩이 제대로 작동합니다.

반응형 폼을 사용하여 이제 올바르게 사용할 수 있습니다.formControlName폼 컨트롤은 예상대로 동작합니다.

자원.

하면 됩니다.formControlName="surveyType" input이 아니라div

이 앵글을 때 는 뜻입니다formControl div이 문제를 해결하려면 두 가지 옵션이 있습니다.

  1. 네가 넣어.formControlName, 에서 Angular는 Angular를 사용합니다. 것들이 있습니다.input,textarea ★★★★★★★★★★★★★★★★★」select.
  2. '하다'를 합니다.ControlValueAccessor인터페이스입니다.이렇게 하면 Angular에게 "컨트롤의 값에 액세스하는 방법"(이름을 따옴)을 알려주는 것입니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★formControlName자연히 관련된 가치를 갖지 않는 요소입니다.

그럼 이제 '' ''를하고,ControlValueAccessor인터페이스는 처음에는 조금 부담스러울 수 있습니다.특히 이 문제에 대한 문서가 별로 없기 때문에 코드에 보일러 플레이트를 많이 추가해야 합니다.이 문제를 알기 쉬운 단계로 나누어 보겠습니다.

양식 컨트롤을 자체 구성요소로 이동

「 」를 실장하려면 , 「 」를 합니다.ControlValueAccessor새로운 컴포넌트(또는 지시어)를 작성해야 합니다.폼 컨트롤과 관련된 코드를 이동합니다.이와 같이 재사용도 용이합니다.에 컨트롤이 있는 될 수 컴포넌트 내부에 컨트롤이 있기 때문에 ''을 .ControlValueAccessor그렇지 않으면 사용자 지정 구성 요소를 Angular 양식과 함께 사용할 수 없기 때문입니다.

코드에 보일러 플레이트 추가

ControlValueAccessor인터페이스는 매우 상세합니다.이치노

import {Component, OnInit, forwardRef} from '@angular/core';
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms';


@Component({
  selector: 'app-custom-input',
  templateUrl: './custom-input.component.html',
  styleUrls: ['./custom-input.component.scss'],

  // a) copy paste this providers property (adjust the component name in the forward ref)
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomInputComponent),
      multi: true
    }
  ]
})
// b) Add "implements ControlValueAccessor"
export class CustomInputComponent implements ControlValueAccessor {

  // c) copy paste this code
  onChange: any = () => {}
  onTouch: any = () => {}
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouch = fn;
  }

  // d) copy paste this code
  writeValue(input: string) {
    // TODO
  }

그러면 개별 부품은 무엇을 하고 있을까요?

  • 시 Angular에게 a) Angular를 .ControlValueAccessor
  • b) 를 것을 합니다.ControlValueAccessor
  • 이수 .c) 이 부분이 가장 혼란스러울 수 있습니다.Angular에게 수 있는 onChange ★★★★★★★★★★★★★★★★★」onTouch실행 시 자체 구현이 가능하므로 이러한 함수를 호출할 수 있습니다.이 점을 이해하는 것이 중요합니다.최초 빈 구현 이외에는 onChangeonTouch를 직접 구현할 필요가 없습니다.당신이 (c)와 함께 하는 유일한 일은 Angular가 당신의 클래스에 자신의 함수를 부가하게 하는 것이다. 왜?그러면 전화할 수 있습니다.onChange ★★★★★★★★★★★★★★★★★」onTouch적절한 시간에 Angular에서 제공하는 방법.아래에서 어떻게 되는지 알아보겠습니다.
  • d) 또, 델이 어떻게writeValue방법은 다음 섹션에서 구현 시 사용할 수 있습니다.여기에 두었으니까 필요한 모든 속성들은ControlValueAccessor이치노

write Value 구현

what?writeValue폼 컨트롤이 외부에서 변경되었을 때 커스텀컴포넌트 내부에서 작업을 수행합니다.예를 들어 사용자 정의 양식 제어 구성 요소의 이름을 지정한 경우app-custom-input부모 컴포넌트에서는 다음과 같이 사용합니다.

<form [formGroup]="form">
  <app-custom-input formControlName="myFormControl"></app-custom-input>
</form>

writeValue마다 트리거됩니다.myFormControl 폼 : 폼 초기화 중)일 수this.form = this.formBuilder.group({myFormControl: ""}); 폼리셋 시) "" " " " " " 。this.form.reset();.

일반적으로 양식 컨트롤 값이 외부에서 변경되면 양식 컨트롤 값을 나타내는 로컬 변수에 씁니다.를 들어, '하다'가 '하다'라고 ,CustomInputComponent 컨트롤을 수 있습니다.

writeValue(input: string) {
  this.input = input;
}

「html」의합니다.CustomInputComponent:

<input type="text"
       [ngModel]="input">

또한 Angular 문서에 설명된 대로 입력 요소에 직접 쓸 수도 있습니다.

이것으로 외부에서 무언가가 변경되었을 때 컴포넌트 내부에서 일어나는 일을 처리했습니다.이제 다른 방향을 봅시다.컴포넌트 내부에 변화가 생겼을 때 어떻게 외부에 알립니까?

변경 시 호출

는 부모 입니다.CustomInputComponentonChange ★★★★★★★★★★★★★★★★★」onTouch(c) 위로부터의 기능이 작용한다.이러한 함수를 호출하면 컴포넌트 내부의 변경 사항을 외부에 알릴 수 있습니다.값의 변경을 외부에 전파하려면 새로운 값을 인수로 하여 onChange를 호출해야 합니다.예를 들어, 사용자가 에 무언가를 입력한 경우input컴포넌트의 에서는, 「」를 합니다.onChange다음 값을 사용합니다.

<input type="text"
       [ngModel]="input"
       (ngModelChange)="onChange($event)">

일이 있는지 수 는 자신의 각도로 바인드되어 있는 것은 이 실장입니다.onChange클래스 속성이 실장에서는 1개의 인수(갱신된 제어값)가 필요합니다.지금 당신이 하고 있는 일은 그 방법을 호출하고 Angular에게 변경에 대해 알리는 것입니다.이제 Angular가 진행되어 바깥쪽 폼 값이 변경됩니다.이게 이 모든 것의 핵심이야.를 호출하여 폼 컨트롤을 갱신해야 하는 시기와 값을 Angular에 알렸습니다."관리 값에 액세스"할 수 있는 수단을 제공했습니다.

: 이름onChange예를 들어 어떤 것이든 할 수 .propagateChange또는 이와 유사합니다. 이름을 와 Angular에서 를 사용할 수 .registerOnChange실행 시 메서드를 사용합니다.

온터치 호출

양식 컨트롤은 "터치"할 수 있으므로 사용자 정의 양식 컨트롤이 터치된 시점을 이해하는 수단도 Angular에 제공해야 합니다.수 할 수 있다, 할 수 있다, 할 수 있다, 할 수 있다, 할 수 있다.onTouch할 수 있는하고 있는지 Angular로 전화해야 합니다.onTouch" " " 력드가가드가 。

<input type="text"
       [(ngModel)]="input"
       (ngModelChange)="onChange($event)"
       (blur)="onTouch()">

한 번, 하다.onTouch제가 고른 이름인데, 실제 기능은 앵글이 제공하고 인수가 필요 없습니다.앵글에게 방금 알려줬으니 폼 컨트롤이 만졌다는 게 말이 되네

모든 것을 종합하면

다 합쳐서 어떤 느낌일까요?다음과 같이 표시됩니다.

// custom-input.component.ts
import {Component, OnInit, forwardRef} from '@angular/core';
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms';


@Component({
  selector: 'app-custom-input',
  templateUrl: './custom-input.component.html',
  styleUrls: ['./custom-input.component.scss'],

  // Step 1: copy paste this providers property
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomInputComponent),
      multi: true
    }
  ]
})
// Step 2: Add "implements ControlValueAccessor"
export class CustomInputComponent implements ControlValueAccessor {

  // Step 3: Copy paste this stuff here
  onChange: any = () => {}
  onTouch: any = () => {}
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouch = fn;
  }

  // Step 4: Define what should happen in this component, if something changes outside
  input: string;
  writeValue(input: string) {
    this.input = input;
  }

  // Step 5: Handle what should happen on the outside, if something changes on the inside
  // in this simple case, we've handled all of that in the .html
  // a) we've bound to the local variable with ngModel
  // b) we emit to the ouside by calling onChange on ngModelChange

}
// custom-input.component.html
<input type="text"
       [(ngModel)]="input"
       (ngModelChange)="onChange($event)"
       (blur)="onTouch()">
// parent.component.html
<app-custom-input [formControl]="inputTwo"></app-custom-input>

// OR

<form [formGroup]="form" >
  <app-custom-input formControlName="myFormControl"></app-custom-input>
</form>

기타 예

중첩된 양식

Control Value Accessors: 값 접근자 제어폼에는, 「」를 할 수 .@Input() subformControl Control Value Accessor를 랩하는 합니다.controls 아니라, 이에요.groups! 네스트된 형식의 입력을 사용하는 예를 참조하십시오.https://stackblitz.com/edit/angular-nested-forms-input-2

원천

이것은 Angular가 이러한 유형의 제어에 대해 서로 다른 ValueAccessor를 가지고 있기 때문에 선택한 입력 컨트롤의 "복수" 속성 때문입니다.

const countryControl = new FormControl();

그리고 내부 템플릿은 이렇게 사용합니다.

    <select multiple name="countries" [formControl]="countryControl">
      <option *ngFor="let country of countries" [ngValue]="country">
       {{ country.name }}
      </option>
    </select>

자세한 내용은 공식 문서를 참조하십시오.

언급URL : https://stackoverflow.com/questions/45659742/angular4-no-value-accessor-for-form-control

반응형