Tot ce trebuie să știți despre ng-template, ng-content, ng-container și *ngTemplateOutlet în Angular

iul. 1, 2021
admin

A fost una dintre acele zile în care am fost ocupat să lucrez la noi caracteristici pentru proiectul meu de birou. Dintr-o dată, ceva mi-a atras atenția:

DOM-ul final redat în Angular

În timp ce inspectam DOM-ul am văzut ngcontent fiind aplicat pe elemente de către Angular. Hmm… dacă acestea conțin elementele din DOM-ul final, atunci la ce folosește <ng-container>? În acel moment am făcut confuzie între <ng-container> și <ng-content>.

În căutarea răspunsurilor la întrebările mele am descoperit conceptul de <ng-template>. Spre surprinderea mea, exista și *ngTemplateOutlet. Mi-am început călătoria căutând claritate asupra a două concepte, dar acum aveam patru, care sunau aproape la fel!

Ați fost vreodată în această situație? Dacă da, atunci vă aflați în locul potrivit. Așa că, fără alte discuții, haideți să le luăm pe rând.

<ng-template>

După cum sugerează și numele, <ng-template> este un element de șablon pe care Angular îl folosește cu directive structurale (*ngIf, *ngFor, și directive personalizate).

Aceste elemente de șablon funcționează doar în prezența directivelor structurale. Angular înfășoară elementul gazdă (căruia i se aplică directiva) în interiorul <ng-template> și consumă <ng-template> în DOM-ul finit, înlocuindu-l cu comentarii de diagnosticare.

Considerăm un exemplu simplu de *ngIf:

Exemplu 1- Procesul Angular de interpretare a directivelor structurale

Consemnată mai sus este interpretarea Angular a *ngIf. Angular plasează elementul gazdă căruia i se aplică directiva în <ng-template> și păstrează gazda așa cum este. DOM-ul final este similar cu ceea ce am văzut la începutul acestui articol:

Exemplu 1- DOM redat final

Utilizare:

Am văzut cum folosește Angular <ng-template> dar ce facem dacă vrem să îl folosim? Deoarece aceste elemente funcționează doar cu o directivă structurală, putem scrie ca:

Exemplu 2- Utilizarea <ng-template>

Aici home este o proprietate boolean a componentei setată la valoarea true. Rezultatul codului de mai sus în DOM:

Exemplu 2- DOM redat final

Nimic nu a fost redat! 🙁

Dar de ce nu putem vedea mesajul nostru chiar și după ce am folosit corect <ng-template> cu o directivă structurală?

Acesta era rezultatul așteptat. După cum am discutat deja, Angular înlocuiește <ng-template> cu comentarii de diagnosticare. Fără îndoială, codul de mai sus nu ar genera nicio eroare, deoarece Angular este perfect în regulă cu cazul dumneavoastră de utilizare. Nu veți ajunge niciodată să știți ce s-a întâmplat exact în spatele scenei.

Să comparăm cele două DOM-uri de mai sus care au fost redate de Angular:

Exemplul 1 vs Exemplul 2

Dacă urmăriți cu atenție, există un tag de comentariu în plus în DOM-ul final al Exemplului 2. Codul pe care Angular l-a interpretat a fost:

Procesul de interpretare Angular pentru Exemplul 2

Angular a înfășurat gazda dvs. <ng-template> în alt <ng-template> și a convertit nu numai <ng-template> exteriorul în comentarii de diagnosticare, ci și pe cel interior! Acesta este motivul pentru care nu ați putut vedea niciunul dintre mesajele dumneavoastră.

Pentru a scăpa de acest lucru există două modalități de a obține rezultatul dorit:

Utilizarea corectă a <ng-template>

Metoda 1:

În această metodă, îi furnizați lui Angular formatul de-sugare care nu mai are nevoie de nicio altă prelucrare. De data aceasta, Angular ar converti doar <ng-template> în comentarii, dar lasă conținutul din interiorul lor neatins (nu mai sunt în interiorul niciunui <ng-template>, așa cum era în cazul anterior). Astfel, va reda conținutul în mod corect.

Pentru a afla mai multe despre modul de utilizare a acestui format cu alte directive structurale, consultați acest articol.

Metoda 2:

Este un format destul de inedit și este rar utilizat (utilizarea a două <ng-template> înfrățite). Aici dăm o referință de șablon la *ngIf în then pentru a-i spune ce șablon ar trebui să fie folosit dacă condiția este adevărată.

Utilizarea mai multor <ng-template> ca acesta nu este recomandată (ați putea folosi <ng-container> în schimb), deoarece nu pentru asta sunt destinate. Ele sunt utilizate ca un container pentru șabloane care pot fi reutilizate în mai multe locuri. Vom aborda mai multe despre acest lucru într-o secțiune ulterioară a acestui articol.

<ng-container>

Ați scris sau ați văzut vreodată cod asemănător cu acesta:

Exemplu 1

Motivul pentru care mulți dintre noi scriu acest cod este imposibilitatea de a utiliza mai multe directive structurale pe un singur element gazdă în Angular. Acum, acest cod funcționează bine, dar introduce mai multe <div> goale suplimentare în DOM dacă item.id este o valoare falsă care ar putea să nu fie necesară.

Exemplu 1- DOM redat final

Poate că cineva nu este îngrijorat pentru un exemplu simplu ca acesta, dar pentru o aplicație uriașă care are un DOM complex (pentru a afișa zeci de mii de date) acest lucru ar putea deveni problematic deoarece elementele ar putea avea ascultători atașați la ele care vor fi încă acolo în DOM ascultând evenimente.

Ceea ce este și mai rău este nivelul de anvelopare pe care trebuie să îl faceți pentru a aplica stilizarea (CSS)!

Imagine din: Inside Unbounce

Nu vă faceți griji, avem <ng-container> pentru salvare!

Elementul Angular <ng-container> este un element de grupare care nu interferează cu stilurile sau aspectul, deoarece Angular nu îl pune în DOM.

Așa că dacă scriem Exemplul nostru 1 cu <ng-container>:

Exemplul 1 cu <ng-container>

obținem DOM-ul final ca:

DOM redat final cu <ng-container>

Vezi că am scăpat de acele <div>s goale. Ar trebui să folosim <ng-container> atunci când dorim doar să aplicăm mai multe directive structurale fără a introduce niciun element suplimentar în DOM-ul nostru.

Pentru mai multe informații consultați documentația. Există un alt caz de utilizare în care este folosit pentru a injecta un șablon în mod dinamic într-o pagină. Voi aborda acest caz de utilizare în ultima secțiune a acestui articol.

<ng-content>

Sunt utilizate pentru a crea componente configurabile. Acest lucru înseamnă că componentele pot fi configurate în funcție de nevoile utilizatorului său. Acest lucru este bine cunoscut sub denumirea de proiecție de conținut. Componentele care sunt utilizate în bibliotecile publicate se folosesc de <ng-content> pentru a se face configurabile.

Considerăm o componentă <project-content> simplă:

Exemplu 1- Definiția <project-content>
Proiectarea conținutului cu componenta <project-content>

Conținutul HTML transmis în cadrul etichetelor de deschidere și închidere ale componentei <project-content> este conținutul care urmează să fie proiectat. Aceasta este ceea ce numim proiecție de conținut. Conținutul va fi redat în interiorul <ng-content> din cadrul componentei. Acest lucru permite consumatorului componentei <project-content> să treacă orice subsol personalizat în interiorul componentei și să controleze exact modul în care dorește să fie redat.

Proiecții multiple:

Ce ați face dacă ați putea decide ce conținut ar trebui să fie plasat unde? În loc ca fiecare conținut să fie proiectat în interiorul unui singur <ng-content>, puteți controla, de asemenea, modul în care conținutul va fi proiectat cu atributul select al <ng-content>. Este nevoie de un selector de elemente pentru a decide ce conținut se va proiecta în interiorul unui anumit <ng-content>.

Iată cum:

Exemplu 2- Proiecție multicontenit cu <proiect-content actualizat>

Am modificat definiția <project-content>pentru a realiza proiecția multicontenit. Atributul select selectează tipul de conținut care va fi redat în interiorul unui anumit <ng-content>. Aici avem primul select pentru a reda elementul de antet h1. În cazul în care conținutul proiectat nu are nici un element h1, nu se va reda nimic. În mod similar, al doilea select caută un div. Restul conținutului este redat în interiorul ultimului <ng-content> fără select.

Apelarea componentei va arăta astfel:

Exemplu 2- Apelarea componentei <proiect-content> în componenta părinte

*ngTemplateOutlet

…Acestea sunt folosite ca un container pentru șabloane care pot fi reutilizate în mai multe locuri. Vom aborda mai multe despre acest lucru într-o secțiune ulterioară a acestui articol.
…Există un alt caz de utilizare în care este folosit pentru a injecta un șablon în mod dinamic într-o pagină. Voi acoperi acest caz de utilizare în ultima secțiune a acestui articol.

Aceasta este secțiunea în care vom discuta cele două puncte de mai sus menționate anterior. *ngTemplateOutlet este utilizat pentru două scenarii – pentru a insera un șablon comun în diferite secțiuni ale unei vizualizări, indiferent de bucle sau condiții și pentru a realiza o componentă foarte bine configurată.

Reutilizarea șablonului:

Considerați o vizualizare în care trebuie să inserați un șablon în mai multe locuri. De exemplu, un logo de companie care trebuie plasat în cadrul unui site web. Putem realiza acest lucru scriind șablonul pentru logo o singură dată și reutilizându-l peste tot în cadrul vizualizării.

În cele ce urmează este fragmentul de cod:

Exemplu 1- Reutilizarea șablonului

Cum puteți vedea, am scris șablonul pentru logo o singură dată și l-am folosit de trei ori pe aceeași pagină cu o singură linie de cod!

*ngTemplateOutlet acceptă, de asemenea, un obiect context care poate fi trecut pentru a personaliza ieșirea șablonului comun. Pentru mai multe informații despre obiectul context, consultați documentația oficială.

Componente personalizabile:

Cel de-al doilea caz de utilizare pentru *ngTemplateOutlet este reprezentat de componente foarte personalizate. Luați în considerare exemplul nostru anterior al componentei <project-content>cu unele modificări:

Exemplu 2- Realizarea unei componente personalizabile, project-content.html

Acesta este versiunea modificată a componentei <project-content> care acceptă trei proprietăți de intrare – headerTemplate, bodyTemplate, footerTemplate. Urmează fragmentul pentru project-content.ts:

Exemplu 2- Realizarea componentei personalizabile, project-content.ts

Ceea ce încercăm să realizăm aici este să afișăm antetul, corpul și subsolul așa cum sunt primite de la componenta părinte <project-content>. Dacă unul dintre ele nu este furnizat, componenta noastră va afișa șablonul implicit în locul său. Astfel, creăm o componentă extrem de personalizată.

Pentru a utiliza componenta noastră recent modificată:

Exemplu 2- Utilizarea componentei recent modificate <proiect-content>

Acesta este modul în care vom trece referințele șablonului către componenta noastră. Dacă niciunul dintre ele nu este trecut, atunci componenta va reda șablonul implicit.

ng-content vs. *ngTemplateOutlet

Ambele ne ajută să obținem componente foarte personalizate, dar pe care să le alegem și când?

Se poate vedea clar că *ngTemplateOutlet ne oferă ceva mai multă putere de a afișa șablonul implicit dacă nu este furnizat niciunul.

Nu este cazul cu ng-content. Acesta redă conținutul așa cum este. La maxim, puteți împărți conținutul și le puteți reda în diferite locații ale vizualizării cu ajutorul atributului select. Nu puteți reda condiționat conținutul în cadrul ng-content. Trebuie să afișați conținutul care este primit de la părinte fără a avea posibilitatea de a lua decizii pe baza conținutului.

Cu toate acestea, alegerea de a selecta dintre cele două depinde complet de cazul de utilizare. Cel puțin acum avem o nouă armă *ngTemplateOutlet în arsenalul nostru, care oferă mai mult control asupra conținutului în plus față de caracteristicile lui ng-content!

Lasă un răspuns

Adresa ta de email nu va fi publicată.