В прошлых статьях использовались автономные компоненты, которые существовали как бы сами по себе. Мы могли в эти компоненты импортировать и использовать внешний функционал (например, модуль FormsModule для работы с элементами формы) и загружать эти компоненты непосредственно на веб-страницу. И команда разработчиков Angular рекомендует для новых проектов придерживаться этого подхода. Однако есть и другой подход, который применялся до Angular 16 и в принципе сейчас также может применяться - это использование модулей.
Модуль служит для объединения нескольких компонентов, которые предназначены для выполнения какой-то общей задачи, в одно целое. Приложение Angular может состоять из нескольких модулей. В этом случае один модуль является корневым или главным (root module). Сначала загружается главный модуль, Согласно условностям, он обычно называется 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'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
Для работы модуля ему необходимы ряд библиотек, поэтому в начале файла идет их подключение. Имя каждой библиотеки Angular начинается с префикса @angular.
Библиотеки устанавливаются через пакетный менеджер npm и импортируются с помощью директивы import
.
Например, импорт функциональности декоратора NgModule
из библиотеки @angular/core:
import { NgModule } from "@angular/core";
То есть здесь мы должны импортировать все модули и классы, которые использует данный модуль. В частности, для AppModule необходимы:
NgModule
: функциональность декоратора NgModule, без которой мы не сможем создать модуль
BrowserModule
: модуль, необходимый для работы с браузером
FormsModule
: модуль, необходимый для работы с формами html и, в частности, с элементами input. (Так как класс компонента работает с подобными
элементами, то мы обязаны также импортировать этот модуль)
AppComponent
: функциональность корневого компонента приложения
Непосредственно сам модуль представлен классом AppModule
, который на первый взгляд ничего не делает и не содержит никакого функционала:
export class AppModule { }
Однако в Angular модуль это не просто класс. Каждый модуль должен определяться с декоратором @NgModule.
NgModule представляет функцию-декоратора, которая принимает объект, свойства которого описывают метаданные модуля. Наиболее важные свойства:
declarations: классы представлений (view classes), которые принадлежат модулю. Angular имеет три типа классов представлений: компоненты (components), директивы (directives), каналы (pipes)
exports: набор классов представлений, которые должны использоваться в шаблонах компонентов из других модулей
imports: другие модули, классы которых необходимы для шаблонов компонентов из текущего модуля
providers: классы, создающие сервисы, используемые модулем
bootstrap: корневой компонент, который вызывается по умолчанию при загрузке приложения
В случае выше единственным классом представлений является компонент AppComponent. Поэтому он указывается для свойств declarations и bootstrap. И поскольку его действие зависит от модулей BrowserModule и FormsModule, то данные модули указываются для свойства imports.
А значение bootstrap: [ AppComponent ]
указывает, что модуль для загрузки в качестве основного компонента будет использовать
класс AppComponent.
Но при необходимости мы могли бы использовать и другие свойства:
@NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent ], bootstrap: [ AppComponent ], exports: [ ], providers: [ ] })
В файле app.component.ts определим следующий компонент AppComponent:
import { Component } from "@angular/core"; @Component({ selector: "my-app", template: `<label>Введите имя:</label> <input [(ngModel)]="name" placeholder="name"> <h1>Добро пожаловать {{name}}!</h1>` }) export class AppComponent { name= ''; }
Обратите внимание, что это компонент не автономный. И хотя этот компонент использует функциональность модуля FormsModule, этот модуль не надо явным образом импортировать - это делает модуль AppModule для всех своих компонентов.
При запуске приложения первым выполняется код, который определен в файле main.ts. Определим в нем код загрузки модуля AppModule:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; const platform = platformBrowserDynamic(); platform.bootstrapModule(AppModule);
Первая строка импортирует функциональность модуля platformBrowserDynamic
из пакета angular/platform-browser-dynamic
.
platformBrowserDynamic использует bootstrapModule для загрузки нужного модуля.
То есть фактически здесь platformBrowserDynamic запускает импортированный во второй строке модуль AppModule. После этого начинает работать вся логика, которая заложена в модуле AppModule, который представляет главный модуль приложения.
При запуске приложения будет загружаться главный модуль AppModule, который будет использовать в качестве загружаемого компонента AppComponent:
Сравнение модульного подхода и автономных компонентов:
В последующих статьях мы будем применять автономные компоненты как рекомендуемый подход.