Avatar ·

Ошибка Angular: "There is no directive with exportAs set to ngForm" при работе с формами

Всем привет! Я новичок в Angular и TypeScript, и уже несколько часов бьюсь над ошибкой, которая возникает при попытке использовать шаблонные формы. У меня есть простой компонент для регистрации пользователя. Я создал форму с двумя полями: email и пароль. Использую директиву `ngModel` для двустороннего связывания данных и хочу получить доступ к форме через локальную переменную `#myForm="ngForm"`. Вот мой код: **user-registration.component.ts:** ```typescript import { Component } from '@angular/core'; @Component({ selector: 'app-user-registration', templateUrl: './user-registration.component.html', styleUrls: ['./user-registration.component.css'] }) export class UserRegistrationComponent { user = { email: '', password: '' }; onSubmit() { console.log('Форма отправлена', this.user); } } ``` **user-registration.component.html:** ```html
``` При запуске приложения в консоли браузера появляется ошибка: ``` Error: There is no directive with "exportAs" set to "ngForm" ``` Я импортировал `FormsModule` в `AppModule`, но ошибка всё равно остаётся. Подскажите, пожалуйста, в чём может быть проблема? Может быть, я что-то упустил в настройках модуля или не так использую директивы? <<>>

Причина ошибки

Ошибка "There is no directive with exportAs set to ngForm" возникает, когда Angular не может найти директиву NgForm, экспортирующую себя под именем ngForm. Это происходит, если FormsModule не импортирован в ваш модуль или импортирован неправильно. Даже если вы думаете, что импортировали его, ошибка может быть связана с тем, что вы импортируете FormsModule в AppModule, но ваш компонент объявлен в другом модуле (например, в FeatureModule), который не импортирует FormsModule.

Решение

Убедитесь, что FormsModule импортирован в тот модуль, где объявлен ваш компонент. Чаще всего это AppModule, но если у вас есть модули с ленивой загрузкой, импорт нужно делать в каждый из них. Вот правильный пример:

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // <-- обязательно импортировать

import { AppComponent } from './app.component';
import { UserRegistrationComponent } from './user-registration/user-registration.component';

@NgModule({
  declarations: [
    AppComponent,
    UserRegistrationComponent // <-- компонент объявлен здесь
  ],
  imports: [
    BrowserModule,
    FormsModule // <-- FormsModule добавлен в imports
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Пошаговая проверка

  1. Проверьте импорт в модуле: Убедитесь, что строка import { FormsModule } from '@angular/forms'; присутствует в файле модуля.
  2. Проверьте массив imports: FormsModule должен быть в массиве imports, а не в declarations или providers.
  3. Если у вас несколько модулей: Каждый модуль, который использует ngModel или ngForm, должен импортировать FormsModule.
  4. Проверьте версию Angular: В старых версиях (2.x) FormsModule мог быть в другом пакете. Убедитесь, что используете актуальные версии.
  5. Перезапустите сервер: После добавления импорта обязательно перезапустите сервер разработки (ng serve), так как изменения в модулях не применяются горячей перезагрузкой.

Дополнительная проверка

Если ошибка всё ещё появляется, проверьте, не импортировали ли вы случайно ReactiveFormsModule вместо FormsModule. Для шаблонных форм (template-driven forms) нужен именно FormsModule. ReactiveFormsModule используется для реактивных форм и не содержит директивы ngForm.

// Неправильно:
import { ReactiveFormsModule } from '@angular/forms'; // это для реактивных форм

// Правильно:
import { FormsModule } from '@angular/forms'; // для шаблонных форм

Проверка на опечатки

Убедитесь, что в шаблоне вы используете именно #myForm="ngForm" (с маленькой буквы 'n' в 'ngForm'). Angular чувствителен к регистру, и #myForm="ngform" или #myForm="NgForm" вызовут эту же ошибку.

После всех этих исправлений ваша форма должна работать корректно, и вы сможете использовать myForm.valid, myForm.submitted и другие свойства директивы NgForm.

<<>>

Альтернативный подход: использование реактивных форм

Если вы не хотите разбираться с шаблонными формами или вам нужна более сложная валидация, рассмотрите использование реактивных форм (Reactive Forms). Они не используют директиву ngForm, поэтому ошибка "There is no directive with exportAs set to ngForm" не возникнет.

// app.module.ts
import { ReactiveFormsModule } from '@angular/forms'; // импортируем ReactiveFormsModule

@NgModule({
  imports: [
    BrowserModule,
    ReactiveFormsModule // <-- используем реактивные формы
  ]
})
export class AppModule { }
// user-registration.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-user-registration',
  templateUrl: './user-registration.component.html'
})
export class UserRegistrationComponent implements OnInit {
  registrationForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.registrationForm = this.fb.group({
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required, Validators.minLength(6)]]
    });
  }

  onSubmit() {
    if (this.registrationForm.valid) {
      console.log('Форма отправлена', this.registrationForm.value);
    }
  }
}
<!-- user-registration.component.html -->
<form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">
  <div>
    <label>Email:</label>
    <input type="email" formControlName="email">
    <div *ngIf="registrationForm.get('email')?.invalid && registrationForm.get('email')?.touched">
      Введите корректный email
    </div>
  </div>
  <div>
    <label>Пароль:</label>
    <input type="password" formControlName="password">
  </div>
  <button type="submit" [disabled]="!registrationForm.valid">Зарегистрироваться</button>
</form>

Реактивные формы дают больше контроля над валидацией и состоянием формы, а также легче тестируются. Однако для простых форм шаблонный подход с FormsModule часто оказывается удобнее.