I modsætning til andre JavaScript-rammeværk som Backbone eller React, hvor udvikleren eksplicit skal kalde en render-metode for at bearbejde HTML-skabeloner, håndteres denne proces automatisk og gennemskueligt i Angular. En af de primære kendetegn ved Angular er binding, som adskiller en MVC-applikation fra en MVVM-applikation. I Angular er komponenten den mest grundlæggende enhed. En komponent kombinerer en JavaScript-klasse skrevet i TypeScript og en Angular-skabelon skrevet i HTML, CSS og TypeScript til én samlet enhed. Klassen og skabelonen forbindes via bindings, så de kan kommunikere med hinanden som et puslespil, hvor hver del har sin plads.

Klasser, som er en del af objektorienteret programmering (OOP), spiller en central rolle i Angular. Hvis du tager dig tid til at forstå OOP-paradigmet på et dybere niveau, vil du betydeligt forbedre din forståelse af, hvordan Angular fungerer. OOP-paradigmet tillader Dependency Injection (DI) af afhængige services i dine komponenter, hvilket betyder, at du kan lave HTTP-kald eller udløse beskeder til brugeren uden at trække denne logik ind i selve komponenten eller duplikere din kode. DI gør det lettere for udviklere at bruge flere indbyrdes afhængige services uden at bekymre sig om rækkefølgen af oprettelsen, initialisering eller destruktion af objekterne i hukommelsen.

Angular-skabeloner muliggør også genbrug af kode gennem direktiver, pipes, brugerdefinerede kontroller og andre komponenter. Dette er stykker af kode, som indkapsler interaktiv kode for slutbrugeren. Denne interaktive kode er ofte kompleks og svær at forstå og bør derfor holdes adskilt fra forretningslogik eller præsentationslogik for at bevare vedligeholdelsen af koden. Med introduktionen af Angular 17 er der blevet lanceret en ny kontrolstrømsyntaks, der erstatter direktiver som *ngIf med @if, *ngFor med @for og *ngSwitch med @switch, samt introducerer @empty, @defer, kontekstuelle variabler og betingede udsagn. Denne nye syntaks gør skabeloner nemmere at læse og undgår, at gamle direktiver skal importeres til hver komponent i et selvstændigt projekt. I denne bog vil vi udelukkende bruge denne nye kontrolstrømsyntaks.

Angular-applikationer kan oprettes på to forskellige måder: enten som et NgModule-projekt eller som et selvstændigt projekt. Fra Angular 17 er den anbefalede tilgang at oprette din app som et selvstændigt projekt. Denne tilgang har mange fordele, som forklaret i afsnittet om Angular Router nedenfor. Der er mange nye begreber at lære, men moduler som koncept er ikke forsvundet. De er bare ikke længere nødvendige. Uanset om din app starter med bootstrapApplication eller bootstrapModule, vil Angular-komponenter, services, direktiver, pipes og brugerdefinerede kontroller blive givet til bootstrapApplication-funktionen eller organiseret under moduler. Konfigurationen på rotniveau gengiver din første komponent, injicerer de nødvendige services og forbereder eventuelle afhængigheder.

I et selvstændigt projekt kan du lade individuelle komponenter blive lazy-loaded. Du kan også introducere feature-moduler for at lazy-loade grupper af services og komponenter. Alle disse funktioner hjælper med at få appen til at indlæse hurtigt, hvilket forbedrer First Contentful Paint-tiderne, da rammeværket ikke behøver at downloade og indlæse alle webapplikationens komponenter samtidig. For eksempel ville det være spild af ressourcer at sende kode for et administrativt dashboard til en bruger uden administratorrettigheder. Muligheden for at oprette selvstændige komponenter giver os mulighed for at undgå oprettelsen af unødvendige moduler. Tidligere var du tvunget til at placere delte komponenter i et delt modul, hvilket kunne føre til ineffektivitet og større app-størrelser, da udviklere ikke nødvendigvis ville oprette et modul for hver delt komponent. Et eksempel på dette er LocalCast Weather appen, der er en simpel app, der ikke profiterer på modulkonceptet, mens LemonMart appen naturligt afspejler en modulær arkitektur ved at implementere separate forretningsfunktioner i forskellige moduler.

Selvstændige komponenter bør ikke forveksles med Angular-elements, som er en implementering af webstandarden for brugerdefinerede elementer (også kaldet Web Components). Hvis du implementerer komponenter på denne måde, ville det kræve, at Angular-rammeværket reduceres til kun et par KB i størrelse, mod de nuværende omkring 150 KB. Hvis dette lykkes, vil du kunne bruge en Angular-komponent, du udvikler, i enhver webapplikation.

Angular gør intens brug af RxJS-biblioteket, som introducerer reaktive udviklingsmønstre i Angular i stedet for de mere traditionelle imperative udviklingsmønstre. Angular understøtter flere programmeringsstile, og mangfoldigheden af kodningsstile i Angular er en af årsagerne til, at rammeværket er tilgængeligt for programmører med forskellige baggrunde. Uanset om du kommer fra en objektorienteret programmeringsbaggrund eller er en stor tilhænger af funktionel programmering, kan du bygge levedygtige apps med Angular. I kapitel 2, hvor vi arbejder med Forms, Observables, Signals og Subjects, vil vi begynde at udnytte de reaktive programmeringskoncepter i opbygningen af LocalCast Weather-appen.

Som programmør er du sandsynligvis vant til imperative programmering. Imperativ programmering betyder, at du som programmør skriver sekventiel kode, der beskriver alt, hvad der skal gøres i den rækkefølge, du definerer, og applikationens tilstand er afhængig af de rette variabler, der er sat korrekt for at fungere korrekt. Du skriver løkker, betingelser og kalder funktioner; du udløser hændelser og forventer, at de bliver håndteret. Imperativ og sekventiel logik er den måde, du er vant til at kode på.

Reaktiv programmering er en underkategori af funktionel programmering. I funktionel programmering kan du ikke stole på de variabler, du tidligere har sat. Hver funktion, du skriver, skal stå alene, modtage sin egen sæt af inputs og returnere et resultat uden at blive påvirket af tilstanden i en ydre funktion eller klasse. Funktionel programmering understøtter Test Driven Development (TDD) meget godt, fordi hver funktion er en enhed, der kan testes isoleret. Som sådan bliver hver funktion, du skriver, sammensat. Du kan mixe, matche og kombinere enhver funktion, du skriver, med andre og konstruere en række kald, der giver det resultat, du forventer.

Reaktiv programmering tilføjer en tvist til funktionel programmering. Du arbejder ikke længere med ren logik, men med en asynkron datastrøm, som du kan transformere og forme på enhver måde, du behøver, med et sammensat sæt af funktioner. Så når du abonnerer på en hændelse i en reaktiv strøm, ændrer du din kodningsparadigme fra reaktiv til imperativ programmering.

Hvordan man implementerer rollebaseret navigation og login i moderne webapplikationer

Webautentifikationssystemer skal opfylde høje standarder, og eventuelle fejl bør kommunikeres klart. Efterhånden som applikationer vokser, bør deres autentifikationssystem være nemt at vedligeholde og udvide for at sikre en problemfri brugeroplevelse. Når vi designer webapplikationer, er det derfor nødvendigt at tage højde for både tekniske krav og den brugerrejse, som autentifikationen indebærer. En solid baselinetilgang til autentifikation skal sikre, at systemet er både sikkert og brugervenligt. Dette kapitel tager udgangspunkt i en implementering af LemonMart-applikationen og diskuterer de tekniske og designmæssige udfordringer ved at opbygge et effektivt autentifikationssystem.

I kapitel 4 af bogen introducerede vi et router-first design for en single-page application (SPA). Vi definerede brugerroller og implementerede grundlæggende routinglogik. Med denne struktur på plads er vi nu klar til at implementere en rollebaseret navigation, der skaber en autentifikationsoplevelse, som føles både naturlig og sikker for brugeren. I dette kapitel vil vi bygge videre på dette fundament og bruge Google Firebase til autentifikation.

En vigtig del af den moderne webapplikation er, hvordan vi dynamisk opdaterer brugergrænsefladen (UI) baseret på den brugerens rolle og autentifikationsstatus. Det betyder, at brugerens adgang til specifikke sider og funktionaliteter skal styres af autentifikations- og autorisationssystemet. For eksempel, når en bruger forsøger at få adgang til en beskyttet side, og de ikke er autentificeret, vil systemet omdirigere dem til login-siden.

Dynamiske UI-komponenter og navigation

Når en bruger forsøger at logge ind, skal systemet være i stand til at validere indtastede oplysninger og derefter opdatere UI’et i henhold til den autentificerede brugers rolle. Dette kræver brug af asynkrone tjenester som AuthService, der kan returnere brugerens autentifikationsstatus og eventuelle fejlinformationer. Den dynamiske navigation, som vi implementerer, skal kunne reagere på ændringer i autentifikationsstatus og omdirigere brugeren til den rette side afhængig af deres rolle.

For eksempel, når en bruger logger ind korrekt, kan vi bruge routeren til at navigere dem til en specifik side baseret på deres rolle. Hvis login mislykkes, skal en fejlmeddelelse vises for at informere brugeren om, at loginforsøget ikke var succesfuldt.

I praksis implementeres login-komponenten i applikationen ved hjælp af en reaktiv formular, der indeholder felter for både e-mail og adgangskode. Ved at bruge Angulars reactive forms kan vi tilføje validering og fejlhåndtering. Når formularen indsendes, sendes anmodningen til serveren via AuthService, som derefter behandler loginforsøget.

Implementering af LoginComponent

Login-komponenten er afgørende for at sikre, at brugeren kan tilgå applikationen på en sikker og effektiv måde. Komponenten bør være uafhængig af andre komponenter, så den nemt kan vises under en routingbegivenhed, for eksempel hvis en bruger forsøger at tilgå en beskyttet side uden at være logget ind. For at gøre dette muligt opretter vi en rute til login-siden i applikationens routingfil. Vi anvender også en redirectUrl parameter, så systemet kan huske, hvor brugeren blev omdirigeret fra, og efter en vellykket login kan de sendes tilbage til denne side.

Login-logikken implementeres ved at bruge en formular, der validerer e-mail og adgangskode. Når brugeren sender formularen, forsøger systemet at logge dem ind ved at kalde AuthService.login metoden. Hvis login er vellykket, bruges routeren til at sende brugeren til den oprindelige side, de forsøgte at tilgå. Hvis login mislykkes, vises en fejlmeddelelse, som informerer brugeren om, hvad der gik galt.

Vigtige tekniske detaljer

  1. Brug af Firebase til autentifikation: Firebase tilbyder et robust autentifikationssystem, der kan bruges til at implementere login-funktionalitet i webapplikationer. Ved at integrere Firebase Authentication kan du udnytte en række autentifikationsmetoder som e-mail, Google-login, og sociale medier-login. Det gør det lettere at implementere en sikker og fleksibel login-proces.

  2. Rollebaseret navigation: Det er ikke nok blot at logge brugeren ind. Det er også nødvendigt at sikre, at brugeren kun har adgang til de sider, der er relevante for deres rolle. Dette kræver, at vi implementerer "guards" i Angular, som kan bruges til at beskytte ruter, der kun er tilgængelige for bestemte brugerroller.

  3. Fejlmeddelelser og brugervenlighed: En vigtig del af en god brugeroplevelse er klart definerede fejlmeddelelser. Hvis en bruger forsøger at logge ind med forkerte oplysninger, bør systemet vise en forståelig fejlmeddelelse, som hjælper brugeren med at rette fejlen. Dette kan være fejlmeddelelser som "Forkert adgangskode" eller "E-mail allerede i brug".

  4. Asynkrone opkald og håndtering af login-status: I en moderne webapplikation er det nødvendigt at håndtere login- og autentifikationsstatus asynkront. Ved at bruge observable strømme som authStatus$ og currentUser$ kan vi lytte efter ændringer i brugerens login-status og opdatere UI’et dynamisk.

Det er også vigtigt at bemærke, at selvom de tekniske aspekter af autentifikationssystemet er kritiske, er brugerens oplevelse ikke kun afhængig af funktionalitet, men også af hvordan systemet er designet. Et tydeligt og effektivt design, der tager hensyn til brugervenlighed, vil hjælpe med at opretholde en god og sikker oplevelse for brugerne.

Hvordan Implementere NgRx i Angular-applikationer: En konkret Guide

At implementere routere i Angular kan være kompliceret, især når man arbejder med lazy-loaded moduler og navngivne outlets. For at undgå fejl kan du aktivere routerens debug-tilstand ved at ændre root-provider i app.config.ts og tilføje funktionen withDebugTracing(), som vist her: provideRouter(routes, withDebugTracing()).

Material Design i Angular kan også bringe en dynamisk brugeroplevelse. Når en række i en tabel klikkes, aktiverer matRipple-direktivet et bølgeeffekt, hvilket forbedrer brugerinteraktionen. Efter dette implementeres klikhåndterere, hvor standarden for en række klikker viser detaljer via showDetail()-funktionen. Alternativt, hvis en bruger klikker på en 'view' knap i den højre kolonne, vises detaljerne også. En klik på refresh-knappen udløser en opdatering i refresh$ observable, som bliver behandlet i komponentens merge pipeline.

Når du har konfigureret hovedvisningen, viser tabellen de relevante data. Når en række klikkes, vises ViewUserComponent i detail-outletet. Dette er en grundlæggende master/detail-implementering. Ved at vælge 'View Details'-kolonnen øger du synligheden af en ekstra kolonne, som også giver dig mulighed for at interagere med detaljevisningen. Tilsvarende fungerer ikonet til visning af detaljer på samme måde som at klikke på en række, men med routerLink i stedet for direkte funktionalitet.

I tidligere kapitler blev 'Edit'-funktionen introduceret, repræsenteret ved en blyantikon, som tillader redigering af en brugerpost. Det er vigtigt at teste denne funktionalitet, og du bør sikre dig, at en opdateret brugerpost vises korrekt i datatabellen, når den er blevet ændret.

Testing og Refleksion over arkitekturen

Når vi ser på enhedenstests, er det vigtigt at bemærke, at i stedet for at bruge createComponentMock-funktionen fra angular-unit-test-helper, importerer vi de konkrete implementeringer af NameInputComponent eller ViewUserComponent. createComponentMock kan ikke håndtere binding af data til børns komponenter, og derfor er direkte implementering nødvendig.

Efter at have implementeret funktionerne i vores applikation kan vi begynde at udforske alternative arkitekturer og værktøjer, som kan forbedre forståelsen af, hvordan Angular-applikationer bedst struktureres til forskellige behov. En sådan teknologi er NgRx, et bibliotek til reaktiv tilstandshåndtering.

NgRx Store og Effects

NgRx bringer reaktiv tilstandshåndtering til Angular ved hjælp af RxJS. Denne tilgang gør det muligt at opdele logikken i små, atomare stykker kode, der kan komponeres og genbruges. Med NgRx skaber vi actions, reducers og selectors, som hver især spiller en rolle i at isolere bivirkninger ved ændringer af tilstand.

NgRx fungerer som et abstraktionslag over RxJS og passer ind i Flux-mønsteret, som allerede blev beskrevet i kapitlet om Angulars arkitektur. De vigtigste elementer i NgRx er:

  • Store: Et centralt lager, hvor tilstand opbevares. Reducere bruges til at gemme tilstandsovergang i storet, og selectors bruges til at læse data.

  • Action: Unikke begivenheder, der sker i applikationen og sendes til storet.

  • Dispatcher: En metode til at sende actions til storet.

  • Effect: En kombination af en action og en dispatcher. Effects bruges til handlinger, der ikke udløses af en brugerinteraktion i grænsefladen.

Implementering af NgRx i LocalCast Weather App

Lad os tage et konkret eksempel og implementere NgRx i en simpel vejrapp. Vi vil bruge NgRx Store og Effects til at implementere søgefunktionen i LocalCast Weather appen. I dette eksempel bruges actions til at håndtere søgeanmodninger, og NgRx's effektbibliotek isolerer de sideeffekter, der opstår under interaktionen.

Processen starter med, at en bruger udløser en søgeaction via CitySearchComponent. Denne action sendes til WeatherService, som henter vejrinformationer fra OpenWeather API'et. Når dataene er hentet, dispatcher en effect weatherLoaded action, som opdaterer storet med de nyeste vejrdata. En selector lytter på ændringer i denne data og giver applikationen mulighed for at opdatere visningen automatisk, når dataene ændres.

Sammenligning af BehaviorSubject og NgRx

I denne del sammenlignes NgRx med en enklere implementering, der bruger BehaviorSubject fra RxJS. Når vi anvender BehaviorSubject, opbevarer vi tilstand i en observable, som vi selv håndterer. Dette kan være tilstrækkeligt i simple applikationer, men når applikationen vokser i kompleksitet, giver NgRx et mere robust og struktureret alternativ.

Forskellen mellem de to tilgange kan ses i en slide-toggle, der gør det muligt at skifte mellem at bruge NgRx og BehaviorSubject. Med NgRx får man en mere skalerbar løsning, der er lettere at vedligeholde og udvide. På den anden side kan BehaviorSubject være

Hvordan Angular har udviklet sig til en skalerbar platform for virksomhedsapplikationer

Angular er et open-source projekt, der vedligeholdes af Google og et aktivt fællesskab af udviklere. Den moderne Angular-platform adskiller sig markant fra den ældre version af rammeværket, AngularJS, og repræsenterer en betydelig forbedring i både funktionalitet og anvendelighed. Samarbejdet mellem Google og Microsoft har været afgørende for denne udvikling, idet Microsofts TypeScript blev gjort til standardsprog for Angular, og dermed kunne udviklerne målrette ældre browsere, såsom Internet Explorer 11, samtidig med at de kunne skrive moderne JavaScript-kode, der fungerer i de nyeste browsere som Chrome, Firefox og Edge.

AngularJS, som var en monolitisk JavaScript SPA-ramme, blev hurtigt et populært valg for webudviklere, men havde sine begrænsninger. Den moderne version, Angular 2+, er ikke længere begrænset til blot webapplikationer, men er blevet en platform, der kan målrette browsere, hybride mobilrammer, desktopapplikationer og server-side rendererede visninger. Denne udvikling har gjort Angular til en alsidig platform, der kan imødekomme et væld af udviklingsbehov.

Opgraderingerne fra AngularJS til Angular 2+ medførte dog flere udfordringer for udviklerne. I den ældre version var det risikabelt og kostbart at opgradere til nye versioner, da selv små opdateringer kunne introducere nye kodemønstre og eksperimentelle funktioner. Opdateringer kunne også medføre nedlæggelse af eksisterende funktioner, hvilket betød, at store dele af koden skulle skrives om. Dette gjorde opgraderingsprocessen uforudsigelig og vanskelig at planlægge. I 2018 udgav Angular-holdet den sidste store opdatering til AngularJS med version 1.7, og slutningen på livscyklussen for AngularJS blev fastlagt til januar 2022.

Med Angular 2+ blev dette problem løst ved at følge SemVer, en versionsstyringsmodel, der sikrer, at mindre versioner kun indeholder nye funktioner og deprecations, men ikke breaking changes. Google har forpligtet sig til at følge en fast opdateringsplan, hvor store versioner bliver udgivet hver sjette måned, og hver version får 18 måneders support med fejlrettelser og sikkerhedsopdateringer. Dette betyder, at udviklere kan være sikre på, at deres Angular-kode er kompatibel og støttet i op til 24 måneder, selv uden at foretage ændringer.

I praksis er de fleste deprecations i Angular mindre og relativt enkle at rette, hvilket gør opgraderingsprocessen smidig og effektiv. Angular-holdet har arbejdet målrettet på at gøre opdateringer til en førstklasseoplevelse. Med Angular 6 blev værktøjet ng update introduceret, som gør det muligt at opgradere applikationer automatisk og nemt. Dette har markant reduceret opdateringstiden for store virksomheder som Air France og KLM, som tidligere brugte op til 30 dage på at opdatere deres Angular-applikationer, men nu kan gøre det på én dag.

Denne forudsigelighed og automatisering af opdateringsprocessen er en stor fordel for udviklere og organisationer. I stedet for at blive hængende på ældre versioner, som er svære at opgradere, kan teams nu planlægge ressourcerne for at sikre, at deres applikationer fortsat er moderne og konkurrencedygtige.

Den åbne kildekodefilosofi bag Angular gør det muligt for udviklere at skabe fantastiske webapplikationer og bidrage til et fællesskab af innovation. Google og Microsoft har ikke blot økonomiske interesser i at holde udviklerne engagerede; de ønsker også at opbygge et stærkt teknologisk fundament, der kan tiltrække og fastholde talent i udviklingsmiljøet. Dette samarbejde resulterer i høj kvalitet og stabilitet, hvilket også gavner virksomhederne selv, når de bruger Angular til at udvikle deres egne applikationer.

Angular er ikke uden sine udfordringer. Når man søger hjælp online, kan det være vanskeligt at skelne mellem versionerne af Angular og AngularJS. Derudover er det vigtigt at forstå, at nogle råd, der gælder for versioner før Angular 14, muligvis ikke længere er relevante på grund af ændringer i rendering-motoren (Ivy). Derfor er det altid anbefalet at læse den officielle dokumentation for den version af Angular, man arbejder med, hvilket kan findes på den officielle Angular-webside.

Når man vælger et framework som Angular, er det vigtigt at overveje, hvad der er den bedste investering for fremtidens webapplikationer. React og Vue er også populære alternativer, men Angular tilbyder en mere omfattende platform med stærke værktøjer til både udvikling og vedligeholdelse af store applikationer. At mestre Angular åbner op for en bred vifte af karrieremuligheder, og det er et fundament, som mange succesfulde webapplikationer er bygget på. Det er en investering, der betaler sig på lang sigt, både for udviklere og for organisationer, der ønsker at opbygge robuste og skalerbare applikationer.