Alles wat u moet weten over ng-template, ng-content, ng-container, en *ngTemplateOutlet in Angular

jul 1, 2021
admin

Het was een van die dagen dat ik druk bezig was met nieuwe functies voor mijn kantoorproject. Plotseling trok iets mijn aandacht:

Eindig gerenderde DOM in Angular

Tijdens het inspecteren van de DOM zag ik de ngcontent die door Angular op elementen werd toegepast. Hmm… als ze de elementen in het uiteindelijke DOM bevatten, wat is dan het nut van <ng-container>? Op dat moment raakte ik in de war tussen <ng-container> en <ng-content>.

In de zoektocht naar de antwoorden op mijn vragen ontdekte ik het concept van <ng-template>. Tot mijn verbazing was er ook *ngTemplateOutlet. Ik begon mijn reis op zoek naar duidelijkheid over twee concepten, maar nu had ik er vier, die bijna hetzelfde klonken!

Heb je ooit in deze situatie verkeerd? Zo ja, dan bent u op de juiste plaats. Dus laten we ze zonder verder oponthoud één voor één behandelen.

<ng-template>

Zoals de naam al doet vermoeden is de <ng-template> een template element dat Angular gebruikt met structurele directives (*ngIf, *ngFor, en aangepaste directives).

Deze template elementen werken alleen in de aanwezigheid van structurele directives. Angular verpakt het host-element (waarop de directive wordt toegepast) in <ng-template> en consumeert de <ng-template> in het voltooide DOM door het te vervangen door diagnostisch commentaar.

Overweeg een eenvoudig voorbeeld van *ngIf:

Voorbeeld 1- Angular-proces van interpretatie van structurele directives

Hierboven is de Angular-interpretatie van *ngIf te zien. Angular plaatst het host-element waarop de directive wordt toegepast binnen <ng-template> en houdt de host zoals die is. Het uiteindelijke DOM is vergelijkbaar met wat we aan het begin van dit artikel hebben gezien:

Example 1- Definitief gerenderde DOM

Gebruik:

We hebben gezien hoe Angular <ng-template> gebruikt, maar wat als we het willen gebruiken? Aangezien deze elementen alleen werken met een structurele richtlijn, kunnen we schrijven als:

Exemplaar 2-het gebruik van <ng-template>

Hierbij is home een boolean eigenschap van de component die is ingesteld op true waarde. De uitvoer van de bovenstaande code in DOM:

Voorbeeld 2- Definitief gerenderde DOM

Niets gerendered!

Maar waarom zien we ons bericht niet, zelfs niet nadat we <ng-template> correct hebben gebruikt met een structurele richtlijn?

Dit was het verwachte resultaat. Zoals we al hebben besproken, vervangt Angular de <ng-template> door diagnostisch commentaar. Ongetwijfeld zou de bovenstaande code geen fout genereren, omdat Angular perfect in orde is met uw use case. U zou nooit te weten komen wat er achter de schermen precies is gebeurd.

Laten we de twee bovenstaande DOMs eens vergelijken die door Angular zijn gerenderd:

Voorbeeld 1 vs. Voorbeeld 2

Als u goed kijkt, ziet u één extra commentaartag in de uiteindelijke DOM van Voorbeeld 2. De code die Angular heeft geïnterpreteerd was:

Angular interpretatieproces voor Voorbeeld 2

Angular heeft uw host <ng-template> binnen een andere <ng-template> ingepakt en niet alleen de buitenste <ng-template> naar diagnostisch commentaar geconverteerd, maar ook de binnenste! Daarom kon u geen enkel bericht zien.

Om dit te verhelpen zijn er twee manieren om het gewenste resultaat te bereiken:

Correct gebruik van <ng-template>

Methode 1:

In deze methode voorziet u Angular van het ontsmette format dat geen verdere bewerking behoeft. Deze keer zet Angular <ng-template> alleen om in commentaar, maar laat de inhoud ongemoeid (deze staat niet meer in een <ng-template>, zoals in het vorige geval). De inhoud wordt dus correct weergegeven.

Om meer te weten te komen over het gebruik van dit formaat met andere structurele directives, zie dit artikel.

Methode 2:

Dit is een vrij ongezien formaat en wordt zelden gebruikt (met behulp van twee sibling <ng-template>). Hier geven we een sjabloon verwijzing naar de *ngIf in zijn then om te vertellen welk sjabloon moet worden gebruikt als de voorwaarde waar is.

Het gebruik van meerdere <ng-template> zoals deze wordt niet aangeraden (u zou <ng-container> in plaats daarvan kunnen gebruiken), omdat dit niet is waar ze voor bedoeld zijn. Ze worden gebruikt als een container voor sjablonen die op meerdere plaatsen hergebruikt kunnen worden. We zullen hier later in dit artikel meer over vertellen.

<ng-container>

Heb je ooit code geschreven of gezien die hierop lijkt:

Example 1

De reden waarom velen van ons deze code schrijven, is de onmogelijkheid om meerdere structural directives op een enkel host-element te gebruiken in Angular. Nu werkt deze code prima, maar het introduceert een aantal extra lege <div> in de DOM als item.id een falsy waarde is die misschien niet nodig is.

Voorbeeld 1- Definitief gerenderde DOM

In een eenvoudig voorbeeld als dit hoeft u zich geen zorgen te maken, maar voor een enorme toepassing met een complexe DOM (om tienduizenden gegevens weer te geven) kan dit lastig worden omdat er luisteraars aan de elementen kunnen zijn gekoppeld die nog steeds in de DOM naar gebeurtenissen luisteren.

Wat nog erger is, is het niveau van nesting dat u moet doen om uw styling (CSS) toe te passen!

Beeld van: Inside Unbounce

Geen zorgen, we hebben <ng-container> om te redden!

De Angular <ng-container> is een groeperingselement dat niet interfereert met stijlen of lay-out omdat Angular het niet in het DOM plaatst.

Als we dus ons Voorbeeld 1 met <ng-container> schrijven:

Voorbeeld 1 met <ng-container>

We krijgen het uiteindelijke DOM als:

Eindresultaat met <ng-container>

Zie dat we die lege <div>s hebben verwijderd. We zouden <ng-container> moeten gebruiken wanneer we meerdere structurele directieven willen toepassen zonder een extra element in ons DOM te introduceren.

Voor meer informatie verwijzen we naar de docs. Er is nog een use case waar het gebruikt wordt om een template dynamisch in een pagina te injecteren. Ik zal dit gebruik in de laatste sectie van dit artikel behandelen.

<ng-content>

Ze worden gebruikt om configureerbare componenten te maken. Dit betekent dat de componenten kunnen worden geconfigureerd afhankelijk van de behoeften van de gebruiker. Dit staat bekend als Content Projection. Componenten die worden gebruikt in gepubliceerde bibliotheken maken gebruik van <ng-content> om zichzelf configureerbaar te maken.

Zie een eenvoudige <project-content>-component:

Voorbeeld 1- <project-content>-definitie
Contentprojectie met <project-content>-component

De HTML-inhoud die binnen de openings- en sluit-tags van <project-content>-component wordt doorgegeven, is de inhoud die moet worden geprojecteerd. Dit is wat we Content Projection noemen. De inhoud zal worden weergegeven binnen de <ng-content> binnen de component. Hierdoor kan de gebruiker van het <project-content> component elke aangepaste footer binnen het component doorgeven en precies bepalen hoe hij wil dat deze wordt weergegeven.

Meervoudige projecties:

Wat als je zou kunnen beslissen welke inhoud waar moet worden geplaatst? In plaats van elke inhoud te projecteren binnen een enkele <ng-content>, kunt u ook bepalen hoe de inhoud wordt geprojecteerd met het select attribuut van <ng-content>. Er is een element selector nodig om te beslissen welke inhoud binnen een bepaalde <ng-content> wordt geprojecteerd.

Hier ziet u hoe:

Voorbeeld 2- projectie van meerdere inhoudsdelen met bijgewerkte <project-content>

We hebben de <project-content>-definitie gewijzigd om projectie van meerdere inhoudsdelen mogelijk te maken. Het select-attribuut selecteert het type inhoud dat binnen een bepaalde <ng-content> zal worden weergegeven. Hier hebben we eerst select om header h1 element te renderen. Als de geprojecteerde inhoud geen h1 element heeft zal het niets renderen. Op dezelfde manier zoekt de tweede select naar een div. De rest van de inhoud wordt weergegeven in de laatste <ng-content> zonder select.

Het aanroepen van de component ziet er als volgt uit:

Exemplaar 2- Aanroepen van <project-content> component in parent component

*ngTemplateOutlet

…Ze worden gebruikt als een container voor sjablonen die op meerdere plaatsen kunnen worden hergebruikt. We zullen hier later in dit artikel meer over vertellen.
…Er is nog een use case waar het gebruikt wordt om een template dynamisch in een pagina te injecteren. Ik zal deze use case in de laatste sectie van dit artikel behandelen.

Dit is de sectie waar we de twee eerder genoemde punten zullen bespreken. *ngTemplateOutlet wordt gebruikt voor twee scenario’s – om een gemeenschappelijk sjabloon in te voegen in verschillende secties van een view ongeacht lussen of conditie en om een hoog geconfigureerde component te maken.

Template hergebruik:

Bedenk een view waar je een sjabloon op meerdere plaatsen moet invoegen. Bijvoorbeeld een bedrijfslogo dat binnen een website moet worden geplaatst. We kunnen dit bereiken door het sjabloon voor het logo eenmaal te schrijven en het overal binnen de weergave te hergebruiken.

Hierna volgt een stukje code:

Voorbeeld 1- Hergebruik van sjablonen

Zoals u kunt zien, hebben we het logosjabloon eenmaal geschreven en het driemaal op dezelfde pagina gebruikt met slechts één regel code.

*ngTemplateOutlet accepteert ook een contextobject dat kan worden doorgegeven om de gemeenschappelijke sjabloonuitvoer aan te passen. Meer informatie over het context-object vindt u in de officiële documenten.

Aanpasbare componenten:

Het tweede gebruikscasus voor *ngTemplateOutlet is sterk aangepaste componenten. Bekijk ons vorige voorbeeld van <project-content>-component met enkele wijzigingen:

Voorbeeld 2- Aanpasbare component maken, project-content.html

Hierboven ziet u de gewijzigde versie van <project-content>-component die drie invoereigenschappen accepteert – headerTemplate, bodyTemplate, footerTemplate. Hieronder volgt het knipsel voor project-content.ts:

Voorbeeld 2- Aanpasbare component maken, project-content.ts

Wat we hier proberen te bereiken, is om de header, body en footer weer te geven zoals deze zijn ontvangen van de bovenliggende component van <project-content>. Als een van deze elementen niet is voorzien, toont onze component het standaardsjabloon in plaats daarvan. Op deze manier wordt een zeer aangepaste component gecreëerd.

Om onze onlangs gewijzigde component te gebruiken:

Exemplaar 2-Het gebruik van de onlangs gewijzigde component <project-content>

Op deze manier gaan we de sjabloonrefs doorgeven aan onze component.

ng-content vs. *ngTemplateOutlet

Beiden helpen ons om componenten met een hoge mate van maatwerk te maken, maar welke te kiezen en wanneer?

Het is duidelijk te zien dat *ngTemplateOutlet ons wat meer macht geeft om het standaard sjabloon te tonen als er geen is opgegeven.

Dit is niet het geval met ng-content. Het rendert de inhoud zoals die is. Je kunt de inhoud maximaal opsplitsen en op verschillende plaatsen in je view renderen met behulp van select attribuut. U kunt de inhoud niet voorwaardelijk renderen binnen ng-content. Je moet de inhoud tonen die van de ouder wordt ontvangen, zonder de mogelijkheid om beslissingen te nemen op basis van de inhoud.

Hoe dan ook, de keuze tussen de twee hangt volledig af van je use case. In ieder geval hebben we nu een nieuw wapen *ngTemplateOutlet in ons arsenaal dat meer controle over de inhoud biedt naast de mogelijkheden van ng-content!

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.