All files / app/services seo.service.ts

38.09% Statements 24/63
100% Branches 1/1
33.33% Functions 1/3
38.09% Lines 24/63

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 641x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x     7x 7x 1x 1x                           1x 1x                                                 1x  
 
import { Injectable, Renderer2, RendererFactory2, inject, DOCUMENT } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { environment } from '@environments/environment';
import { filter } from 'rxjs/operators';
 
@Injectable({ providedIn: 'root' })
export class SeoService {
	private document = inject(DOCUMENT);
	private router = inject(Router);
	private renderer: Renderer2;
 
	constructor() {
		const rendererFactory = inject(RendererFactory2);
		this.renderer = rendererFactory.createRenderer(null, null);
 
		this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe(() => {
			this.updateCanonical();
			this.updateRobotsTag();
		});
	}
 
	private updateCanonical(): void {
		const existingLink = this.document.querySelector('link[rel="canonical"]');
		if (existingLink) this.document.head.removeChild(existingLink);

		const link = this.renderer.createElement('link');
		this.renderer.setAttribute(link, 'rel', 'canonical');

		const baseUrl = environment.frontendUrl;
		const path = this.router.url.split(/[?#]/)[0]; // remove query/hash
		const fullUrl = path !== '/' ? `${baseUrl}${path}` : baseUrl;

		this.renderer.setAttribute(link, 'href', fullUrl);
		this.renderer.appendChild(this.document.head, link);
	}
 
	private updateRobotsTag(): void {
		const existingMeta = this.document.querySelector('meta[name="robots"]');

		// Do not overwrite if this tag is manually locked
		if (existingMeta?.getAttribute('data-seo-lock') === 'true') {
			return;
		}

		if (existingMeta) {
			this.document.head.removeChild(existingMeta);
		}

		const meta = this.renderer.createElement('meta');
		this.renderer.setAttribute(meta, 'name', 'robots');

		let content = 'index, follow';
		if (!environment.production) {
			content = 'noindex, nofollow';
		} else if (this.router.url.includes('?')) {
			content = 'noindex, follow';
		}

		this.renderer.setAttribute(meta, 'content', content);
		this.renderer.appendChild(this.document.head, meta);
	}
}