Search code examples
angularlodashwordpress-rest-apiswitchmap

Angular - How to get posts and tag names from Wordpress REST API using switchMap (merge two server responses)?


I am working on an Angular app that needs to fetch posts and their respective tag names from Wordpress REST API. With the API two GET requests need to be sent to the server. The first request is being sent to /wp/v2/posts. The response from the server looks like this:

Excerpt of posts request:

[
    {
        "id": 9,
        "title": {
            "rendered": "Hello World! 3"
        },
        "tags": [
            2,
            3,
            4
        ]
    },
    {
        "id": 7,
        "title": {
            "rendered": "Hello World! 2"
        },
        "tags": [
            2,
            3
        ]
    }
    ...
]

The numbers in the tags arrays aren't the actual human-readable tag names, they're just the identifies for the tags. After we have received the first response from the server, we need to send another GET request to the server to /wp/v2/tags?include=2,3,4 while supplying the tag identifiers with it. We don't need every single tag available in the database, just the ones that were referenced to in the response to the first request. In other words, the second request depends upon the results of the first request. The second request's response from the server looks like this:

Excerpt of tags request:

[
    {
        "id": 2,
        "name": "test"
    },
    {
        "id": 3,
        "name": "test2"
    },
    {
        "id": 4,
        "name": "test3"
    }
]

After doing research, I discovered that in Angular nested Observable.subscribe() methods are not the recommended way to solve this problem. RxJS' switchMap operator seems to be the way to go. My requirements are as follows:

  • call posts
  • take IDs from posts
  • call tags with IDs
  • merge tags with posts and return (so that posts array has a key called tag_names)

then .subscribe() to the overall flow and get a combined object of posts and tags which can then be iterated over in the Angular template file with NgForOf. A person on this website gave me a piece of code to work with. His approach was to use Lodash to combine both arrays according to the id property of their objects. His approach however doesn't do what it's supposed to do, as in the template I cannot access real tag names to display them from mergedArrays.

Please note that I do not require you to use Lodash to merge the results in your answer. It's just that in my code that is what was attempted. Any other means to merge the results will also qualify.


Solution

  • The vanilla JS approach is to use map and find to replace the ID with the corresponding tag.

    Like this:

    .subscribe(({ questions, tags }) => {
        const mergedArrays = questions.map((q) => {
          return {
            ...q,
            tag_names: q.tags
              .map((tagId) => tags.find((x) => x.id == tagId).name)
              .filter((exists) => !!exists),
          };
        });
    
        this.mergedArrays = mergedArrays;
      });
    

    Here is your example, but forked into my solution: https://stackblitz.com/edit/angular-ivy-vxcxzw?file=src/app/app.component.ts