From 76d31dadbc0dcd02aa06de03d0b38a74230a1899 Mon Sep 17 00:00:00 2001 From: Vladimir Lugovsky Date: Fri, 20 Dec 2019 11:09:37 +0300 Subject: [PATCH] feat(seo): add canonical tag (#5578) --- src/app/@core/core.module.ts | 2 ++ src/app/@core/utils/index.ts | 2 ++ src/app/@core/utils/seo.service.ts | 58 ++++++++++++++++++++++++++++++ src/app/app.component.ts | 4 ++- 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/app/@core/utils/seo.service.ts diff --git a/src/app/@core/core.module.ts b/src/app/@core/core.module.ts index 786d89547a..012f80972c 100644 --- a/src/app/@core/core.module.ts +++ b/src/app/@core/core.module.ts @@ -9,6 +9,7 @@ import { AnalyticsService, LayoutService, PlayerService, + SeoService, StateService, } from './utils'; import { UserData } from './data/users'; @@ -140,6 +141,7 @@ export const NB_CORE_PROVIDERS = [ AnalyticsService, LayoutService, PlayerService, + SeoService, StateService, ]; diff --git a/src/app/@core/utils/index.ts b/src/app/@core/utils/index.ts index 77e971d8d1..1b3f94daad 100644 --- a/src/app/@core/utils/index.ts +++ b/src/app/@core/utils/index.ts @@ -2,10 +2,12 @@ import { LayoutService } from './layout.service'; import { AnalyticsService } from './analytics.service'; import { PlayerService } from './player.service'; import { StateService } from './state.service'; +import { SeoService } from './seo.service'; export { LayoutService, AnalyticsService, PlayerService, + SeoService, StateService, }; diff --git a/src/app/@core/utils/seo.service.ts b/src/app/@core/utils/seo.service.ts new file mode 100644 index 0000000000..50f877d754 --- /dev/null +++ b/src/app/@core/utils/seo.service.ts @@ -0,0 +1,58 @@ +import { Injectable, Inject, PLATFORM_ID, OnDestroy } from '@angular/core'; +import { isPlatformBrowser } from '@angular/common'; +import { NavigationEnd, Router } from '@angular/router'; +import { NB_DOCUMENT } from '@nebular/theme'; +import { filter, takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; + +@Injectable() +export class SeoService implements OnDestroy { + + private readonly destroy$ = new Subject(); + private readonly dom: Document; + private readonly isBrowser: boolean; + private linkCanonical: HTMLLinkElement; + + constructor( + private router: Router, + @Inject(NB_DOCUMENT) document, + @Inject(PLATFORM_ID) platformId, + ) { + this.isBrowser = isPlatformBrowser(platformId); + this.dom = document; + + if (this.isBrowser) { + this.createCanonicalTag(); + } + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + + createCanonicalTag() { + this.linkCanonical = this.dom.createElement('link'); + this.linkCanonical.setAttribute('rel', 'canonical'); + this.dom.head.appendChild(this.linkCanonical); + this.linkCanonical.setAttribute('href', this.getCanonicalUrl()); + } + + trackCanonicalChanges() { + if (!this.isBrowser) { + return; + } + + this.router.events.pipe( + filter((event) => event instanceof NavigationEnd), + takeUntil(this.destroy$), + ) + .subscribe(() => { + this.linkCanonical.setAttribute('href', this.getCanonicalUrl()); + }); + } + + private getCanonicalUrl(): string { + return this.dom.location.origin + this.dom.location.pathname; + } +} diff --git a/src/app/app.component.ts b/src/app/app.component.ts index f858b0c4b2..2962b9a55d 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -5,6 +5,7 @@ */ import { Component, OnInit } from '@angular/core'; import { AnalyticsService } from './@core/utils/analytics.service'; +import { SeoService } from './@core/utils/seo.service'; @Component({ selector: 'ngx-app', @@ -12,10 +13,11 @@ import { AnalyticsService } from './@core/utils/analytics.service'; }) export class AppComponent implements OnInit { - constructor(private analytics: AnalyticsService) { + constructor(private analytics: AnalyticsService, private seoService: SeoService) { } ngOnInit(): void { this.analytics.trackPageViews(); + this.seoService.trackCanonicalChanges(); } }