03/04/2022
I den moderne webudvikling er en intuitiv og responsiv brugerflade afgørende for en god brugeroplevelse. Angular, et populært framework for at bygge dynamiske webapplikationer, tilbyder sammen med Angular Material en kraftfuld suite af UI-komponenter, der kan forvandle dine applikationer. Blandt disse komponenter er menuerne en fundamental del af navigationen og interaktionen. Denne artikel vil guide dig gennem implementeringen af smukke og funktionelle menuer i Angular ved hjælp af Angular Material, og dækker alt fra grundlæggende opsætning til avancerede funktioner.

Angular Material er et UI-komponentbibliotek udviklet af Google, der gør det muligt for Angular-udviklere at skabe moderne applikationer på en struktureret og responsiv måde. Ved at bruge dette bibliotek kan vi markant forbedre slutbrugernes brugeroplevelsen, og dermed øge vores applikations popularitet. Biblioteket indeholder moderne, klar-til-brug-elementer, der direkte kan anvendes med minimal eller ingen ekstra kode.
- Installation af Angular Material i dit Projekt
- Grundlæggende Implementering af Angular Material Menuer
- Tilpasning af Menuens Placering
- Menupunkter med Ikoner
- Indlejrede Menuer (Submenuer)
- Programmatisk Åbning af Menuer
- Oprettelse af Dynamiske Menupunkter
- Håndtering af Klikbegivenheder og Navigation
- Deaktivering af Menupunkter
- Overførsel af Data til Menuindholdspanelet
- Vigtig Bemærkning: Ingen MenuItemCheckbox/MenuItemRadio Roller
- Ofte Stillede Spørgsmål om Angular Material Menuer
- Konklusion
Installation af Angular Material i dit Projekt
Før vi kan begynde at implementere menuer, skal Angular Material installeres i dit Angular-projekt. Forudsætningen er, at du har Angular CLI installeret på dit system.
Trin 1: Tilføj Angular Material
Åbn din terminal i roden af dit Angular-projekt, og udfør følgende kommando:
ng add @angular/materialDenne kommando vil installere biblioteket og konfigurere dit projekt med de nødvendige stilarter og temaer. Du vil blive bedt om at vælge et tema og om at inkludere Angular Material-typografi og browseranimationer. Vælg de indstillinger, der passer bedst til dit projekt.
Trin 2: Importér de Nødvendige Moduler
For at bruge menukomponenten skal vi importere MatMenuModule. Hvis du også ønsker at bruge ikoner, skal du importere MatIconModule. Disse moduler skal importeres i din app.module.ts fil eller i en fælles Material-modulfil, som kan bruges på tværs af applikationen.
import { MatMenuModule } from '@angular/material/menu'; import { MatIconModule } from '@angular/material/icon'; // Kun hvis du vil bruge ikonerTilføj derefter de importerede moduler til imports-arrayet i din @NgModule-dekoration:
@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, BrowserAnimationsModule, MatMenuModule, MatIconModule // Kun hvis du vil bruge ikoner ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }Kernen i at skabe en menu i Angular Material er brugen af <mat-menu>-komponenten og direktivet matMenuTriggerFor. En mat-menu er en flydende panel, der indeholder en liste af menupunkter.
Brug <mat-menu>-vælgeren til at definere din menupanel. Du skal tilføje en skabelonreferencevariabel (f.eks. #menu="matMenu") til <mat-menu>, som vil blive brugt til at referere til menupanelet.
<mat-menu #menu="matMenu"> <button mat-menu-item>Menupunkt 1</button> <button mat-menu-item>Menupunkt 2</button> </mat-menu>Inden i <mat-menu> definerer du de enkelte menupunkter ved hjælp af <button mat-menu-item>. Det er vigtigt at tilføje mat-menu-item attributten til dine menuindstillinger, typisk på et <button>-element.
<mat-menu>-elementet i sig selv render ikke noget i UI'en. Menuen skal tilknyttes et udløserelement, som vil åbne og lukke menuen. Dette gøres ved hjælp af matMenuTriggerFor-direktivet.
<button mat-button [matMenuTriggerFor]="menu">Simpel Menu</button> <mat-menu #menu="matMenu"> <button mat-menu-item>Menupunkt A</button> <button mat-menu-item>Menupunkt B</button> </mat-menu>I eksemplet ovenfor tilknytter vi <mat-menu>-containeren til en knap kaldet "Simpel Menu" via matMenuTriggerFor-attributten. Den skabelonreferencevariabel, vi oprettede (#menu), bruges her til at linke udløseren til det korrekte menupanel.
Som standard vises Angular Material-menuen under udløserelementet. Du kan ændre menuens position ved hjælp af xPosition og yPosition egenskaberne på <mat-menu>-vælgeren.
Horisontal Placering (xPosition)
xPosition-egenskaben ændrer menuens position langs den horisontale akse. Den accepterer værdierne "before" eller "after".
<button mat-button [matMenuTriggerFor]="beforeMenu">Før</button> <mat-menu #beforeMenu="matMenu" xPosition="before"> <button mat-menu-item>Element 1</button> <button mat-menu-item>Element 2</button> </mat-menu> <button mat-button [matMenuTriggerFor]="afterMenu">Efter</button> <mat-menu #afterMenu="matMenu" xPosition="after"> <button mat-menu-item>Element 1</button> <button mat-menu-item>Element 2</button> </mat-menu>Vertikal Placering (yPosition)
yPosition-egenskaben bruges til at ændre menuens position langs den vertikale akse. Den accepterer værdierne "above" eller "below".
<button mat-button [matMenuTriggerFor]="aboveMenu">Over</button> <mat-menu #aboveMenu="matMenu" yPosition="above"> <button mat-menu-item>Element A</button> <button mat-menu-item>Element B</button> </mat-menu> <button mat-button [matMenuTriggerFor]="belowMenu">Under</button> <mat-menu #belowMenu="matMenu" yPosition="below"> <button mat-menu-item>Element A</button> <button mat-menu-item>Element B</button> </mat-menu>Her er en oversigt over positioneringsmulighederne:
| Egenskab | Værdier | Beskrivelse |
|---|---|---|
xPosition | "before", "after" | Placerer menuen til venstre (før) eller højre (efter) udløseren. |
yPosition | "above", "below" | Placerer menuen over eller under udløseren. |
Du kan forbedre menupunkternes visuelle appel ved at tilføje Material Design-ikoner. Dette gøres ved at placere <mat-icon>-elementer før menupunktets tekst.
<button mat-button [matMenuTriggerFor]="menuMedIkon">Menu med Ikon</button> <mat-menu #menuMedIkon="matMenu"> <button mat-menu-item><mat-icon>home</mat-icon><span>Hjem</span></button> <button mat-menu-item><mat-icon>info</mat-icon><span>Om os</span></button> </mat-menu>Du kan også bruge et ikon som selve menupunktets udløser:
<button mat-icon-button [matMenuTriggerFor]="ikonMenu"> <mat-icon>more_vert</mat-icon> </button> <mat-menu #ikonMenu="matMenu"> <button mat-menu-item><mat-icon>settings</mat-icon><span>Indstillinger</span></button> <button mat-menu-item><mat-icon>logout</mat-icon><span>Log ud</span></button> </mat-menu>At skabe indlejrede menuer, ofte kaldet submenuer, er utroligt simpelt med Angular Material. Du skal blot tilknytte en anden <mat-menu> til et eksisterende <button mat-menu-item> ved hjælp af matMenuTriggerFor-egenskaben.
Lad os opbygge et eksempel med programmeringssprog, der har flere niveauer af submenuer:
<mat-card> <button mat-button [matMenuTriggerFor]="sprogMenu">Sprog</button> <!-- Første niveau Menu --> <mat-menu #sprogMenu="matMenu"> <button mat-menu-item [matMenuTriggerFor]="frontendMenu">Frontend</button> <button mat-menu-item [matMenuTriggerFor]="backendMenu">Backend</button> </mat-menu> <!-- Andet niveau sub-menu: Frontend --> <mat-menu #frontendMenu="matMenu"> <button mat-menu-item [matMenuTriggerFor]="javascriptMenu">Javascript</button> <button mat-menu-item>Typescript</button> <button mat-menu-item>Angular</button> </mat-menu> <!-- Andet niveau sub-menu: Backend --> <mat-menu #backendMenu="matMenu"> <button mat-menu-item>C#</button> <button mat-menu-item>Java</button> </mat-menu> <!-- Tredje niveau sub-menu: Javascript --> <mat-menu #javascriptMenu="matMenu"> <button mat-menu-item>jQuery</button> <button mat-menu-item>VueJs</button> </mat-menu> </mat-card>Som du kan se, er princippet at ethvert mat-menu-item kan fungere som en udløser for en ny mat-menu, hvilket skaber en hierarkisk struktur. Dette giver mulighed for at skabe komplekse og velorganiserede navigationsstrukturer, som er essentielle for mange applikationer.
I visse situationer kan det være nødvendigt at åbne en menu programmatisk i stedet for via et brugerklik på en udløser. Dette er muligt ved at få en instans af MatMenuTrigger.

Tilføj en skabelonvariabel (f.eks. #triggerBtn) til det element, der fungerer som din menuudløser. Brug derefter @ViewChild i din komponent-TS-fil til at hente instansen af MatMenuTrigger.
<button mat-button (click)="åbnMenuProgrammatisk()">Åbn Menu</button> <button mat-icon-button #triggerBtn [matMenuTriggerFor]="normalMenu"> <mat-icon>more_vert</mat-icon> </button> <mat-menu #normalMenu="matMenu"> <button mat-menu-item>Hjem</button> <button mat-menu-item>Kontakt</button> </mat-menu>I din komponentens TypeScript-fil:
import { Component, ViewChild } from '@angular/core'; import { MatMenuTrigger } from '@angular/material/menu'; @Component({ selector: 'app-my-component', templateUrl: './my-component.html' }) export class MyComponent { @ViewChild(MatMenuTrigger) triggerBtn!: MatMenuTrigger; åbnMenuProgrammatisk() { this.triggerBtn.openMenu(); } }MatMenuTrigger eksponerer flere metoder, herunder openMenu(), som åbner menuen.
I mange virkelige applikationer er menupunkter ikke statiske, men genereres dynamisk, f.eks. fra en API eller en observerbar kilde. Du kan nemt oprette dynamiske menuer ved at binde en liste af objekter til <mat-menu-item> ved hjælp af *ngFor.
Trin 1: Definer din Data Struktur
Opret en TypeScript-klasse eller interface, der repræsenterer strukturen for dine menupunkter:
export class MatMenuListItem { menuLinkText!: string; menuIcon!: string; isDisabled!: boolean; routerLink?: string; // Valgfri, til navigation }Udfyld derefter en array med disse objekter i din komponent:
menuListItems: MatMenuListItem[] = [ {menuLinkText: 'Indstillinger', menuIcon: 'settings', isDisabled: false, routerLink: '/settings'}, {menuLinkText: 'Om os', menuIcon: 'people', isDisabled: false, routerLink: '/about'}, {menuLinkText: 'Hjælp', menuIcon: 'help', isDisabled: false, routerLink: '/help'}, {menuLinkText: 'Kontakt', menuIcon: 'contact_support', isDisabled: true, routerLink: '/contact'} ];Brug *ngFor i din HTML-skabelon til at iterere over menuListItems-arrayet og generere menupunkter:
<mat-toolbar> <button mat-icon-button [matMenuTriggerFor]="dynamiskMenu"> <mat-icon>more_vert</mat-icon> </button> <span>Valgt menu: {{selectedMenu}}</span> </mat-toolbar> <mat-menu #dynamiskMenu="matMenu"> <button mat-menu-item *ngFor="let item of menuListItems" (click)="klikPåMenupunkt(item)" [disabled]="item.isDisabled" [routerLink]="item.routerLink" > <mat-icon>{{ item.menuIcon }}</mat-icon> <span> {{ item.menuLinkText }}</span> </button> </mat-menu>Når en bruger klikker på et menupunkt, vil du ofte udføre en handling eller navigere til en anden rute. Angular Material menuer understøtter standard klikbegivenheder.
Klikbegivenheder
Du kan binde en metode til (click)-begivenheden på <button mat-menu-item>:
// I din komponentens TypeScript-fil kliPaaMenupunkt(menuItem: MatMenuListItem) { console.log(menuItem); this.selectedMenu = menuItem.menuLinkText; // Udfør andre handlinger her }Hvis dine menupunkter skal navigere til Angular-ruter, har du et par muligheder:
- Programmatisk Navigation: Brug Angulars
Router-service til at navigere baseret på menupunktets data. - Deklarativ Navigation med
routerLink: Hvis menupunktet udelukkende bruges til rutenavigation, kan du direkte tilføjerouterLink-attributten til<button mat-menu-item>.
import { Router } from '@angular/router'; // ... constructor(private router: Router) {} kliPaaMenupunkt(menuItem: MatMenuListItem) { this.selectedMenu = menuItem.menuLinkText; if (menuItem.routerLink) { this.router.navigate([menuItem.routerLink]); } }<button mat-menu-item *ngFor="let item of menuListItems" [routerLink]="item.routerLink"> <mat-icon>{{ item.menuIcon }}</mat-icon> <span> {{ item.menuLinkText }}</span> </button>Det er ofte nødvendigt at deaktivere visse menupunkter baseret på brugerrettigheder eller applikationens tilstand. Du kan nemt deaktivere et <mat-menu-item> ved at bruge [disabled]-egenskaben.
Hvis du bruger dynamiske menupunkter, kan du inkludere en isDisabled-egenskap i din dataobjekt og binde den til [disabled]:
<button mat-menu-item *ngFor="let item of menuListItems" (click)="kliPaaMenupunkt(item)" [disabled]="item.isDisabled"> <mat-icon>{{ item.menuIcon }}</mat-icon> <span> {{ item.menuLinkText }}</span> </button>Husk, at hvis alle menupunkter er deaktiverede, er det ofte bedre at skjule eller deaktivere selve menuudløseren for at undgå en dårlig brugeroplevelse.
En avanceret funktion er muligheden for at sende data fra udløserelementet til menuens indholdspanel. Dette giver dig mulighed for at genbruge en enkelt menuinstans med forskellige datasæt, afhængigt af den data, der sendes af udløserelementet. Dette er især nyttigt i scenarier, hvor du har dynamisk indhold, der skal vises i menuen baseret på konteksten.
Du passerer data til menupanelet via matMenuTriggerData inputtet på udløseren. I menupanelet bruges <ng-template matMenuContent> til at modtage og gengive dataen.
Lad os forestille os et scenarie, hvor du administrerer flere brugerkonti, og menuen skal vise kontooplysninger dynamisk:
Komponentens TypeScript-fil (.ts):
export class User { Name!: string; IsActive!: boolean; } export class MenuData { Users!: User[]; OtherMenus!: string[]; ActiveUser!: User; } @Component({ selector: 'app-my-component', templateUrl: './my-component.html' }) export class MyComponent implements OnInit { activeUser: User = { Name: "@angular_js", IsActive: true }; menuItems: MenuData = { Users: [ { Name: "@arungudelli", IsActive: false }, { Name: "@angular_js", IsActive: true } ], OtherMenus: [ "Tilføj eksisterende konto", "Administrer konti" ], ActiveUser: this.activeUser }; constructor() { } ngOnInit(): void { } }HTML-skabelon (.html):
<button mat-button [matMenuTriggerFor]="administrerKonti" [matMenuTriggerData]="menuItems"> {{activeUser.Name}} </button> <mat-menu #administrerKonti="matMenu"> <ng-template matMenuContent let-data="menuItems"> <ng-container *ngFor="let user of data.Users"> <button mat-menu-item> <span>{{user.Name}}</span> <mat-icon *ngIf="user.IsActive">how_to_reg</mat-icon> </button> </ng-container> <ng-container *ngFor="let othermenu of data.OtherMenus"> <button mat-menu-item>{{othermenu}}</button> </ng-container> <button mat-menu-item>Log af {{data.ActiveUser.Name}}</button> </ng-template> </mat-menu>I dette eksempel bruges [matMenuTriggerData]="menuItems" til at sende hele menuItems-objektet til menupanelet. Inde i <ng-template matMenuContent let-data="menuItems"> kan vi derefter tilgå disse data via den lokale variabel data. Dette giver en utrolig fleksibilitet til at skabe kontekstafhængige menuer.
Hvis du har et simpelt objekt, kan du direkte bruge let-nøgleordet til at definere en ny variabel og bruge den i menuindholdspanelet:
<button mat-icon-button [matMenuTriggerFor]="brugerMenu" [matMenuTriggerData]="{navn: 'ArunGudelli'}"> <mat-icon>more_vert</mat-icon> </button> <mat-menu #brugerMenu="matMenu"> <ng-template matMenuContent let-brugernavn="navn"> <button mat-menu-item>Log af {{brugernavn}}</button> </ng-template> </mat-menu>Det er vigtigt at bemærke, at Angular Material ikke understøttermenuitemcheckbox eller menuitemradio roller. Dette betyder, at du ikke direkte kan implementere menupunkter, der fungerer som afkrydsningsfelter eller radioknapper med indbygget ARIA-support via Angular Material's menukomponent. Hvis du har brug for denne funktionalitet, skal du sandsynligvis implementere det manuelt med din egen logik og styling, eller overveje alternative komponenter.
Ved åbning fokuserer udløseren det første fokuserbare menupunkt. Ved lukning returnerer menuen fokus til sin udløser. Undgå at oprette en menu, hvor alle punkter er deaktiverede; skjul i stedet eller deaktiver menuudløseren.
Som standard lukker en Angular Material menu, når du klikker på et mat-menu-item. Hvis du vil forhindre dette for specifikke punkter (f.eks. for at lade en bruger vælge flere indstillinger), kan du stoppe event-propagationen. Dette er dog en avanceret brugssituation og kræver manuel håndtering af menuens tilstand.
Ja, Angular Material-komponenter kan styles. Du kan bruge standard CSS til at overskrive Angular Materials indbyggede stilarter. Det anbefales at bruge CSS custom properties (variabler) leveret af Angular Material, eller at anvende ::ng-deep eller en global stilarkfil for at målrette specifikke elementer, da komponenterne bruger Shadow DOM.
Angular Material er designet med tilgængelighed i tankerne og følger ARIA-best practices. Menuer håndterer automatisk fokusstyring (flytter fokus til det første menupunkt ved åbning og tilbage til udløseren ved lukning) og tastaturnavigation (piletaster til at navigere, Enter/Space til at vælge). Sørg for at dine egne implementeringer ikke bryder disse indbyggede funktioner, og at tekstindhold er klart.
Mens mat-menu primært er til navigation og simple handlinger, kan du placere formkontroller inde i menupunkter. Men hvis du har komplekse formularer, der kræver input og validering, er det ofte bedre at bruge en dialog (MatDialog) eller et sidepanel (MatSidenav) for en bedre brugeroplevelse.
Konklusion
Angular Material tilbyder en robust og fleksibel måde at implementere menuer på, der spænder fra simple drop-downs til komplekse, indlejrede navigationsstrukturer. Med funktioner som dynamiske menuer, programmatisk kontrol og muligheden for at overføre data, kan du skabe enestående og responsive brugergrænseflader. Ved at følge de retningslinjer, der er beskrevet i denne artikel, kan du udnytte det fulde potentiale af Angular Material menuer og levere en intuitiv og engagerende brugeroplevelse i dine Angular-applikationer.
Hvis du vil læse andre artikler, der ligner Effektive Menuer med Angular Material, kan du besøge kategorien Teknologi.
