Antonio Mikulić
Antonio Mikulić

Reputation: 3

Angular7 -> Navigate to id="#article-1" in dynamicly loaded HTML

I'm contacting backend which returns full .html file, which has to be displayed in Angular component. When I get the file, it has navigations to anchors, which does not work in Angular7, as it tries to navigate to localhost:4200/#. I want to allow users to use anchors for navigation.

I have been trying to do this without using any packages, using InnerHtml, OuterHtml, ElementRef, ViewContainerRef and parsing data on Backend. I tried replacing: href="#id" with href="javascript:; (click)="navigate(#id)" and routerLink with fragmentation.

The issue is that this newly injected code doesn't work due to DOM Sanitazation.

    @ViewChild('dynamic', { read: ElementRef }) dynamic: ElementRef;

    private loadHtmlData(data: string) {
        // Only take body
        data = data.split("<body")[1].split(">").slice(1).join(">").split("</body>")[0];

        let pageRegex = /(href="#page-)/g;
        data = data.replace(pageRegex, 'href="javascript:;" [routerLink]="[]" fragment="page-');

        this.fullHtml = data;
        this.dynamic.nativeElement.outerHTML = data;
        this.htmlLoaded = true;
    }

                <!-- Direct Injection
                    <div [innerHTML]="fullHtml | sanitizeHtml"
                    *ngIf="htmlLoaded"></div>
                -->
                <div #dynamic>
                </div>

Expectation was that clicking on newly formated link would take me to that anchor.

Fixed it like this:

    <div [innerHTML]="navigationHtml | sanitizeHtml: 'html'"
            (click)="loadedHtmlClicked($event)"
            *ngIf="htmlLoaded">
    </div>
    loadedHtmlClicked(event) {
        if (event && event.target && event.target.attributes) {
            let attributes: NamedNodeMap = event.target.attributes;
            let fragment = attributes.getNamedItem('fragment');
            if (fragment && this.fragment != fragment.value) {
                this.router.navigate([], { fragment: fragment.value });

                let element = document.getElementById(fragment.value);
                if (element) {
                    // Allows for some padding above element
                    window.scrollTo({
                        top: element.offsetTop + 60,
                        behavior: "smooth"
                    });
                }
            }
        }
    }

Upvotes: 0

Views: 65

Answers (1)

Christoph
Christoph

Reputation: 302

Angular template syntax is no native html. Your angular cli will compile it down to html/js. So your runtime generated template won't feel the pleasure.

// I would comment this, but lack the rep.

Upvotes: 0

Related Questions