1. Компоненты нового поколения
До сих пор мы работали с классическими Angular-компонентами, которые всегда требуют регистрации в NgModule. Теперь пришло время познакомиться с более современным подходом — Standalone Components.
Если вы только начинаете знакомство с Angular, то слово Standalone может звучать как что-то из мира фильмов про супергероев. На самом деле, Standalone Components — это компоненты, которые могут существовать и использоваться без объявления их в каком-либо NgModule. Это нововведение появилось в Angular 14, а с версии 16 оно стало стандартом для большинства новых проектов.
Зачем это нужно?
- Проще стартовать новый проект. Не нужно создавать и поддерживать NgModule для каждого компонента.
- Меньше шаблонного кода, меньше ошибок с импортами и декларациями.
- Упрощает рефакторинг и повторное использование компонентов между проектами.
- Более быстрые загрузки и улучшенная поддержка ленивой загрузки (lazy loading).
Устройство классического компонента
Вот шаги работы с обычными компонентами:
- Создаём компонент (например, TaskListComponent).
- Обязательно добавляем его в массив declarations какого-либо модуля (обычно AppModule).
- Если хотим использовать его в другом модуле — не забудьте про exports и imports в соответствующем NgModule.
- Если забыли добавить компонент в нужный модуль — получите ошибку "Component is not part of any NgModule" (Компонент не является частью какого-либо NgModule) при запуске приложения.
Вот пример классического компонента и его объявления в модуле:
// task-list.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-task-list',
template: `<h2>Список задач</h2>`
})
export class TaskListComponent {}
// app.module.ts (пример модуля, где объявляется классический компонент)
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { TaskListComponent } from './task-list.component'; // Импортируем наш компонент
@NgModule({
declarations: [TaskListComponent], // <--- Объявляем (регистрируем) компонент здесь!
imports: [BrowserModule],
bootstrap: [TaskListComponent] // Или AppComponent, если это корневой
})
export class AppModule {}
Вопрос: А если забыть добавить компонент в declarations?
Ответ: Angular вас не пощадит — получите ошибку при запуске, потому что не будет знать о его существовании.
2. Standalone Component: синтаксис и создание
С появлением Standalone Components всё стало проще. Теперь можно создать компонент, который не требует объявления в NgModule.
Как создать Standalone Component?
Через CLI:
ng generate component task-list --standalone
Или покороче:
ng g c task-list --standalone
Результат:
CLI сгенерирует компонент с новым параметром standalone: true в декораторе @Component.
// task-list.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-task-list',
standalone: true, // ← вот оно!
template: `<h2>Список задач</h2>`
})
export class TaskListComponent {}
Обратите внимание:
- Нет необходимости добавлять компонент в declarations какого-либо модуля.
- Можно использовать компонент напрямую в точке входа приложения (bootstrapApplication).
3. Использование Standalone Components в приложении
Новый способ запуска приложения
С появлением Standalone Components, Angular предлагает новый подход к запуску приложения — без NgModule! Вместо bootstrapModule(AppModule), теперь можно использовать bootstrapApplication().
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { TaskListComponent } from './task-list.component';
bootstrapApplication(TaskListComponent)
.catch(err => console.error(err));
Вуаля! Ваше приложение стартует с компонента, который даже не знает, что такое NgModule.
Добавление других Standalone Components
Если у вас есть ещё один Standalone Component (например, TaskItemComponent), вы можете импортировать его прямо в imports другого компонента:
// task-item.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-task-item',
standalone: true,
template: `<li>{{ task }}</li>`
})
export class TaskItemComponent {
@Input() task = '';
}
// task-list.component.ts
import { Component } from '@angular/core';
import { TaskItemComponent } from './task-item.component';
@Component({
selector: 'app-task-list',
standalone: true,
imports: [TaskItemComponent], // ← прямо здесь!
template: `
<h2>Список задач</h2>
<ul>
<app-task-item *ngFor="let t of tasks" [task]="t"></app-task-item>
</ul>
`
})
export class TaskListComponent {
tasks = ['Погладить кота', 'Сделать домашку', 'Посмотреть сериал'];
}
Ключевой момент:
Всё, что раньше импортировалось через NgModule, теперь импортируется непосредственно в компонент через свойство imports.
4. Импорт Angular- и сторонних модулей в Standalone Component
Всё хорошо, но как же быть с Angular-модулями вроде CommonModule (чтобы работали *ngIf, *ngFor), или сторонними библиотеками?
Просто добавьте их в imports:
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-my-list',
standalone: true,
imports: [CommonModule],
template: `
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
`
})
export class MyListComponent {
items = ['Angular', 'React', 'Vue'];
}
Факт:
Теперь CommonModule и любые другие Angular-модули (например, FormsModule, ReactiveFormsModule) можно импортировать непосредственно в Standalone Component.
5. Сравнение: Standalone Component vs. NgModule
| Критерий | Standalone Component | Классический через NgModule |
|---|---|---|
| Объявление | в декораторе |
В массиве модуля |
| Импорт других компонентов | Через в декораторе компонента |
Через и модуля |
| Использование Angular-модулей | Через компонента |
Через модуля |
| Bootstrap приложения | Через |
Через |
| Ленивые модули (Lazy Loading) | Упрощён, не требует отдельного модуля | Требует отдельного |
| IDE-подсказки | Отлично поддерживается | Отлично поддерживается |
| Совместимость | Angular |
Angular |
Основные отличия:
- Standalone Components не требуют NgModule вообще.
- Импорт других компонентов, директив и пайпов — прямо в декораторе компонента.
- Упрощённая иерархия, меньше файлов, меньше ошибок с импортами.
- Отлично подходят для новых проектов и миграции старых (постепенно).
6. Практика: Развиваем мини-приложение "Список задач"
Давайте добавим форму для создания новых задач, используя Standalone Components и Angular Forms.
Шаг 1. Импортируем FormsModule
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-task-list',
standalone: true,
imports: [CommonModule, FormsModule],
template: `
<h2>Список задач</h2>
<form (ngSubmit)="addTask()">
<input [(ngModel)]="newTask" name="task" required>
<button type="submit">Добавить</button>
</form>
<ul>
<li *ngFor="let t of tasks">{{ t }}</li>
</ul>
`
})
export class TaskListComponent {
tasks = ['Погладить кота', 'Сделать домашку', 'Посмотреть сериал'];
newTask = '';
addTask() {
if (this.newTask.trim()) {
this.tasks.push(this.newTask.trim());
this.newTask = '';
}
}
}
Шаг 2. Запуск Standalone Component
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { TaskListComponent } from './task-list.component';
bootstrapApplication(TaskListComponent)
.catch(err => console.error(err));
Всё! Ваше приложение работает без единого NgModule.
7. Особенности и ограничения Standalone Components
Особенности
- Можно постепенно мигрировать старые проекты: Standalone Components и NgModule могут сосуществовать.
- Можно использовать Standalone Components внутри NgModule (но не наоборот).
- Поддерживают все возможности Angular: DI, роутинг, формы, пайпы, директивы.
Ограничения
- Некоторые сторонние библиотеки могут ещё не поддерживать Standalone Components (ситуация быстро меняется).
- Для сложных приложений с множеством повторно используемых компонентов иногда удобнее группировать их в NgModule (но это уже дело вкуса и архитектуры).
Факт:
Angular Router с версии 14 поддерживает ленивую загрузку Standalone Components без создания отдельного модуля.
8. Типичные ошибки при работе со Standalone Components
Ошибка №1: Забыли указать standalone: true.
Компонент не будет работать как Standalone, если этот параметр не указан. Angular попытается найти его в NgModule и выдаст ошибку.
Ошибка №2: Не импортировали CommonModule, а используете *ngIf или *ngFor.
В Standalone Component всегда нужно явно импортировать нужные Angular-модули через imports, иначе получите ошибку вида: "Can't bind to 'ngForOf' since it isn't a known property of 'li'".
Ошибка №3: Путают imports компонента и NgModule.
В Standalone Component импортируйте всё в массив imports внутри декоратора, а не в NgModule.
Ошибка №4: Забыли добавить FormsModule для работы с формами.
В классическом подходе FormsModule часто импортируется в AppModule, но в Standalone Component его нужно добавить вручную.
Ошибка №5: Не обновили Angular CLI или используете старую версию Angular.
Standalone Components поддерживаются только с Angular 14+. Если у вас старая версия — обновитесь, иначе ничего не получится.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ