← Назад к вопросам

В чём разница между ng-content, ng-container и ng-template?

2.0 Middle🔥 101 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между ng-content, ng-container и ng-template в Angular

Эти три конструкции в Angular служат разным целям и часто используются в шаблонах. Понимание их различий критично для написания переиспользуемых и гибких компонентов.

ng-content

ng-content используется для создания слотов контента в компонентах (Content Projection). Это позволяет родительскому компоненту передавать контент в дочерний.

// child.component.ts
import { Component } from @angular/core;

@Component({
  selector: app-card,
  template: `
    <div class="card">
      <div class="card-header">
        <ng-content select=".header"></ng-content>
      </div>
      <div class="card-body">
        <ng-content></ng-content>
      </div>
      <div class="card-footer">
        <ng-content select=".footer"></ng-content>
      </div>
    </div>
  `
})
export class CardComponent {}
<!-- parent.component.html -->
<app-card>
  <div class="header">Заголовок карточки</div>
  <p>Основное содержимое</p>
  <div class="footer">Подвал карточки</div>
</app-card>

Характеристики ng-content:

  • Служит для projection (передачи содержимого)
  • Сам не отрисовывается (заменяется содержимым)
  • Может использовать select для выбора конкретного контента
  • Создает один элемент в DOM

ng-container

ng-container — это логический контейнер, который не создает элемент в DOM. Используется для группировки элементов без добавления дополнительного DOM узла.

// component.ts
import { Component } from @angular/core;

@Component({
  selector: app-user-list,
  template: `
    <div>
      <ng-container *ngIf="users.length > 0">
        <p>Количество пользователей: {{ users.length }}</p>
        <ul>
          <li *ngFor="let user of users">{{ user.name }}</li>
        </ul>
      </ng-container>
      
      <ng-container *ngIf="users.length === 0">
        <p>Пользователи не найдены</p>
      </ng-container>
    </div>
  `
})
export class UserListComponent {
  users = [];
}

Характеристики ng-container:

  • Логический контейнер
  • Не создает DOM элемента
  • Полезен для условного отображения (ngIf)
  • Полезен для циклов (ngFor)
  • Полезен для ng-switch
  • Может применять директивы

ng-template

ng-template — это шаблон, который не отрисовывается по умолчанию. Используется с директивами (*ngIf, *ngFor, ngTemplateOutlet) для определения повторно используемого шаблона.

// component.ts
import { Component, TemplateRef, ViewChild } from @angular/core;

@Component({
  selector: app-template-demo,
  template: `
    <ng-template #greeting let-name="name">
      <p>Привет, {{ name }}!</p>
    </ng-template>
    
    <div *ngTemplateOutlet="greeting; context: { name: Иван }"></div>
    <div *ngTemplateOutlet="greeting; context: { name: Мария }"></div>
  `
})
export class TemplateDemoComponent {
  @ViewChild(greeting) greetingTemplate: TemplateRef<any>;
}

Характеристики ng-template:

  • Определяет шаблон, который не отрисовывается по умолчанию
  • Используется с ngTemplateOutlet для отрисовки
  • Поддерживает контекст (передачу переменных)
  • Может быть переиспользован несколько раз
  • Используется с директивами (*ngIf, *ngSwitch)

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

Пример 1: Условное отображение

<!-- Плохо - добавляет лишний div -->
<div *ngIf="isVisible">
  <p>Видимо</p>
  <span>Текст</span>
</div>

<!-- Хорошо - не добавляет DOM элемент -->
<ng-container *ngIf="isVisible">
  <p>Видимо</p>
  <span>Текст</span>
</ng-container>

Пример 2: Циклы

<!-- Плохо - добавляет лишний div -->
<div *ngFor="let item of items">
  <span>{{ item }}</span>
</div>

<!-- Хорошо - без лишних элементов -->
<ng-container *ngFor="let item of items">
  <span>{{ item }}</span>
</ng-container>

Пример 3: Переиспользуемые компоненты

// list.component.ts
import { Component, Input, TemplateRef } from @angular/core;

@Component({
  selector: app-generic-list,
  template: `
    <div class="list">
      <div *ngFor="let item of items" class="list-item">
        <ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: item }"></ng-container>
      </div>
    </div>
  `
})
export class GenericListComponent {
  @Input() items: any[] = [];
  @Input() itemTemplate: TemplateRef<any>;
}
<!-- parent.html -->
<app-generic-list [items]="users" [itemTemplate]="userTemplate"></app-generic-list>

<ng-template #userTemplate let-user>
  <p>{{ user.name }} - {{ user.email }}</p>
</ng-template>

Пример 4: ng-switch с шаблонами

<ng-container [ngSwitch]="status">
  <ng-template ngSwitchCase="loading">
    <p>Загрузка...</p>
  </ng-template>
  
  <ng-template ngSwitchCase="success">
    <p>Успешно загружено</p>
  </ng-template>
  
  <ng-template ngSwitchCase="error">
    <p>Произошла ошибка</p>
  </ng-template>
  
  <ng-template ngSwitchDefault>
    <p>Неизвестное состояние</p>
  </ng-template>
</ng-container>

Таблица сравнения

Характеристикаng-contentng-containerng-template
Создает DOM элементНетНетНет
Для projectionДаНетНет
Для условных блоковНетДаДа
Для цикловНетДаДа
ПереиспользуемыйНетНетДа
С контекстомНетНетДа
С ngTemplateOutletНетНетДа

Практические примеры использования

1. Модальное окно с projection

@Component({
  selector: app-modal,
  template: `
    <div class="modal" *ngIf="isOpen">
      <div class="modal-header">
        <ng-content select=".header"></ng-content>
      </div>
      <div class="modal-body">
        <ng-content></ng-content>
      </div>
      <div class="modal-footer">
        <ng-content select=".footer"></ng-content>
      </div>
    </div>
  `
})
export class ModalComponent {
  @Input() isOpen = false;
}
<app-modal [isOpen]="showModal">
  <div class="header">Подтверждение</div>
  <p>Вы уверены?</p>
  <div class="footer">
    <button (click)="confirm()">Да</button>
    <button (click)="cancel()">Нет</button>
  </div>
</app-modal>

2. Таблица с кастомными ячейками

@Component({
  selector: app-data-table,
  template: `
    <table>
      <tr *ngFor="let row of rows">
        <td *ngFor="let column of columns">
          <ng-container *ngTemplateOutlet="getCellTemplate(column); context: { $implicit: row[column.field] }"></ng-container>
        </td>
      </tr>
    </table>
  `
})
export class DataTableComponent {
  @Input() rows: any[] = [];
  @Input() columns: any[] = [];
  @Input() cellTemplates: { [key: string]: TemplateRef<any> } = {};
  
  getCellTemplate(column: any) {
    return this.cellTemplates[column.field] || this.defaultCellTemplate;
  }
  
  @ViewChild(defaultCell) defaultCellTemplate: TemplateRef<any>;
}

3. Условный рендеринг с минимальным DOM

<!-- ng-container не добавляет элемент в DOM -->
<section>
  <h2>Список пользователей</h2>
  
  <ng-container *ngIf="users.length > 0; else noUsers">
    <ul>
      <li *ngFor="let user of users">{{ user.name }}</li>
    </ul>
  </ng-container>
  
  <ng-template #noUsers>
    <p>Пользователи не найдены</p>
  </ng-template>
</section>

Рекомендации

  1. ng-content - для создания переиспользуемых компонентов с гибким контентом
  2. ng-container - для группировки элементов без добавления DOM узла (условия, циклы)
  3. ng-template - для определения переиспользуемых шаблонов с контекстом

Вывод: Правильное использование этих конструкций делает Angular код чище, производительнее и более переиспользуемым. ng-container часто недооценивается, но это мощный инструмент для минимизации DOM иерархии.

В чём разница между ng-content, ng-container и ng-template? | PrepBro