navigating to fragments in a page

fragment

Posted by bolatah on 7/10/2024, 9:25:22 AM

import { Component, OnInit, AfterViewInit, AfterViewChecked, ElementRef } from "@angular/core";

import { ActivatedRoute, Router, NavigationEnd } from "@angular/router";

import { DocumentationService } from "./documentation.service";

import { filter, delay } from "rxjs/operators";

interface Subtitle {

    title: string;

    content: string;

}

interface Item {

    name: string;

    subtitles: Subtitle[];

}

@Component({

    selector: "app-documentation",

    templateUrl: "./documentation.component.html",

    styleUrls: ["./documentation.component.scss"],

})

export class DocumentationComponent implements OnInit , AfterViewInit{

    items: Item[] = [];

    selectedItem: Item | null = null;

    selectedSubtitle: Subtitle | null = null;

    pendingFragment: string | null = null;

    constructor(

        private documentationService: DocumentationService,

        private route: ActivatedRoute,

        private router: Router,

        private elementRef: ElementRef

    ) {

        this.items = this.documentationService.getItems();

    }

    ngOnInit() {

        // Handle route params

        this.route.paramMap.subscribe((params) => {

            const itemName = params.get("itemName");

            if (itemName) {

                this.selectItemByName(itemName);

            } else if (this.items.length > 0) {

                const firstItem = this.items[0];

                this.selectItemByName(firstItem.name);

            }

        });

           // Handle fragment changes

           this.router.events

           .pipe(

               filter((event) => event instanceof NavigationEnd),

               delay(1000), // Add delay to allow the DOM to update

               filter(() => !!this.selectedSubtitle) // Ensure selectedSubtitle is defined

           )

           .subscribe(() => {

               const fragment = this.route.snapshot.fragment;

               this.scrollToFragment(fragment);

           });

      

      }

    ngAfterViewInit(): void {

    

    }

      

    sanitizeForURL(str: string): string {

        return str.replace(/[^a-zA-Z0-9]+/g, "-").toLowerCase();

    }

    selectItemByName(name: string) {

        this.selectedItem =

            this.items.find((item) => this.sanitizeForURL(item.name) === this.sanitizeForURL(name)) || null;

        if (this.selectedItem) {

            const firstSubtitle = this.selectedItem.subtitles[0];

            this.selectedSubtitle = firstSubtitle || null;

            this.updateUrlParams();

        }

    }

    selectSubtitleByTitle(title: string) {

        if (this.selectedItem) {

            this.selectedSubtitle =

                this.selectedItem.subtitles.find(

                    (subtitle) => this.sanitizeForURL(subtitle.title) === this.sanitizeForURL(title)

                ) || null;

            const sanitizedId = this.sanitizeForURL(title);

            this.updateUrlParams(sanitizedId);

        }

    }

    updateUrlParams(fragment?: string) {

        if (this.selectedItem) {

            const itemName = this.sanitizeForURL(this.selectedItem.name);

            this.router.navigate(["/documentation", itemName], {

                fragment: fragment ? fragment : null,

            });

        }

    }

    scrollToFragment(fragment: string) {

      const element = document.getElementById(fragment);

      if (element) {

        element.scrollIntoView();

      }

    }

}

<mat-drawer-container class="drawer-container" autosize>

    <!-- Left Sidebar -->

    <mat-drawer #leftDrawer mode="side" opened class="left-sidenav">

        <div class="center-content">

            <mat-nav-list>

                <a mat-list-item *ngFor="let item of items" 

                   (click)="selectItemByName(item.name)"

                   [class.selected]="item === selectedItem">

                    {{ item.name }}

                </a>

            </mat-nav-list>

        </div>

    </mat-drawer>

    <!-- Main Content -->

    <div class="main-content">

        <div class="center-content">

            <mat-toolbar color="primary">

                {{ selectedItem?.name }}

            </mat-toolbar>

            <div class="page-content" #content>

                <ng-container *ngIf="selectedItem">

                    <div *ngFor="let subtitle of selectedItem.subtitles">

                        <!-- Apply the sanitized ID to the subtitle -->

                        <h2 [id]="sanitizeForURL(subtitle.title)">

                            {{ subtitle.title }}

                        </h2>

                        <p>{{ subtitle.content }}</p>

                    </div>

                </ng-container>

            </div>

        </div>

    </div>

    <!-- Right Sidebar -->

    <mat-drawer #rightDrawer mode="side" opened position="end" class="right-sidenav">

        <div class="center-content">

            <h2><strong>On This Page</strong></h2>

            <mat-nav-list *ngFor="let subtitle of selectedItem?.subtitles" >

          

                    <a mat-list-item   

                    (click)="selectSubtitleByTitle(subtitle.title)"

                   [class.selected]="subtitle === selectedSubtitle">

                    {{ subtitle.title }}

                </a>

            

                

            </mat-nav-list>

        </div>

    </mat-drawer>

</mat-drawer-container>