angularseoserver-side-renderingcanonical-link

Implement Canonical tag in an Angular Application


I have an Angular application where I want to have canonical tag value changing dynamically.

I have a component named article.component.ts which is responsible for displaying individual blog pages. Now the value of the canonical URL is available in the ngOnit method in the article component and it renders the value correctly after the page loads completely but since canonical tag changes are for SEO changes therefore it should reflect in the View Source option of the browser so that it reflects in the crawling of the web page by Search Engine.

I have used Server Side Rendering (SSR) in my Angular application to reflect the correct value of SEO tags like Meta tags, titles, and canonical tags.

Below are my code changes.

index.html

Mentioned initial canonical tag

<link rel="canonical" href="https://example.com">

Method in article component to update canonical tag

updateCanonicalLink(newCanonicalUrl: string) {
    const canonicalLink =  this.elementRef.nativeElement.querySelector('link[rel="canonical"]');
    const metaDes =  this.elementRef.nativeElement.querySelector('meta[name="description"]');
    console.log('canonical link',canonicalLink);
    if (canonicalLink) {
      console.log("Canonical tag updated",canonicalLink);
      this.renderer.setAttribute(canonicalLink, 'href', newCanonicalUrl);
    }
  }

Calling the above method in the ngOnit method of Article Component

ngOnInit(): void {
    this.subscriptions.push(this.router.params.subscribe(routeParams => {
      this.getArticle(routeParams.id, routeParams.path);
      this.pageId = `blog/${routeParams.id}`;       
       let canonicalURl = `https://example.com/blog/${routeParams.id}/${routeParams.path}`;
       this.updateCanonicalLink(canonicalURl);
    }));
  }

Somehow when I hit the URL then the canonical tag value is not reflected in View Source as well as console.log('canonical link',canonicalLink); prints null in the console.

If I am using document.querySelector('link[rel="canonical"]'); then also I am getting the below error in the application and not reflecting in View Source But console.log prints the correct value and is also updated in the element section.

Unless it's not updated in View Source then it not solves my purpose.

ERROR ReferenceError: document is not defined
    at article_component_ArticleComponent.updateCanonicalLink (C:\code\blogui\BlogApp\dist\BlogApp\serverless\modules-article-article-module.js:1:3670)
    at article_component_ArticleComponent.setDocTitle (C:\code\blogui\BlogApp\dist\BlogApp\serverless\modules-article-article-module.js:1:8635)
    at SafeSubscriber.subscriptions.push.blogService.getBlog.subscribe.isShowArticle [as _next] (C:\code\blogui\BlogApp\dist\BlogApp\serverless\modules-article-article-module.js:1:6413)
    at SafeSubscriber.__tryOrUnsub (C:\code\blogui\BlogApp\dist\BlogApp\serverless\main.js:1:456358)
    at SafeSubscriber.next (C:\code\blogui\BlogApp\dist\BlogApp\serverless\main.js:1:455057)
    at Subscriber._next (C:\code\blogui\BlogApp\dist\BlogApp\serverless\main.js:1:453716)
    at Subscriber.next (C:\code\blogui\BlogApp\dist\BlogApp\serverless\main.js:1:453478)
    at MapSubscriber._next (C:\code\blogui\BlogApp\dist\BlogApp\serverless\main.js:1:2369981)
    at MapSubscriber.next (C:\code\blogui\BlogApp\dist\BlogApp\serverless\main.js:1:453478)
    at FilterSubscriber._next (C:\code\blogui\BlogApp\dist\BlogApp\serverless\main.js:1:2519565)


Solution

  • You need to inject an Angular reference to the document

    import { DOCUMENT } from '@angular/common';
    import { Inject } from '@angular/core';
    
    constructor(@Inject(DOCUMENT)private document: Document){}
    
    updateCanonicalLink(newCanonicalUrl: string) {
        const canonicalLink = this.document.querySelector('link[rel="canonical"]');
        const metaDes = this.document.querySelector('meta[name="description"]');
        console.log('canonical link',canonicalLink);
        if (canonicalLink) {
          console.log("Canonical tag updated",canonicalLink);
          this.renderer.setAttribute(canonicalLink, 'href', newCanonicalUrl);
        }
      }