使用外部API调用更新angular Universal中的元标签

时间:2018-10-11 17:03:51

标签: angular seo meta-tags angular-universal ssr

我花了两个多月的时间,但找不到如何进行角度通用的清晰解决方案。 我已经花了大约6个月的时间来在一个项目上实施angular Universal,而我却花了很多时间,但现在我仍然坚持这个问题。任何人都可以帮我解决这个问题,因为全世界似乎都想知道Angular SSR的解决方案。

这是我的代码(元标记服务):

import {Injectable} from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';
import {commonMetas} from './meta-data.model';

@Injectable()
export class SeoService {
    public commonMetas = commonMetas;
    constructor(public meta: Meta, public title: Title) {}

    setAutomatically (key = 'none') {
        const detail = this.commonMetas[key];
        /** setting defaults */
        this.setTitle(detail.title);
        this.setAuthor();
        this.setDescription(detail.description);
        this.setKeywords(detail.keyword);
    }
    setFromJson(key: {
        title: any,
        description: any,
        image: any,
        keyword: any,
        author: any
    }) {
        key.title = key.title ? key.title : this.commonMetas['none'].title;
        key.description = key.description ? key.description : this.commonMetas['none'].description;

    }
    setTitle(titleToSet = '') {
        this.title.setTitle(titleToSet);
    }
    setAuthor (nameToSet = '') {
        this.meta.addTag({ name: 'author',   content: 'havemybooks.com'});
    }
    setKeywords (keyword = '') {
        this.meta.addTag({ name: 'keywords', content: keyword});
    }
    }
}

还有我的component.ts

  ngOnInit() {
    this.sub = this.route.params.subscribe(params => {
      this.id = +params['id'];
      this.api.getParticular({id: this.id}).subscribe((response) => {
        this.content = response.blog_data[0];
        this.content.main_image = this.getImage(this.content.main_image);
        this.content.metaCreatedAt = moment(this.content.created_at).format('YYYY-MM-DD');
        this.content.displayCreatedAt = moment.utc(new Date(this.content.created_at)).fromNow();
        this.content.name = this.handleName(this.content.name);
        this.seo.setFromJson({
          title: this.content.title,
          image: this.content.main_image,
          description: this.content.blog,
          author: this.content.name,
          keyword: ''
        });
      });
   });
  }

以下是一些链接的StackOverflow问题和GitHub问题:

Angular universal Server Side Rendering, Meta tags

Updating meta tags for SEO using angular universal

Angular Universal + External API

https://github.com/fulls1z3/ngx-meta/issues/101

Angular Universal - OG meta tags not working with child routes

https://github.com/fulls1z3/ngx-meta/issues/118(I试图从成功实施但没有帮助的人那里获得帮助)

https://github.com/maciejtreder/ng-toolkit/issues/460(我打开了它)

这个清单还在继续,我已经看到了许多从未结束的讨论。任何可以建议如何在ng-express中渲染之前进行API调用的人。

我已经实现了SSR,并使用ngx-meta标签,但fb搜寻器仍显示了我在head标签中使用的默认元标签。

  

更新:我能够使用中的“查看源代码”选项来更新源代码   chrome,但Facebook和Google搜寻器显示默认的元标记   默认情况下在那里。要启动我的网站非常困难   剩下的任何帮助,我们感激不尽。 @Brandon指导了我很多事情   与Jade和Nunchucks一起实现节点的时间相当长,但是   默认情况下,角度通用使用angular-express,所以我无法   使用上述渲染引擎。

有没有一种方法可以使用ng express引擎呈现元标记。

赞这个<title>{{meta.title}}</title>...

4 个答案:

答案 0 :(得分:0)

我在Angular 2 Universal上实现了设置标题。应该使用Renderer完成,就像这样:

1。在组件内部导入渲染器:

import {Renderer } from '@angular/core';

2。在构造函数内部添加依赖项:

constructor
    (
        ...
        private renderer: Renderer
    ) {}

3。立即使用它来设置标题:

renderer.setText(renderer.selectRootElement('title'), value);

答案 1 :(得分:0)

偶然发现了这个寻找相同的解决方案。使用setTimeout对我有用。确保刷新缓存或使用隐身模式,否则您将错过看到元数据的功能(我犯了这个错误)。我的研究表明,在SSR呈现页面之前,必须等待订阅API数据,以便观察到的内容必须保持打开状态(但我不是专家)。 https://angular.io/guide/observables。另外,使其生效的唯一方法是将来自订阅权限的响应放入metaService。我将在代码中显示我的意思。

setTimeout( () =>
              this.seo.setFromJson({
              title: this.content.title,
              image: this.content.main_image,
              description: this.content.blog,
              author: this.content.name,
              keyword: ''
            });
    ,0);

我的解决方案代码:

this.publicFeedService.getPublicProfile(data).subscribe((response:any) => {
        this.memberProfile = response[this.userId];
        setTimeout( () => 
        //Define the meta title using profile data
        this.titleService.setTitle('The best investment ideas from ' + response[this.userId].firstName + ' ' + response[this.userId].lastName), 0);
        setTimeout( () =>         
        //Define the meta tags using the user profile data
        this.metaService.addTags([
          {name: 'keywords', content: 'investing ideas, stock ideas, financial profile'},
          {name: 'description', content: response[this.userId].about},
          {name: 'robots', content: 'index, follow'}
        ]), 0);

答案 2 :(得分:0)

找不到简单的方法,但这是GitHub用户here提供的一种临时/ hacky解决方案,我直接引用了他的答案:

//all imports
enableProdMode();

export const app = express();

const mysql = require('mysql');
const httpRequest = require("request");
// all other consts

app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));
//all other piece of code in server.ts

app.get('/*', (req, res) => {
  res.render('index', {req, res}, (err, html) => {
    if (html) {
        
        //console.log(html);
        // This is where you get hold of HTML which "is about to be rendered"
    
        // after some conditional checks make a HTTP call
        let url = 'http://....';
        httpRequest.get(url, (error, response, body) => {
                        if(error) {
                            return console.log(error);
                        }
                        const respBody = JSON.parse(body);
                        if(respBody){
                              html = html.replace(/\$TITLE/g, respBody.title);
                              html = html.replace(/\$DESCRIPTION/g, respBody.description);
                              html = html.replace(/\$OG_META_KEYWORDS/g, respBody.metaKeywords);
                              html = html.replace(/\$OG_META_DESCRIPTION/g, respBody.metaDescription);
                              html = html.replace(/\$OG_DESCRIPTION/g, respBody.ogDescription);
                              html = html.replace(/\$OG_TITLE/g, respBody.ogTitle);
                              html = html.replace(/\$OG_IMAGE/g, respBody.img);
                              html = html.replace(/\$OG_SITE/g, respBody.ogSite);
                        }
                        res.send(html);
            });
     }
  }
}

然后在index.html中,创建如下模板值:

    <title>$TITLE</title>

    <meta name="description" content="$DESCRIPTION"/> 
    <meta name="keywords" content="$OG_META_KEYWORDS" />
    <meta name="metaDescription" content="$OG_META_DESCRIPTION"/> 
    <meta name="metaKeywords" content="$OG_META_KEYWORDS" />
    <meta property="og:title" content="$OG_TITLE" />
    <meta property="og:description" content="$OG_DESCRIPTION" />
    <meta property="og:site_name" content="$OG_SITE" /> 
    <meta property="og:type" content="website" />   
    <meta property="og:image" content="$OG_IMAGE" />

答案 3 :(得分:-1)

首先像这样在index.html文件中添加所有必需的元标记

index file

然后更新每个必需组件中的meta标记,如下使用meta.updateTag()

component file

这个对我有用。

我尝试创建要更新的服务,但该服务不起作用,仅当在同一个组件中添加了元更新时,该服务才起作用。