Angular2 - SEO - how to manipulate the meta description

后端 未结 4 1197
野的像风
野的像风 2020-12-02 17:15

Search Results in google are displayed via TitleTag and the Tag. The </code>-Tag is editiable via Ang <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-5408099190056760" data-ad-slot="7305827575" data-ad-format="auto" data-full-width-responsive="true"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> </div> <div class="fly-panel detail-box" id="flyReply"> <fieldset class="layui-elem-field layui-field-title" style="text-align: center;"> <legend>4条回答</legend> </fieldset> <ul class="jieda" id="jieda"> <li data-id="111" class="jieda-daan"> <a name="item-1111111111"></a> <div class="detail-about detail-about-reply"> <a class="fly-avatar" href=""> <img src="https://www.e-learn.cn/qa/data/avatar/000/00/00/small_000000025.jpg" alt=" 执笔经年 "> </a> <div class="fly-detail-user"> <a href="" class="fly-link"> <cite> 执笔经年</cite> </a> <span>(楼主)</span> </div> <div class="detail-hits"> <span>2020-12-02 17:51</span> </div> </div> <div class="detail-body jieda-body photos"> <p> <p>It is possible. I implemented it in my app and below I provide the description how it is made.</p> <p>The basic idea is to use <code>Meta</code> from <code>@angular/platform-browser</code></p> <p>To dynamically change particular meta tag you have to:</p> <ol> <li>Remove the old one using <code>removeTag(attrSelector: string) : void</code> method.</li> <li>Add the new one using <code>addTag(tag: MetaDefinition, forceCreation?: boolean) : HTMLMetaElement</code> method.</li> </ol> <p>And you have to do it when the router fires route change event.</p> <p>Notice: In fact it is also necessary to have default <code><title>... and in head of index.html so before it is set dynamically there is already some static content.

My app-routing.module.ts content:

import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';

import { NgModule } from '@angular/core';
import { RouterModule, Routes, Router, NavigationEnd, ActivatedRoute } from '@angular/router';

import { StringComparisonComponent }  from '../module-string-comparison/string-comparison.component';
import { ClockCalculatorComponent }  from '../module-clock-calculator/clock-calculator.component';

import { Title, Meta } from '@angular/platform-browser';

const routes: Routes = [
  {
    path: '', redirectTo: '/string-comparison', pathMatch: 'full',
    data: { title: 'String comparison title', metaDescription: 'String comparison meta description content' }
  },
  {
    path: 'string-comparison',  component: StringComparisonComponent,
    data: { title: 'String comparison title', metaDescription: 'String comparison meta description content' }
  },
  {
    path: 'clock-time-calculator',  component: ClockCalculatorComponent,
    data: { title: 'Clock time calculator title', metaDescription: 'Clock time calculator meta description content' }
  }
];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})

export class AppRoutingModule {

  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute,
    private titleService: Title,
    private metaService: Meta
  ){
    //Boilerplate code to filter out only important router events and to pull out data object field from each route
    this.router.events
    .filter(event => event instanceof NavigationEnd)
    .map(() => this.activatedRoute)
    .map(route => {
        while (route.firstChild) route = route.firstChild;
        return route;
    })
    .filter(route => route.outlet === 'primary')
    //Data fields are merged so we can use them directly to take title and metaDescription for each route from them
    .mergeMap(route => route.data)
    //Real action starts there
    .subscribe((event) => {
        //Changing title
        this.titleService.setTitle(event['title']);

        //Changing meta with name="description"
        var tag = { name: 'description', content: event['metaDescription'] };
        let attributeSelector : string = 'name="description"';
        this.metaService.removeTag(attributeSelector);
        this.metaService.addTag(tag, false);
    });
  }

}
  1. As it can be seen there is an additional data object field for each route. It contains title and metaDescription strings which will be used as title and meta tag content.
  2. In constructor we filter out router events and we subscribe to filtered router event. Rxjs is used there, but in fact it is not necessary to use it. Regular if statements and loops could be used insead of stream, filter and map.
  3. We also merge our data object field with our event so we can easily use info like title and metaDescription strings.
  4. We dynamically change ... and tags.

Effects:

First component

Second component

In fact I currently use a little bit more sophisticated version of this solution which uses also ngx-translate to show different title and meta description for different languages.
Full code is available in angular2-bootstrap-translate-website-starter project.
The app-routing.module.ts file with ngx-translate solution is exactly there: app-routing.module.ts.

There is also the production app which uses the same solution: http://www.online-utils.com.

For sure it is not the only way and there might be better ways to do it. But I tested this solution and it works.

In fact the solution is very similar to this from corresponding post about changing title: How to change page title in angular2 router.

Angular Meta docs: https://angular.io/docs/ts/latest/api/platform-browser/index/Meta-class.html. In fact they aren't very informative and I had to experiment and look into real .js code to make this dynamic meta change working.

提交回复
热议问题