Все, що вам потрібно знати про ng-template, ng-content, ng-container та * ngTemplateOutlet у Angular

Це був один із тих днів, коли я був зайнятий роботою над новими функціями для свого офісного проекту. Раптом щось привернуло мою увагу:

Під час огляду DOM я побачив, ngcontentяк Angular застосовує елементи до елементів. Хм ... якщо вони містять елементи в остаточному DOM, то яка користь ? У той час я плутався між і .

У пошуках відповідей на мої запитання я виявив поняття . На мій подив, теж було *ngTemplateOutlet. Я розпочав свою подорож, шукаючи ясності щодо двох понять, але зараз у мене їх було чотири, і звучали майже однаково!

Ви коли-небудь були в такій ситуації? Якщо так, то ви знаходитесь у правильному місці. Тож без зайвих сумнівів давайте візьмемо їх по одному.

1.

Як підказує назва , яке є шаблоном елемент , який використовує кутові зі структурними директивами ( *ngIf, *ngFor, [ngSwitch]і призначені для користувача директиви).

Ці елементи шаблону працюють лише за наявності структурних директив . Angular загортає хост-елемент (до якого застосовується директива) всерединіі споживаєготовий DOM, замінюючи його діагностичними коментарями.

Розглянемо простий приклад *ngIf:

Вище наведено Кутову інтерпретацію *ngIf. Angular розміщує елемент хоста, до якого застосовується директива, і зберігає хост таким, яким він є. Остаточний DOM подібний до того, що ми бачили на початку цієї статті:

Використання:

Ми бачили, як Angular використовує, але що, якщо ми хочемо ним користуватися? Оскільки ці елементи працюють лише зі структурною директивою, ми можемо записати як:

Ось homeце booleanвластивість компонента набору до trueзначенням. Вихід вищезазначеного коду в DOM:

Нічого не отримано! :(

Але чому ми не можемо побачити своє повідомлення навіть після правильного використання зі структурною директивою?

Це був очікуваний результат. Як ми вже обговорювали, Angular замінює діагностичні коментарі. Без сумніву, наведений вище код не призведе до помилок, оскільки Angular цілком відповідає вашому випадку використання. Ви ніколи не дізнаєтесь, що саме сталося за лаштунками.

Давайте порівняємо дві наведені вище DOM, які були відтворені Angular:

Якщо ви уважно стежите, в останньому DOM прикладу 2 є один додатковий тег коментаря . Код, який інтерпретував Angular:

Angular загорнув ваш хост в інший і перетворив не лише зовнішній на діагностичні коментарі, але й внутрішній! Ось чому ви не бачили жодного свого повідомлення.

Щоб позбутися цього, є два способи отримати бажаний результат:

Спосіб 1:

За допомогою цього методу ви надаєте Angular формат, що не цукрується, і який не потребує подальшої обробки. Цього разу Angular перетворить лише на коментарі, але залишить вміст усередині нього недоторканим (їх більше немає всередині, як це було в попередньому випадку). Таким чином, він правильно відобразить вміст.

Щоб дізнатись більше про те, як використовувати цей формат з іншими структурними директивами, зверніться до цієї статті.

Спосіб 2:

Це досить невидимий формат, який рідко використовується (за допомогою двох братів та сестер ). Тут ми даємо посилання на шаблон *ngIfв його, thenщоб сказати, який шаблон слід використовувати, якщо умова відповідає дійсності.

Використовувати декілька подібних не рекомендується (ви можете використовувати їх ), оскільки це не те, для чого вони призначені. Вони використовуються як контейнер для шаблонів, які можна використовувати повторно в декількох місцях. Детальніше про це ми поговоримо у наступному розділі цієї статті.

2.

Ви коли-небудь писали або бачили код, подібний до цього:

Причиною того, що багато хто з нас пише цей код, є неможливість використання декількох структурних директив на одному елементі хосту в Angular. Зараз цей код працює нормально, але він вводить кілька зайвих порожніх значень у DOM, якщо item.idце хибне значення, яке може не знадобитися.

Можливо, вас не турбує такий простий приклад, як цей, але для величезної програми, яка має складний DOM (для відображення десятків тисяч даних), це може стати проблемою, оскільки елементи можуть мати приєднані до них слухачі, які все ще будуть там у DOM слухає події.

Що ще гірше - це рівень вкладеності, який вам потрібно зробити, щоб застосувати свій стиль (CSS)!

Не хвилюйтеся, ми маємо на допомогу!

Angular - це елемент групування, який не заважає стилям або макету, оскільки Angular не поміщає його в DOM .

Отже, якщо ми напишемо наш Приклад 1 з :

Ми отримуємо остаточний DOM як:

Дивись, ми позбулися цих порожніх с. Нам слід використовувати, коли ми просто хочемо застосувати декілька структурних директив, не вводячи жодного зайвого елемента в наш DOM.

Для отримання додаткової інформації зверніться до документів. Існує ще один варіант використання, коли він використовується для динамічного введення шаблону на сторінку. Я розгляну цей випадок використання в останньому розділі цієї статті.

3.

Вони використовуються для створення налаштованих компонентів. Це означає, що компоненти можуть бути налаштовані залежно від потреб користувача. Це добре відомо як Проекція вмісту . Компоненти, які використовуються у виданих бібліотеках, використовують, щоб зробити їх налаштованими.

Розглянемо простий компонент:

Вміст HTML, переданий у відкриваючі та закриваючі теги компонента, є вмістом, що проектується. Це те, що ми називаємо проекцією вмісту . Вміст відображатиметься всередині компонента. Це дозволяє споживачеві компонента передавати будь-який спеціальний нижній колонтитул всередині компонента і контролювати , як саме вони хочуть, щоб він відображався.

Кілька проекцій:

Що, якби ви могли вирішити, який вміст де розміщувати? Замість кожного вмісту, що проектується всередині одного , ви також можете контролювати, як вміст буде проектуватися за допомогою selectатрибута . Для вибору вмісту для проектування всередині конкретного потрібен селектор елементів .

Ось як:

Ми змінили визначення, щоб виконати проеціювання багатоконтентного вмісту. selectАтрибут вибирає тип контенту , який буде наданий всередині конкретним . Тут ми повинні спершу selectвідтворити заголовок h1. Якщо прогнозований вміст не має h1елемента, він нічого не відображатиме. Так само другий selectшукає a div. Решта вмісту відображається всередині останнього без select.

Виклик компонента буде виглядати так:

4. * ngTemplateOutlet

... Вони використовуються як контейнер для шаблонів, які можна використовувати повторно в декількох місцях. Детальніше про це ми поговоримо у наступному розділі цієї статті.

... Існує ще один варіант використання, коли він використовується для динамічного введення шаблону на сторінку. Я розгляну цей випадок використання в останньому розділі цієї статті.

У цьому розділі ми обговоримо два вищезазначені моменти, згадані раніше. *ngTemplateOutletвикористовується для двох сценаріїв - вставити загальний шаблон у різні розділи подання незалежно від циклів або стану та створити висококонфігурований компонент.

Повторне використання шаблону:

Розглянемо подання, де вам потрібно вставити шаблон у декількох місцях. Наприклад, логотип компанії, що розміщується на веб-сайті. Ми можемо досягти цього, написавши шаблон для логотипу один раз і повторно використовуючи його скрізь у поданні.

Нижче наведено фрагмент коду:

Як бачите, ми просто написали шаблон логотипу один раз і використали його тричі на одній сторінці з одним рядком коду!

*ngTemplateOutletтакож приймає об'єкт контексту, який можна передати для налаштування загального виводу шаблону. Для отримання додаткової інформації про об'єкт контексту зверніться до офіційних документів.

Настроювані компоненти:

Другий варіант використання - *ngTemplateOutletце високо налаштовані компоненти. Розглянемо наш попередній приклад компонента з деякими модифікаціями:

Вище модифікована версія компонента , який приймає три вхідних властивості -  headerTemplate, bodyTemplate, footerTemplate. Нижче наведено фрагмент для project-content.ts:

Тут ми намагаємося показати заголовок, тіло та нижній колонтитул, отримані від батьківського компонента . Якщо якийсь із них не вказаний, наш компонент покаже шаблон за замовчуванням замість нього. Таким чином, створюється високо налаштований компонент.

Щоб використовувати наш нещодавно змінений компонент:

Ось як ми будемо передавати посилання на шаблон до нашого компонента. Якщо будь-який з них не передано, тоді компонент відобразить шаблон за замовчуванням.

ng-content проти * ngTemplateOutlet

Вони обидва допомагають нам досягти високо налаштованих компонентів, але які вибрати і коли?

Чітко видно, що це *ngTemplateOutletдає нам більше можливостей показу шаблону за замовчуванням, якщо жодного не передбачено.

Це не так ng-content. Він робить вміст таким, як є. За допомогою selectатрибута ви можете розділити вміст і відобразити його в різних місцях вашого перегляду . Ви не можете умовно відтворити вміст усередині ng-content. Ви повинні показувати вміст, отриманий від батьків, без жодних засобів для прийняття рішень на основі вмісту.

Однак вибір вибору серед двох цілком залежить від вашого випадку використання. Принаймні зараз *ngTemplateOutletу нашому арсеналі є нова зброя, яка забезпечує більший контроль над вмістом на додаток до функцій ng-content!