이 경고는 부모 컴포넌트에 폼 디렉티브(NgForm 또는 FormGroupDirective)가 있지만 자식 컴포넌트 안의 ngModel(또는 템플릿 기반 폼 컨트롤)이 해당 폼에 등록할 수 없을 때 발생합니다.
원인은 NgModel이 @Host()로 ControlContainer를 주입하기 때문입니다. 이 설정은 인젝터가 컴포넌트 경계를 넘어 탐색하지 못하게 합니다. 따라서 자식 템플릿의 NgModel에서는 부모 컴포넌트 템플릿의 폼 디렉티브가 보이지 않습니다.
그 결과 자식 컨트롤은 별도 알림 없이 독립적인 컨트롤로 동작하며 부모 폼의 값, 유효성, 제출 상태에 참여하지 않습니다.
경고 해결하기
방법 1: viewProviders로 ControlContainer 연결하기
자식 컴포넌트에 viewProviders를 추가하여 부모 폼을 자신의 뷰에 다시 제공합니다. 경고에 표시된 클래스를 사용하세요. 템플릿 기반 폼(<form>)에는 NgForm, 반응형 폼([formGroup])에는 FormGroupDirective를 사용합니다.
// Parent uses a template-driven form: <form> ... <app-child> </form>
import {ControlContainer, NgForm} from '@angular/forms';
import {Component} from '@angular/core';
@Component({
selector: 'app-child',
template: `<input name="email" [(ngModel)]="email" />`,
viewProviders: [{provide: ControlContainer, useExisting: NgForm}],
})
export class Child {
email = '';
}
// Parent uses a reactive form: <div [formGroup]="myGroup"> ... <app-child> </div>
import {ControlContainer, FormGroupDirective} from '@angular/forms';
import {Component} from '@angular/core';
@Component({
selector: 'app-child',
template: `<input name="email" [(ngModel)]="email" />`,
viewProviders: [{provide: ControlContainer, useExisting: FormGroupDirective}],
})
export class Child {
email = '';
}
이제 부모 폼에서 자식 컨트롤을 정상적으로 인식하고 검증합니다.
방법 2: 컨트롤을 독립적으로 설정하기
자식 컨트롤이 실제로 부모 폼과 독립적으로 동작해야 한다면 명시적으로 등록을 제외하세요.
<input name="email" [(ngModel)]="email" [ngModelOptions]="{standalone: true}" />
경고 디버깅하기
경고 메시지에는 오류 코드 NG01354가 포함됩니다. 호출 스택으로 경고를 발생시킨 ngModel을 찾으세요. <form> 태그와 ngModel 입력 요소를 소유한 컴포넌트가 같은지 확인하고, 다르다면 위 방법 중 하나를 적용하세요.