18/03/2011
Angular, et af de mest populære frameworks til at bygge dynamiske webapplikationer, er fyldt med kraftfulde værktøjer, der forenkler udviklingsprocessen. Et af de mest fundamentale og hyppigt anvendte værktøjer i enhver Angular-udviklers arsenal er *ngIf-direktivet. Dette direktiv giver os mulighed for betinget at tilføje eller fjerne elementer fra DOM'en (Document Object Model), hvilket gør vores brugergrænseflader interaktive og responsive over for dataændringer. At forstå, hvordan *ngIf fungerer, inklusiv dets mere avancerede funktioner og faldgruber, er afgørende for at skrive ren og effektiv Angular-kode.
Hvad er *ngIf? Et Strukturelt Direktiv
*ngIf er et strukturelt direktiv. Det betyder, at det har magten til at ændre DOM'ens layout ved at tilføje, fjerne eller manipulere elementer. Navnet i sig selv giver et hint om dets funktion: 'ng' er præfikset for alt, der er en del af Angular-kernen, og 'If' repræsenterer den betingede logik, det udfører. Når udtrykket, der er bundet til *ngIf, evalueres til true, vil det element, som direktivet er knyttet til (og dets underordnede elementer), blive gengivet i DOM'en. Hvis udtrykket evalueres til false, fjernes elementet fuldstændigt fra DOM'en.
Et simpelt eksempel kunne være at vise en velkomstbesked til en bruger, der er logget ind:
<div *ngIf="brugerErLoggetInd"> <h2>Velkommen tilbage, {{ brugernavn }}!</h2> </div>I dette tilfælde vil <div>-elementet kun eksistere i browseren, hvis variablen brugerErLoggetInd i den tilsvarende komponent er sand.
Mysteriet om Stjernen (*)
Et almindeligt spørgsmål for nye Angular-udviklere er: Hvorfor er der en stjerne (*) foran ngIf? Stjernen er en bekvem genvej, eller syntaktisk sukker, som Angular tilbyder for strukturelle direktiver. Bag kulisserne omdanner Angular denne stjernesyntaks til en mere detaljeret struktur, der bruger <ng-template>-elementet.
Den kode, vi så før:
<div *ngIf="brugerErLoggetInd">...</div>Bliver internt omdannet af Angular til noget i denne stil:
<ng-template [ngIf]="brugerErLoggetInd"> <div>...</div> </ng-template><ng-template> er et Angular-element, der indeholder indhold, som ikke gengives direkte. I stedet fungerer det som en skabelon, som *ngIf-direktivet kan bruge til at instantiere visningen, når betingelsen er opfyldt. At forstå dette koncept er nøglen til at låse op for mere avancerede anvendelser af *ngIf, såsom else-blokke.
Håndtering af 'else'-tilfælde
Ofte ønsker vi ikke kun at vise noget, når en betingelse er sand, men også at vise noget andet, når den er falsk. *ngIf understøtter dette elegant med en else-klausul. For at bruge den skal vi definere en <ng-template> og give den en referencevariabel (f.eks. #ellersBlok).
<!-- Vises hvis brugerErLoggetInd er sand --> <div *ngIf="brugerErLoggetInd; else ellersBlok"> <p>Du er logget ind.</p> <button (click)="logUd()">Log ud</button> </div> <!-- Vises hvis brugerErLoggetInd er falsk --> <ng-template #ellersBlok> <p>Log venligst ind for at fortsætte.</p> <button (click)="logInd()">Log ind</button> </ng-template>Dette mønster er ekstremt nyttigt for at skifte mellem forskellige visningstilstande i en komponent uden at skulle skrive kompleks logik.
Udfordringen: Bitvise Operatorer i *ngIf-udtryk
En interessant begrænsning i Angulars skabelon-parser er, at den ikke understøtter alle JavaScript-operatorer. Et specifikt eksempel, som udviklere ofte støder på, er den bitvise AND-operator (&). Lad os sige, du arbejder med bit-flag og vil tjekke, om et bestemt flag er sat:
<!-- Dette vil forårsage en fejl! --> <div *ngIf="vaerdi & 2"> Dette flag er aktivt. </div>Hvis vaerdi er 3 (binært 11), skulle 3 & 2 (binært 11 & 10) resultere i 2 (binært 10), hvilket er en 'truthy' værdi. Man ville forvente, at <div>-elementet blev vist. I stedet kaster Angular en 'Template parse error'.
Hvorfor sker dette? Angulars udtryksparser er designet til at være sikker og forudsigelig og understøtter bevidst kun et undersæt af JavaScripts funktionalitet. Bitvise operatorer er ikke en del af dette undersæt.
Løsningen: Flyt Logikken til Komponenten
Den bedste praksis og den korrekte løsning på dette problem er at flytte den logiske operation ud af skabelonen og ind i komponentens TypeScript-fil. Opret en simpel metode i din komponent, der udfører den bitvise operation.
I din komponent.ts:
import { Component } from '@angular/core'; @Component({ selector: 'app-min-komponent', templateUrl: './min-komponent.html' }) export class MinKomponent { vaerdi = 3; checkFlag(value: number, flag: number): boolean { return (value & flag) !== 0; } } Og i din komponent.html kan du nu kalde denne metode:
<!-- Dette virker perfekt --> <div *ngIf="checkFlag(vaerdi, 2)"> Dette flag er aktivt. </div>Denne tilgang har flere fordele: Den holder din skabelon ren og deklarativ, gør logikken testbar og omgår begrænsningerne i skabelon-parseren. Det er en generel regel, at kompleks logik hører hjemme i komponenten, ikke i HTML'en.
En anden almindelig kilde til forvirring er forskellen mellem *ngIf og [hidden]-attributten. Selvom de begge kan bruges til at skjule og vise elementer, gør de det på fundamentalt forskellige måder, hvilket har betydning for ydeevne og adfærd.
| Egenskab | *ngIf="false" | [hidden]="true" |
|---|---|---|
| DOM-manipulation | Elementet og dets børn fjernes fuldstændigt fra DOM'en. | Elementet forbliver i DOM'en, men får CSS-stilen display: none;. |
| Ydeevne ved skift | Kan være dyrere for komplekse elementer, da de skal destrueres og genskabes. | Meget hurtigt, da det kun er en CSS-ændring. |
| Indledende indlæsningstid | Hurtigere, hvis elementet ikke vises fra start, da det ikke bliver behandlet. | Elementet bliver altid gengivet og indlæst, selvom det er skjult. |
| Anvendelsesscenarie | Ideel til elementer, der ikke vises ofte, eller som er ressourcekrævende at gengive. Fx en modal-dialog. | Perfekt til elementer, der skifter synlighed ofte, som f.eks. en fanebladsvisning eller en dropdown-menu. |
Ofte Stillede Spørgsmål (FAQ)
Den største forskel er, at *ngIf fjerner elementet fra DOM'en, mens [hidden] blot skjuler det med CSS. Dette påvirker ydeevne og ressourceforbrug. Brug *ngIf, når et element ikke skal eksistere, og [hidden], når det blot skal være midlertidigt usynligt.
Kan jeg bruge 'async' pipe med *ngIf?
Ja, absolut! At kombinere *ngIf med async-pipen er en af de mest kraftfulde måder at håndtere observables i Angular-skabeloner. Det abonnerer automatisk på observable'en og afmelder sig, når komponenten destrueres, hvilket forhindrer memory leaks.
<div *ngIf="data$ | async as data"> Viser data: {{ data.navn }} </div>Hvorfor virker min bitvise OR-operator (|) heller ikke?
Af samme grund som den bitvise AND-operator (&). Angulars skabelon-parser understøtter ikke bitvise operatorer. Løsningen er den samme: Opret en metode i din komponent, der udfører operationen, og kald den fra din skabelon.
Konklusion
*ngIf er mere end blot en simpel betinget switch. Det er et robust, strukturelt direktiv, der giver os finmasket kontrol over DOM'en. Ved at forstå, hvordan stjernesyntaksen fungerer som syntaktisk sukker for <ng-template>, kan vi udnytte avancerede funktioner som else-blokke. Lige så vigtigt er det at anerkende dets begrænsninger, såsom manglende understøttelse for bitvise operatorer, og vide, at den bedste løsning er at flytte logik til komponenten. At mestre *ngIf og vide, hvornår man skal bruge det i forhold til alternativer som [hidden], er et afgørende skridt på vejen til at blive en effektiv og kyndig Angular-udvikler.
Hvis du vil læse andre artikler, der ligner Dybdegående Guide til *ngIf i Angular, kan du besøge kategorien Sundhed.
