@zoomsphere/ngx-meta

Dynamic page title & meta tags utility for Angular (w/server-side rendering)

Usage no npm install needed!

<script type="module">
  import zoomsphereNgxMeta from 'https://cdn.skypack.dev/@zoomsphere/ngx-meta';
</script>

README

@ngx-meta/core npm version npm downloads

Dynamic page title & meta tags generator for Angular

CircleCI coverage tested with jest Conventional Commits Angular Style Guide

Please support this project by simply putting a Github star. Share this library with friends on Twitter and everywhere else you can.

@ngx-meta/core updates the page title and meta tags every time the route changes, based on Angular app's route configuration.

  • When the Angular app uses server-side rendering, the meta tags and page titles generated by @ngx-meta/core successfully appear on HTML source, due to its platform-free workflow. This allows the SPA to be crawled and rendered by the search engines, as well as sharing the website link on social networks (facebook, twitter, etc).
  • It also supports resolving values using a callback function to use a custom logic on the meta tag contents (http-get, @ngx-translate/core).

Table of contents:

Getting started

Installation

You can install @ngx-meta/core using npm

npm install @ngx-meta/core --save

Examples

Recommended packages

The following package(s) have no dependency for @ngx-meta/core, however may provide supplementary/shorthand functionality:

  • @ngx-config/core: provides meta settings from the application settings loaded during application initialization
  • @ngx-translate/core: provides internationalization (i18n) features to retrieve the translated meta settings

Adding @ngx-meta/core to your project (SystemJS)

Add map for @ngx-meta/core in your systemjs.config

'@ngx-meta/core': 'node_modules/@ngx-meta/core/bundles/core.umd.min.js'

Route configuration

Import MetaGuard using the mapping '@ngx-meta/core' and append canActivate: [MetaGuard] or canActivateChild: [MetaGuard] properties to the route definitions at app.routes (considering the app.routes is the route definitions in Angular application).

Then, add meta settings inside the data property of routes.

Note: meta properties such as title, description, author and publisher will be duplicated as og:title, og:description, og:author and og:publisher, so there's no need to declare them again in this context.

app.routes.ts

...
import { MetaGuard } from '@ngx-meta/core';
...
export const routes: Routes = [
  {
    path: '',
    canActivateChild: [MetaGuard],
    children: [
      {
        path: 'home',
        component: HomeComponent,
        data: {
          meta: {
            title: 'Sweet home',
            description: 'Home, home sweet home... and what?'
          }
        }
      },
      {
        path: 'duck',
        component: DuckComponent,
        data: {
          meta: {
            title: 'Rubber duckie',
            description: 'Have you seen my rubber duckie?'
          }
        }
      },
      {
        path: 'toothpaste',
        component: ToothpasteComponent,
        data: {
          meta: {
            title: 'Toothpaste',
            override: true, // prevents appending/prepending the application name to the title attribute
            description: 'Eating toothpaste is considered to be too healthy!'
          }
        }
      }
    ]
  }
  ...
];

app.module configuration

Import MetaModule using the mapping '@ngx-meta/core' and append MetaModule.forRoot({...}) within the imports property of app.module (considering the app.module is the core module in Angular application).

app.module.ts

...
import { MetaModule } from '@ngx-meta/core';
...

@NgModule({
  declarations: [
    AppComponent,
    ...
  ],
  ...
  imports: [
    ...
    RouterModule.forRoot(routes),
    MetaModule.forRoot()
  ],
  ...
  bootstrap: [AppComponent]
})

Settings

You can call the forRoot static method using the MetaStaticLoader. By default, it is configured to prepend page titles after the application name (if any set). These default meta settings are used when a route doesn't contain any meta settings in its data property.

You can customize this behavior (and ofc other settings) by supplying meta settings to MetaStaticLoader.

The following example shows the use of an exported function (instead of an inline function) for AoT compilation.

Setting up MetaModule to use MetaStaticLoader

app.module.ts

...
import { MetaModule, MetaLoader, MetaStaticLoader, PageTitlePositioning } from '@ngx-meta/core';
...

export function metaFactory(): MetaLoader {
  return new MetaStaticLoader({
    pageTitlePositioning: PageTitlePositioning.PrependPageTitle,
    pageTitleSeparator: ' - ',
    applicationName: 'Tour of (lazy/busy) heroes',
    defaults: {
      title: 'Mighty mighty mouse',
      description: 'Mighty Mouse is an animated superhero mouse character',
      'og:image': 'https://upload.wikimedia.org/wikipedia/commons/f/f8/superraton.jpg',
      'og:type': 'website',
      'og:locale': 'en_US',
      'og:locale:alternate': 'en_US,nl_NL,tr_TR'
    }
  });
}

...

@NgModule({
  declarations: [
    AppComponent,
    ...
  ],
  ...
  imports: [
    ...
    RouterModule.forRoot(routes),
    MetaModule.forRoot({
      provide: MetaLoader,
      useFactory: (metaFactory)
    })
  ],
  ...
  bootstrap: [AppComponent]
})

MetaStaticLoader has one parameter:

  • providedSettings: MetaSettings : meta settings (by default, prepend page titles)

:+1: Holy cow! @ngx-meta/core will update the page title and meta tags every time the route changes.

Using a callback function

The MetaStaticLoader accepts a callback function to use a custom logic on the meta tag contents (http-get, @ngx-translate/core, etc.).

Return type of the callback function must be string, Observable<string> or Promise<string>.

When a callback function is supplied, the MetaService will try to retrieve contents of meta tags (except og:locale and og:locale:alternate) using the specified callback. You can customize the behavior for missing/empty values, directly from the callback function itself.

app.module.ts

...
import { MetaModule, MetaLoader, MetaStaticLoader, PageTitlePositioning } from '@ngx-meta/core';
import { TranslateService } from '@ngx-translate/core';
...

export function metaFactory(translate: TranslateService): MetaLoader {
  return new MetaStaticLoader({
    callback: (key: string) => translate.get(key),
    pageTitlePositioning: PageTitlePositioning.PrependPageTitle,
    pageTitleSeparator: ' - ',
    applicationName: 'APP_NAME',
    defaults: {
      title: 'DEFAULT_TITLE',
      description: 'DEFAULT_DESC',
      'og:image': 'https://upload.wikimedia.org/wikipedia/commons/f/f8/superraton.jpg',
      'og:type': 'website',
      'og:locale': 'en_US',
      'og:locale:alternate': 'en_US,nl_NL,tr_TR'
    }
  });
}

...

@NgModule({
  declarations: [
    AppComponent,
    ...
  ],
  ...
  imports: [
    ...
    RouterModule.forRoot(routes),
    MetaModule.forRoot({
      provide: MetaLoader,
      useFactory: (metaFactory),
      deps: [TranslateService]
    })
  ],
  ...
  bootstrap: [AppComponent]
})

app.component.ts

...
import { MetaService } from '@ngx-meta/core';
...

@Component({
  ...
})
export class AppComponent implements OnInit {
  ...
  constructor(private readonly translate: TranslateService,
              private readonly meta: MetaService) { }

  ngOnInit(): void {
    // add available languages & set default language
    this.translate.addLangs(['en', 'tr']);
    this.translate.setDefaultLang(defaultLanguage.code);

    this.translate.use('en').subscribe(() => {
      this.meta.setTag('og:locale', 'en-US');
    });
  }
  ...
}

home.routes.ts

import { Routes } from '@angular/router';
import { HomeComponent } from './home.component';

export const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    data: {
      meta: {
        title: 'PUBLIC.HOME.PAGE_TITLE',
        description: 'PUBLIC.HOME.META_DESC'
      }
    }
  }
];

You can find out in-depth examples about the use of callback function on ng-seed/universal and on fulls1z3/example-app, which are officially maintained seed projects showcasing common patterns and best practices.

Set meta tags programmatically

...
import { Component, OnInit, OnDestroy } from '@angular/core';
import { MetaService } from '@ngx-meta/core';
...

@Component({
  ...
})
export class ItemComponent implements OnInit, OnDestroy {
  ...
  constructor(private readonly meta: MetaService) { }
  ...
  ngOnInit() {
    this.item = //HTTP GET for "item" in the repository
    this.meta.setTitle(`Page for ${this.item.name}`);
    this.meta.setTag('og:image', this.item.imageUrl);
  }
  ngOnDestroy() {
     this.meta.removeTag('property="og:type"');
  }
}

Credits

  • ng2-meta: Dynamic meta tags and SEO in Angular2

License

The MIT License (MIT)

Copyright (c) 2019 Burak Tasci