【发布时间】:2020-07-30 08:37:34
【问题描述】:
我在尝试动态设置元标记时遇到了一些实际问题。 我可以轻松地在 ngOnInit 方法中设置标签,但如果我使用 Subscription,addTag 方法什么也不做。
export class AppComponent implements OnInit, OnDestroy {
public page: Page;
public postSlug: string;
private pages: Page[] = [];
private url: string = '/';
private routerSubscription: Subscription;
private pagesSubscription: Subscription;
constructor(
private router: Router,
private contentfulService: ContentfulService,
private pageService: PageService,
private meta: Meta
) {}
ngOnInit(): void {
this.meta.addTag({ name: 'app', content: 'Set from app component' });
this.url = this.router.url.split('#')[0]; // For initial page load
this.contentfulService.getPages();
this.getPages();
this.onNavigationEnd();
}
ngOnDestroy(): void {
if (this.routerSubscription) this.routerSubscription.unsubscribe();
if (this.pagesSubscription) this.pagesSubscription.unsubscribe();
}
private onNavigationEnd(): void {
this.routerSubscription = this.router.events.subscribe((event: any) => {
if (!(event instanceof NavigationEnd)) return;
this.url = event.urlAfterRedirects.split('#')[0];
this.setPage();
this.setPost();
});
}
private setPost(): void {
this.postSlug = undefined; // Always reset
if (!this.page || this.url.indexOf('/live-better/') === -1) return;
this.meta.addTag({ name: 'post', content: 'Set post' });
var urlParts = this.url.split('/');
this.postSlug = urlParts[urlParts.length - 1];
}
private setPage(): void {
if (!this.pages.length || !this.url) return;
this.page = this.pages.find((page: Page) => page.slug === this.url);
if (!this.page) {
this.page = this.pages.find(
(page: Page) => this.url.indexOf(page.slug) === 0
);
}
this.meta.addTag({ name: 'page', content: 'Set page' });
console.log(this.page);
this.pageService.setTitle(this.page.title);
this.pageService.setMetadata(this.page);
}
private getPages(): void {
this.pagesSubscription = this.contentfulService.pages.subscribe(
(pages: Page[]) => {
if (!pages.length) return;
this.pages = pages;
this.meta.addTag({ name: 'pages', content: 'Get pages' });
this.setPage();
this.setPost();
}
);
}
}
其余的代码执行并且没问题。如果我查看源代码,我可以看到{ name: 'app', content: 'Set from app component' } 的标签,但我看不到其他任何标签。
有人知道我是否遗漏了什么吗?
我认为这一定是视图后数据加载的问题,所以我创建了一个这样的解析器:
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { ContentfulService } from '../services/contentful.service';
import { Meta } from '@angular/platform-browser';
import { mergeMap, first } from 'rxjs/operators';
import { Observable, of, from } from 'rxjs';
import { Resolve } from '../models/resolve';
import { Page } from '../models/page';
@Injectable({ providedIn: 'root' })
export class PageResolver implements Resolve<{ page: Page; postSlug: string }> {
constructor(
private contentfulService: ContentfulService,
private meta: Meta
) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<{ page: Page; postSlug: string }> {
console.log('about to parse');
return this.getData(state);
}
private getData(
state: RouterStateSnapshot
): Observable<{ page: Page; postSlug: string }> {
const currentUrl = state.url.split('#')[0];
console.log(currentUrl);
this.meta.addTag({ name: 'resolve', content: 'Resolving route' });
if (!this.contentfulService.current.length) {
console.log('first load');
return from(
this.contentfulService.getPages().then((pages: Page[]) => {
this.meta.addTag({
name: 'first',
content: 'First resolve hit',
});
return this.parseData(pages, currentUrl);
})
);
} else {
console.log('after load');
return this.contentfulService.pages.pipe(
first(),
mergeMap((pages: Page[]) => {
this.meta.addTag({
name: 'second',
content: 'Changed page',
});
return of(this.parseData(pages, currentUrl));
})
);
}
}
private parseData(
pages: Page[],
currentUrl: string
): { page: Page; postSlug: string } {
let page = this.setPage(pages, currentUrl);
let postSlug = this.setPost(page, currentUrl);
let data: { page: Page; postSlug: string } = {
page: page,
postSlug: postSlug,
};
console.log(data);
return data;
}
private setPage(pages: Page[], currentUrl: string): Page {
if (!pages.length || !currentUrl) throw 'No pages have been loaded';
let page = pages.find((page: Page) => page.slug === currentUrl);
if (!page) {
page = pages.find(
(page: Page) => currentUrl.indexOf(page.slug) === 0
);
}
return page;
}
private setPost(page: Page, currentUrl: string): string {
if (!page || currentUrl.indexOf('/live-better/') === -1) return;
let urlParts = currentUrl.split('/');
let postSlug = urlParts[urlParts.length - 1];
let queryIndex = postSlug.indexOf('?');
if (queryIndex > -1) postSlug = postSlug.substring(0, queryIndex);
return postSlug;
}
}
并像这样将其添加到我的路由中:
const routes: Routes = [
{
path: '**',
component: HomeComponent,
resolve: { content: PageResolver },
},
];
现在在我的 HomeComponent 中,我只得到如下数据:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Page } from '@models';
import { Meta } from '@angular/platform-browser';
@Component({
selector: 'sxp-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
})
export class HomeComponent implements OnInit {
public page: Page;
public postSlug: string;
constructor(private route: ActivatedRoute, private meta: Meta) {}
ngOnInit(): void {
this.meta.addTag({ name: 'home', content: 'Home component loaded' });
this.route.data.subscribe(
(data: { content: { page: Page; postSlug: string } }) => {
let content = data.content;
this.meta.addTag({ name: 'meta', content: 'Subscription hit' });
this.page = content.page;
this.postSlug = content.postSlug;
console.log(content);
}
);
}
}
如您所见,我在解析器中使用了 3 次 addTag,在 HomeComponent 中使用了 2 次,但是当我查看源代码时,实际上只添加了一个:
this.meta.addTag({ name: 'resolve', content: 'Resolving route' });
我似乎无法在任何订阅后设置任何元标记。我希望解析器会延迟查看页面源的实际尝试获取数据,直到所有内容都首先加载到解析器中。
我在每次addTag 调用后添加了控制台日志。
你可以在这里查看它们:
【问题讨论】:
-
控制台服务器端没有错误?当你查看源代码(CTRL+U)时,你确实已经渲染了页面内容?
-
没有控制台错误,是的,我已经渲染了页面内容
-
你确定你的
this.contentfulService.pagesobservable 有效吗?请同时添加您的代码。 -
是的,解析器中的
console.log(page)实际上是在返回一个页面,所以就这么远了