如何使用 switchMap 从 Wordpress REST API 中获取某个 post、其标签和评论,然后使用 JS 组合结果值?
How to get a certain post, its tags and comments from Wordpress REST API using switchMap and then combine the resulting values using JS?
我正在开发一个 Angular 应用程序,它需要从 Wordpress REST API 中获取具有给定 ID 的特定 post、其各自的标签名称和注释。此应用程序的工作方式与 Whosebug 的 question-answer-logic 非常相似,因此我将 Wordpress post 称为 question
,将 Wordpress 评论称为 answers
。使用 API 三个 GET
请求需要发送到服务器。第一个请求正在发送到 /wp/v2/posts/<id>
。服务器的响应如下所示:
摘录post request:
{
"id": 9,
"title": {
"rendered": "Hello World! 3"
},
"tags": [
2,
3,
4
]
}
tags
数组中的数字不是实际的 human-readable 标签名称,它们只是标签的标识符。在我们收到服务器的第一个响应后,我们需要向服务器发送另一个 GET
请求到 /wp/v2/tags?include=2,3,4
,同时提供标签标识符。我们不需要数据库中可用的每个标签,只需要在对第一个请求的响应中引用的标签。换句话说,第二个请求取决于第一个请求的结果。来自服务器的第二个请求的响应如下所示:
摘录tags request:
[
{
"id": 8,
"name": "test"
},
{
"id": 9,
"name": "test2"
},
{
"id": 30087,
"name": "test3"
}
]
第三个也是最后一个请求需要发送到 /wp/v2/comments?post=9
。这会将结果集限制为分配给特定 post ID 的评论。服务器的响应如下所示:
comments request 的摘录:
[
{
"id":3,
"post":4,
"content":{
"rendered":"<p>This is an example comment number 3.<\/p>\n"
}
},
{
"id":2,
"post":9,
"content":{
"rendered":"<p>This is an example comment number 2.<\/p>\n"
}
}
]
Angular RxJS' switchMap
运算符似乎是要走的路。我的要求如下:
- 调用posts/3(post ID号是从URL参数中收集的
https://angular-ivy-jhuhth.stackblitz.io/detail/3
)
- 取自 post
的 ID
- 使用 ID
调用标签
- 用ID
调用评论
- 使用 vanilla JavaScript 将标签和评论与 post 和 return 合并(这样组合的 object 就有一个名为
tag_names
的键和评论'内容和日期)
然后 .subscribe()
到整体流程并得到 post 的组合 object,然后可以在 Angular 模板中迭代其标签和评论.
编辑:在模板中,我需要显示 question/post 的标题、日期、内容和 human-readable 标签名称,以及 question/post 的内容和日期answer/comment.
到目前为止,我在 Stackblitz 中的代码看起来 like this。对我的代码的分叉将不胜感激。在编写解决方案时,我遇到了控制台错误:detail.component.ts
中第 44 行的 questions.map is not a function
。我需要解决这个问题才能继续工作。
代码中用到的两个概念:
- forkJoin RxJS 操作符,它基本上等待所有 Observables 完成,然后合并结果。
- 异步管道,它订阅了一个 Observable 或 Promise 并且return它发出的最新值
错误原因?
getQuestion()
服务中的方法处理对象而不是对象数组,如下所示。
/** GET specific post from the server based on given ID */
getQuestion(id: number): Observable<Question> {
return this.http.get<Question>(`${this.questionsUrl}/posts/${id}`);
}
questions.map is not a function
在 map
RxJS operator 部分的 detail.component.ts
中抛出错误,因为我们正在尝试为一个对象调用 Array.map()
方法,这不会工作。
解决方案
可以通过创建临时数组并将 switchMap
参数变量 question
推入该临时数组来修复错误。之后,数组可以作为 of
RxJS 运算符中的参数传递。所有这些都将在组件的getQuestion
函数中完成,如下所示:
switchMap((question: Question) => {
const tagIDs = question.tags.join(',');
const questionID = +question.id;
// create temporary empty array
const tempArray = [];
tempArray.push(question);
return forkJoin({
// reference the temporary array in the of operator call
questions: of(tempArray),
tags: this.questionService.getTags(tagIDs),
comments: this.questionService.getDetailsAnswers(questionID),
});
})
这有点粗糙,但有效并设法解决了问题。
最后可以在模板中显示数据,代码如下:
<div class="container m-5">
<div *ngFor="let data of combined$ | async">
<h1>{{ data.title.rendered }}</h1>
<p>Asked {{ data.date | date: 'medium' }}</p>
<hr />
<p [innerHTML]="data.content.rendered"></p>
<span *ngFor="let tag_name of data.tag_names">
<a routerLink="/search/{{ tag_name }}/1" class="badge bg-secondary">{{
tag_name }}</a> </span>
<br /><br />
<p>{{ data?.comments?.length }} answers</p>
<div *ngFor="let answer of data.comments">
<p [innerHTML]="answer?.content?.rendered"></p>
<p class="text-end">Answered {{ answer?.date | date: 'medium' }}</p>
<hr />
</div>
这里是 StackBlitz:https://stackblitz.com/edit/angular-ivy-puctmm?file=src%2Fapp%2Fdetail%2Fdetail.component.ts
我正在开发一个 Angular 应用程序,它需要从 Wordpress REST API 中获取具有给定 ID 的特定 post、其各自的标签名称和注释。此应用程序的工作方式与 Whosebug 的 question-answer-logic 非常相似,因此我将 Wordpress post 称为 question
,将 Wordpress 评论称为 answers
。使用 API 三个 GET
请求需要发送到服务器。第一个请求正在发送到 /wp/v2/posts/<id>
。服务器的响应如下所示:
摘录post request:
{
"id": 9,
"title": {
"rendered": "Hello World! 3"
},
"tags": [
2,
3,
4
]
}
tags
数组中的数字不是实际的 human-readable 标签名称,它们只是标签的标识符。在我们收到服务器的第一个响应后,我们需要向服务器发送另一个 GET
请求到 /wp/v2/tags?include=2,3,4
,同时提供标签标识符。我们不需要数据库中可用的每个标签,只需要在对第一个请求的响应中引用的标签。换句话说,第二个请求取决于第一个请求的结果。来自服务器的第二个请求的响应如下所示:
摘录tags request:
[
{
"id": 8,
"name": "test"
},
{
"id": 9,
"name": "test2"
},
{
"id": 30087,
"name": "test3"
}
]
第三个也是最后一个请求需要发送到 /wp/v2/comments?post=9
。这会将结果集限制为分配给特定 post ID 的评论。服务器的响应如下所示:
comments request 的摘录:
[
{
"id":3,
"post":4,
"content":{
"rendered":"<p>This is an example comment number 3.<\/p>\n"
}
},
{
"id":2,
"post":9,
"content":{
"rendered":"<p>This is an example comment number 2.<\/p>\n"
}
}
]
Angular RxJS' switchMap
运算符似乎是要走的路。我的要求如下:
- 调用posts/3(post ID号是从URL参数中收集的
https://angular-ivy-jhuhth.stackblitz.io/detail/3
) - 取自 post 的 ID
- 使用 ID 调用标签
- 用ID 调用评论
- 使用 vanilla JavaScript 将标签和评论与 post 和 return 合并(这样组合的 object 就有一个名为
tag_names
的键和评论'内容和日期)
然后 .subscribe()
到整体流程并得到 post 的组合 object,然后可以在 Angular 模板中迭代其标签和评论.
编辑:在模板中,我需要显示 question/post 的标题、日期、内容和 human-readable 标签名称,以及 question/post 的内容和日期answer/comment.
到目前为止,我在 Stackblitz 中的代码看起来 like this。对我的代码的分叉将不胜感激。在编写解决方案时,我遇到了控制台错误:detail.component.ts
中第 44 行的 questions.map is not a function
。我需要解决这个问题才能继续工作。
代码中用到的两个概念:
- forkJoin RxJS 操作符,它基本上等待所有 Observables 完成,然后合并结果。
- 异步管道,它订阅了一个 Observable 或 Promise 并且return它发出的最新值
错误原因?
getQuestion()
服务中的方法处理对象而不是对象数组,如下所示。
/** GET specific post from the server based on given ID */
getQuestion(id: number): Observable<Question> {
return this.http.get<Question>(`${this.questionsUrl}/posts/${id}`);
}
questions.map is not a function
在 map
RxJS operator 部分的 detail.component.ts
中抛出错误,因为我们正在尝试为一个对象调用 Array.map()
方法,这不会工作。
解决方案
可以通过创建临时数组并将 switchMap
参数变量 question
推入该临时数组来修复错误。之后,数组可以作为 of
RxJS 运算符中的参数传递。所有这些都将在组件的getQuestion
函数中完成,如下所示:
switchMap((question: Question) => {
const tagIDs = question.tags.join(',');
const questionID = +question.id;
// create temporary empty array
const tempArray = [];
tempArray.push(question);
return forkJoin({
// reference the temporary array in the of operator call
questions: of(tempArray),
tags: this.questionService.getTags(tagIDs),
comments: this.questionService.getDetailsAnswers(questionID),
});
})
这有点粗糙,但有效并设法解决了问题。
最后可以在模板中显示数据,代码如下:
<div class="container m-5">
<div *ngFor="let data of combined$ | async">
<h1>{{ data.title.rendered }}</h1>
<p>Asked {{ data.date | date: 'medium' }}</p>
<hr />
<p [innerHTML]="data.content.rendered"></p>
<span *ngFor="let tag_name of data.tag_names">
<a routerLink="/search/{{ tag_name }}/1" class="badge bg-secondary">{{
tag_name }}</a> </span>
<br /><br />
<p>{{ data?.comments?.length }} answers</p>
<div *ngFor="let answer of data.comments">
<p [innerHTML]="answer?.content?.rendered"></p>
<p class="text-end">Answered {{ answer?.date | date: 'medium' }}</p>
<hr />
</div>
这里是 StackBlitz:https://stackblitz.com/edit/angular-ivy-puctmm?file=src%2Fapp%2Fdetail%2Fdetail.component.ts