Learning how to merge two observable streams in Angular2 by utilizing RxJS and the powerful .flatMap method

Within my Angular2 app, I have created an Observable in a Service called ContentService. Here is a simplified version of the code:

@Injectable()
export class ContentService {

    constructor(private http:Http, private apiService:ApiService) {

        this.content = this.http.get('src/i18n/en.json')
            .map((res:Response) => {
                let json: {} = res.json();
                return mapData(json);
            })

        mapData() {
            // function stuff to format data
        }

Now, I need to combine the results from the apiService with the results from this.content. The apiService returns a JSON object with a similar structure as this.content, but it comes from a third party API. I tried using flatMap to achieve this but encountered some syntax errors. My attempt looked like this:

this.content = this.http.get('src/i18n/' + this.userLang + '.json')
            .map((res:Response) => {
                let json: {} = res.json();
                return mapData(json);
            })
            .flatMap(() => {
                apiService.getAllCurrentListings().subscribe(response => {
                    return mapData(response);
                })
            });

This approach led to an error, indicating that there was a mistake in my syntax. When I call my API service outside the flatMap function, it works fine. So, clearly, I am missing something in the way I'm trying to add the apiService data to the original this.content results. Can someone help me understand how to do this correctly?

Thank you for your assistance.

Answer №1

Here is the solution that I have devised:

this.data = Observable.forkJoin(
            this.http.get('src/i18n/en.json').map((response:Response) => response.json()),
            apiService.fetchAllCurrentListings()
        ).map(result => {
            let mergedData:{} = Object.assign(result[0], result[1]);
            return processMergedData(mergedData);
        })

Answer №2

What type of data is expected to be stored in this content?

In your code, you are fetching an observable from this.http.get. In order to retrieve the data response from the http request, you should follow these steps.

Injectable()
export class ContentService {

    constructor(private http:Http, private apiService:ApiService)     {

        his.http.get('src/i18n/en.json')
            .map((res:Response) => {
                let json: {} = res.json();
                return mapData(json);
            })
            .subscribe(mappedData => 
                      this.content = mappedData)

        mapData() {
            // function stuff to format data
        }
    }      

Based on that, it seems like there might be an issue with your second snippet as well. In this particular scenario, using the flatMap operator may not be necessary since apiService.getAllCurrentListings doesn't rely on the first http call. Therefore, the forkJoin operator could offer a solution.

import {Observable} from 'rxjs/Observable'

Observable.forkJoin([
  this.http.get('src/i18n/' + this.userLang + '.json'),
  this.apiService.getAllCurrentListings()])
  .map(res => {
    this.content = this.mapData(res[0].json())
    /* once again, it's unclear what this.content should hold, but we need a separate variable for the second result */
    this.content2 = this.mapData(res[1].json())
  })
  

The .forkJoin method organizes n Observables into an array structure, requiring each response to be accessed using the appropriate array index.

If this approach doesn't align with your requirements, please specify the definition of this.content and its intended purpose.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring how to read class decorator files in a Node.js environment

I've developed a custom class decorator that extracts permissions for an Angular component. decorator.ts function extractPermissions(obj: { [key: 'read' | 'write' | 'update' | 'delete']: string }[]) { re ...

Opening a new tab in Angular 6 from a component with freshly generated HTML (containing input data)

Hello everyone. I have a requirement where I need to open a new browser tab with formatted input data from a modal component. Here's an example code snippet that attempts to achieve this using ng-template: @Component({ template: '< ...

How to dynamically insert variables into a separate HTML file while creating a VS Code extension

Currently working on a vscode extension, I'm facing an issue with containing the html in a string (like this: https://github.com/microsoft/vscode-extension-samples/blob/main/webview-view-sample/src/extension.ts). It leads to a large file size and lack ...

How to identify a click on a link within the current page using Angular

Is there a way to utilize built-in Angular router properties like RouterLinkActive to detect when a link to the current page is clicked? I am looking to implement a function in the footer that will scroll to the top of the page if the current page link is ...

useEffect does not trigger a rerender on the primary parent component

I am facing an issue where the main parent component does not re-render when I change the state 'click button' in another component while using useEffect. Oddly enough, the main <App /> component only re-renders properly when I reload the p ...

Animating with Angular 2

As I delve into this informative resource, my goal is to incorporate some animations into my applications, but I find myself grappling with understanding how the animations are triggered. HTML Component <div class="navbar navbar-default navbar-fixed-t ...

Angular2 - How to track or listen for (click) events on dynamically inserted HTML elements

I'm trying to inject a string with a dynamically retrieved (click) event into an Angular2 template. Since this string is fetched from the back-end after the DOM is loaded, Angular doesn't recognize the injected event. Here's an example of t ...

Discovering the power of angular async binding in your projects can greatly

Is there a way to achieve something similar to <span *ngIf="admins.includes(name) | async"> where the admins is declared as Observable<string[]> in the component class? I understand that this code may not work, but is there a workaround to make ...

I am encountering an Ionic issue where the Footer selector fails to work properly

I am working on my Ionic page and I have created a separate component for the footer. However, when I use the footer selector in my page, an error is displayed. This is the code for my "foot-card" component (foot-card.ts): import { Component } from &apos ...

I encounter an issue when trying to declare an enum in TypeScript

At line 26 in my typescript file, the code snippet below shows an enum definition: export enum ItemType { Case = 'Case', Study = 'Study', Project = 'Project', Item = 'Item', } I am currently using Visual Stu ...

Enable the use of empty spaces in ag-grid filter bars

I'm experiencing an issue with the ag grid filter. It seems to be disregarding white spaces. Is there a way to configure the grid to recognize blank spaces in the filter? Any suggestions for resolving this issue? Where can I find the option to accept ...

Gradle synchronization in IntelliJ causing missing folders in WAR Artifact

Currently, I am working on a Spring MVC application that incorporates TypeScript. The TypeScript code is transpiled using a Gradle task from the directory src/main/ts to build/ts. Subsequently, the resulting JavaScript files are added to the WAR file usin ...

Ways to resolve a 404 error on a live Angular application being hosted by NGINX

I am encountering an issue with my deployed application on a server where every time I refresh a specific page, I receive a NGINX 404 error. The application is running within Docker. Below is the configuration file for NGINX. server { listen 80; locat ...

Tips for preventing duplicate Java Script code within if statements

In my function, there are various statements to check the visibility of fields: isFieldVisible(node: any, field: DocumentField): boolean { if (field.tag === 'ADDR_KOMU') { let field = this.dfs_look(node.children, 'ADDR_A ...

What is the importance of including "declare var angular" while working with Typescript and AngularJS?

I've been working on an AngularJS 1.7 application that's coded entirely in TypeScript, and there's always been one thing bothering me. Within my app.module.ts file, I have this piece of code that doesn't sit right with me: declare va ...

Tips for sending a value to a container component

Within my task management application, I have implemented two selectors: export const selectFilter = (state: RootState) => state.visibilityFilter export const selectVisibleTodos = createSelector( [selectTodos, selectFilter], (todos: Todo[], filter : ...

Converting an array of date strings to a single string in JavaScript

Here is the JSON format I received with dynamic data: {"range":["2018-07-23T16:03:26.861Z","2018-07-23T16:03:26.861Z"]} Now, I need to convert this into the following format: range(20180723,20180723) Below is my code snippet : var data:Date[] = {"rang ...

Leveraging the power of NestJS in conjunction with Apollo Server version 2

I recently delved into learning nestjs and decided to give this graphql example a try. The issue I encountered is that the example was originally designed for apollo-server version 1, and I'm having difficulty adapting it to work with apollo-server v ...

The "angular2-image-upload" npm package encountering a CORS issue

Using the angular2-image-upload library for uploading files has been a smooth process until recently. After upgrading from version 0.6.6 to 1.0.0-rc.1 to access new features in future, I encountered issues with image uploads. The errors I faced were: Tr ...

What is the best way to sequentially invoke an asynchronous function within an Observable method?

Presently, I have the following method: public classMethod( payload: Payload, ): Observable<Result> { const { targetProp } = payload; let target; return this.secondClass.secondClassMethod({ targetProp }).pipe( delayWhen(() ...