Vše, co potřebujete vědět o ng-template, ng-content, ng-container a *ngTemplateOutlet v Angularu

Čvc 1, 2021
admin

Byl to jeden z těch dnů, kdy jsem pracoval na nových funkcích pro svůj kancelářský projekt. Najednou mě něco zaujalo:

Finální vykreslený DOM v Angularu

Při kontrole DOMu jsem viděl, že na elementy Angular aplikuje ngcontent. Hmm… pokud obsahují prvky ve finálním DOM, k čemu je potom <ng-container>? Tehdy jsem si spletl <ng-container> a <ng-content>.

Při hledání odpovědí na své otázky jsem objevil pojem <ng-template>. K mému překvapení existoval také *ngTemplateOutlet. Na začátku své cesty jsem hledal jasno ve dvou pojmech, ale nyní jsem měl čtyři, které zněly téměř stejně!“

Jste někdy v takové situaci? Pokud ano, pak jste na správném místě. Pojďme si je tedy bez dalšího rozebírat jeden po druhém.

<ng-template>

Jak název napovídá, <ng-template> je šablonový prvek, který Angular používá se strukturálními direktivami (*ngIf, *ngFor, a vlastními direktivami).

Tyto šablonové prvky fungují pouze v přítomnosti strukturálních direktiv. Angular zabalí hostitelský prvek (na který se směrnice aplikuje) dovnitř <ng-template> a spotřebuje <ng-template> v hotovém DOM tak, že jej nahradí diagnostickými komentáři.

Podívejte se na jednoduchý příklad *ngIf:

Příklad 1- Angular proces interpretace strukturálních směrnic

Výše je zobrazena interpretace *ngIf v jazyce Angular. Angular umístí hostitelský prvek, na který je směrnice aplikována, do <ng-template> a hostitelský prvek ponechá tak, jak je. Konečný DOM je podobný tomu, který jsme viděli na začátku tohoto článku:

Příklad 1- Konečný vykreslený DOM

Použití:

Viděli jsme, jak Angular používá <ng-template>, ale co když ho chceme použít? Protože tyto prvky pracují pouze se strukturální direktivou, můžeme je zapsat jako:

Příklad 2- Použití <ng-template>

Zde home je boolean vlastnost komponenty nastavená na hodnotu true. Výstup výše uvedeného kódu v DOM:

Příklad 2- Konečné vykreslení DOM

Nic se nevytvořilo! 🙁

Ale proč se naše zpráva nezobrazí ani po správném použití <ng-template> se strukturní direktivou?“

Tento výsledek byl očekávaný. Jak jsme si již řekli, Angular nahrazuje <ng-template> diagnostickými komentáři. Není pochyb o tom, že výše uvedený kód by nevygeneroval žádnou chybu, protože Angular je s vaším případem použití naprosto v pořádku. Nikdy byste se nedozvěděli, co přesně se stalo v zákulisí.

Pokusme se porovnat výše uvedené dva DOMy, které byly vykresleny systémem Angular:

Příklad 1 vs. Příklad 2

Pokud budete pozorně sledovat, ve finálním DOMu příkladu 2 je jedna značka komentáře navíc. Kód, který Angular interpretoval, byl:

Proces interpretace Angularu pro Příklad 2

Angular zabalil váš hostitelský <ng-template> do dalšího <ng-template> a převedl na diagnostické komentáře nejen vnější <ng-template>, ale také vnitřní! Proto jste nemohli vidět žádnou ze svých zpráv.

Abyste se toho zbavili, existují dva způsoby, jak dosáhnout požadovaného výsledku:

Správné použití <ng-šablony>

Způsob 1:

Při tomto způsobu poskytujete Angularu odcukrovaný formát, který nepotřebuje žádné další zpracování. Tentokrát by Angular pouze převedl <ng-template> na komentáře, ale obsah uvnitř nich ponechá nedotčený (nejsou již uvnitř žádného <ng-template> jako v předchozím případě). Obsah tedy vykreslí správně.

Chcete-li se dozvědět více o použití tohoto formátu s dalšími strukturálními direktivami, přečtěte si tento článek.

Způsob 2:

Tento formát je poměrně nevídaný a používá se jen zřídka (používá dva sourozenecké <ng-template>). Zde dáváme odkaz na šablonu *ngIf v jejím then, abychom jí řekli, která šablona má být použita, pokud je podmínka pravdivá.

Používání více <ng-template> tímto způsobem se nedoporučuje (místo toho můžete použít <ng-container>), protože k tomu nejsou určeny. Používají se jako kontejner k šablonám, které lze opakovaně použít na více místech. Více se tomu budeme věnovat v pozdější části tohoto článku.

<ng-container>

Napsali jste někdy nebo viděli kód podobný tomuto:

Příklad 1

Důvodem, proč mnozí z nás píší tento kód, je nemožnost použít více strukturálních direktiv na jeden hostitelský prvek v systému Angular. Nyní tento kód funguje dobře, ale zavádí do DOM několik dalších prázdných <div>, pokud je item.id falsy hodnota, která nemusí být nutná.

Příklad 1- Konečný vykreslený DOM

U jednoduchého příkladu, jako je tento, to nemusí nikoho trápit, ale u obrovské aplikace, která má složitý DOM (pro zobrazení desítek tisíc dat), to může začít být problematické, protože prvky mohou mít připojené posluchače, kteří tam budou stále v DOM naslouchat událostem.

Ještě horší je úroveň vnoření, kterou musíte udělat, abyste mohli použít stylování (CSS)!

Obrázek z: Inside Unbounce

Nic se neděje, na pomoc máme <ng-container>!“

Angular <ng-container> je seskupovací prvek, který nezasahuje do stylů ani rozvržení, protože jej Angular neumisťuje do DOM.

Zapíšeme-li tedy náš Příklad 1 s <ng-container>:

Příklad 1 s <ng-container>

, dostaneme výsledný DOM jako:

Finální vykreslený DOM s <ng-container>

Vidíme, že jsme se zbavili těch prázdných <div>. <ng-container> Měli bychom použít <ng-container>, když chceme pouze aplikovat více strukturních direktiv, aniž bychom do našeho DOM zavedli nějaký další prvek.

Další informace najdete v dokumentaci. Existuje ještě jeden případ použití, kdy se používá k dynamickému injektování šablony do stránky. Tomuto případu použití se budu věnovat v poslední části tohoto článku.

<ng-content>

Slouží k vytváření konfigurovatelných komponent. To znamená, že komponenty lze konfigurovat v závislosti na potřebách jejich uživatele. To je dobře známo jako promítání obsahu. Komponenty, které se používají v publikovaných knihovnách, využívají <ng-content>, aby byly konfigurovatelné.

Podívejme se na jednoduchou komponentu <project-content>:

Příklad 1- <project-content> definice
Projekce obsahu pomocí komponenty <project-content>

Obsah HTML předaný v úvodní a závěrečné značce komponenty <project-content> je obsah, který se má promítnout. Tomu říkáme promítání obsahu. Obsah bude vykreslen uvnitř <ng-content> v rámci komponenty. To umožňuje spotřebiteli komponenty <project-content> předat v rámci komponenty libovolnou vlastní patičku a přesně řídit, jak ji chce vykreslit.

Vícenásobné promítání:

Co kdybyste mohli rozhodnout, který obsah má být umístěn kde? Místo toho, aby se každý obsah promítal uvnitř jednoho atributu <ng-content>, můžete také řídit, jak se bude obsah promítat pomocí atributu select <ng-content>. O tom, který obsah se promítne uvnitř konkrétního <ng-content>, rozhoduje selektor prvku.

Podívejte se, jak na to:

Příklad 2- Promítání více obsahů s aktualizovaným <project-content>

Upravili jsme definici <project-content>, aby bylo možné provádět promítání více obsahů. Atribut select vybírá typ obsahu, který bude vykreslen uvnitř konkrétního <ng-content>. Zde máme jako první select pro vykreslení záhlaví prvku h1. Pokud promítaný obsah nemá žádný prvek h1, nebude se vykreslovat nic. Podobně druhý select hledá prvek div. Zbytek obsahu se vykreslí uvnitř posledního <ng-content> bez select.

Volání komponenty bude vypadat takto:

Příklad 2- Volání komponenty <project-content> v nadřazené komponentě

*ngTemplateOutlet

…Používají se jako kontejner na šablony, které lze opakovaně použít na více místech. Více se tomu budeme věnovat v některé z dalších částí tohoto článku.
…Existuje ještě jeden případ použití, kdy se používá k dynamickému injektování šablony do stránky. Tomuto případu použití se budu věnovat v poslední části tohoto článku.

V této části se budeme zabývat dvěma výše zmíněnými body. *ngTemplateOutlet Používá se pro dva scénáře – pro vložení společné šablony do různých částí pohledu bez ohledu na smyčky nebo podmínky a pro vytvoření vysoce konfigurovatelné komponenty.

Znovupoužití šablony:

Považujte pohled, kde je třeba vložit šablonu na více místech. Například logo společnosti, které má být umístěno v rámci webové stránky. Toho můžeme dosáhnout tak, že šablonu pro logo napíšeme jednou a opakovaně ji použijeme všude v rámci zobrazení.

Následuje úryvek kódu:

Příklad 1- Opakované použití šablony

Jak vidíte, šablonu pro logo jsme napsali pouze jednou a třikrát ji použili na téže stránce pomocí jediného řádku kódu!

*ngTemplateOutlet Také přijímá kontextový objekt, který lze předat pro přizpůsobení společného výstupu šablony. Další informace o kontextovém objektu najdete v oficiálních dokumentech.

Přizpůsobitelné komponenty:

Druhým případem použití *ngTemplateOutlet jsou vysoce přizpůsobitelné komponenty. Uvažujme náš předchozí příklad komponenty <project-content> s určitými úpravami:

Příklad 2- Vytvoření přizpůsobitelné komponenty, project-content.html

Výše je upravená verze komponenty <project-content>, která přijímá tři vstupní vlastnosti – headerTemplate, bodyTemplate, footerTemplate. Následuje úryvek pro project-content.ts:

Příklad 2- Vytvoření přizpůsobitelné komponenty, project-content.ts

Co se zde snažíme dosáhnout, je zobrazení záhlaví, těla a zápatí tak, jak je obdržíme od nadřazené komponenty <project-content>. Pokud některá z nich není poskytnuta, naše komponenta místo ní zobrazí výchozí šablonu. Vytvoříme tak vysoce přizpůsobenou komponentu.

Pro použití naší nedávno upravené komponenty:

Příklad 2- Použití nově upravené komponenty <project-content>

Takto budeme předávat ref. šablony naší komponentě. Pokud některou z nich nepředáme, bude komponenta vykreslovat výchozí šablonu.

ng-content vs. *ngTemplateOutlet

Oboje nám pomůže dosáhnout vysoce přizpůsobené komponenty, ale kterou zvolit a kdy?

Je jasně vidět, že *ngTemplateOutlet nám dává o něco větší sílu zobrazit výchozí šablonu, pokud žádná není poskytnuta.

To není případ ng-content. Ta vykresluje obsah tak, jak je. Maximálně můžete obsah rozdělit a vykreslit je na různých místech zobrazení pomocí atributu select. V rámci ng-content nelze obsah podmíněně vykreslit. Musíte zobrazit obsah, který je přijat od nadřazeného prvku, bez možnosti rozhodování na základě obsahu.

Výběr výběru mezi těmito dvěma způsoby však zcela závisí na vašem případu použití. Alespoň teď máme v arzenálu novou zbraň *ngTemplateOutlet, která kromě funkcí ng-content poskytuje větší kontrolu nad obsahem!

.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.