Bidirectional communication linking an Angular 2 component and service utilizing the power of Observables

I'm having difficulties establishing a simple connection between an Angular 2 component and service using Observable. I've been trying to achieve this, but I can't seem to get it right.

Here's the scenario: My component HeroViewerComponent is supposed to subscribe to the router parameter id, then pass it to a service called HeroService in order to retrieve a Hero object from the server. The HeroService has a method named getHeroSubscription which takes an Observable<number> as input and returns an Observable<Hero>. However, this setup doesn't seem to be working as intended.

Let's take a look at my implementation of HeroViewerComponent in the file hero-viewer.component.ts:

import { Component, OnInit, OnDestroy } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { Observable } from "rxjs/Observable";
import { Observer } from "rxjs/Observer";
import { Subscription } from "rxjs/Subscription";

import { HeroService } from "./hero.service";
import { Hero } from "./hero";

@Component({
    providers: [HeroService]
})
export class HeroViewerComponent implements OnInit, OnDestroy {
    private routeParamsSubscription:Subscription;

    // Sending data to the service
    private routeParamsObservable:Observable<number>;

    // Subscribing to the route ID param
    private routeParamsObserver:Observer<number>;

    // Receiving data from the service
    private heroSubscription:Subscription;

    // The current hero object
    hero:Hero;

    constructor(private route:ActivatedRoute, private heroService:HeroService) {}

    ngOnInit() {
        this.routeParamsObservable = new Observable<number>((observer:Observer<number>) => this.routeParamsObserver = observer);

        this.heroSubscription = this.heroService
            .getHeroSubscription(this.routeParamsObservable)
            .subscribe(
                hero => this.hero = hero,
                error => console.warn(error)
            );

        this.routeParamsSubscription = this.route
            .params
            .subscribe(
                params => this.routeParamsObserver.next( +params["id"] ),
                error => console.warn(error)
            );
    }

    ngOnDestroy() {
        this.routeParamsSubscription.unsubscribe();
        this.heroSubscription.unsubscribe();
        this.routeParamsObserver.complete();
    }
}

Now, let's examine the HeroService defined in hero.service.ts:

import { Injectable } from "@angular/core";
import { Http, Response } from "@angular/http";
import { Observable } from "rxjs/Observable";
import { Observer } from "rxjs/Observer";
import "rxjs/add/operator/merge";
import "rxjs/add/operator/map";
import "rxjs/add/observable/throw";
import "rxjs/add/operator/catch";

import { Hero } from "./hero";

@Injectable()
export class HeroService {
    constructor(private http:Http) {}

    getHeroSubscription(heroIdObservable:Observable<number>):Observable<Hero> {
        let heroObserver:Observer<Hero>;
        let heroObservable = new Observable<Hero>((observer:Observer<Hero>) => {
            heroObserver = observer;
        });

        let heroIdSubscription = heroIdObservable.subscribe(
            heroId => {
                const tmp = this.http
                    .get("api/heroes/" + heroId)
                    .map((response:Response) => response.json().data)
                    .catch((response:any) => {
                        if (response instanceof Response) {
                            return Observable.throw(response.json().error);
                        }
                        return Observable.throw(response);
                    });
                heroObservable.merge(tmp);
            },
            error => console.warn(error),
            () => {
                heroIdSubscription.unsubscribe();
                heroObserver.complete();
            }
        );

        return heroObservable;
    }
}

Finally, here's the definition of Hero found in hero.ts:

export class Hero {public id: number;}

After reviewing all the code, can you spot where I might have gone wrong?

Answer №1

It seems like the issue could be that heroObservable.merge(tmp) is not actually mutating heroObservable, but rather returning a new observable that gets lost in your code.

Consider storing it in a variable and then returning it for the getHeroSubscription method instead of simply returning heroObservable.

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

How can I obtain the model values for all cars in the primary object?

const vehicles={ vehicle1:{ brand:"Suzuki", model:565, price:1200 }, vehicle2:{ brand:"Hyundai", model:567, price:1300 }, vehicle3:{ brand:"Toyota", model ...

Stop /Terminate the Angular 2 HTTP API request

Occasionally, the loading time for an http API call can be quite lengthy. However, even if we navigate to another component, the call still continues execution (which is visible in the browser console). Is there a method or approach that allows us to can ...

I encountered the error message "The property you are trying to access does not exist on the type 'never'" while attempting to retrieve JSON data from the API response

Every time I attempt to access the fields in items such as id or title, an error pops up saying Property does not exist on type 'never'. Interestingly, when I log the data using console.log(response.data), everything seems to be working fine. I ...

Issue with Object.keys printing in an abnormal manner

My goal is to extract only the keys from an object, but instead of getting the desired output with the keys, I am seeing numbers. Here is the code snippet: data = {"property" : "{\"animalID\": \"12345\" ...

Using Firebase with the async pipe in Angular 5

I am struggling to implement async pipe in Angular firebase and encountering an error that I cannot resolve: ERROR Error: InvalidPipeArgument: '[object Object]' for pipe 'AsyncPipe' Utilizing the Firebase NoSQL database: { "bos ...

What causes the typescript error in my code: The argument being passed is either a string, an array of FilterData, an array of numbers, or an array of Moments, which is not compatible with a parameter of type 'string'?

When writing my code, I have the need to utilize various types for different scenarios. Depending on the situation, the type may be a string, number[], FilterData[] (a custom type), or Moment[]. To address this requirement, I defined the type as: export ty ...

Establishing global date restrictions for the DatePicker component in Angular 8 using TypeScript across the entire application

I am currently learning Angular 8 and I am looking to globally set the minimum and maximum dates for a datepicker in my application. I would like to accomplish this by using format-datepicker.ts. Any suggestions on how I can achieve this? Min date: Jan 1, ...

Creating a React Native project without the use of TypeScript

Recently I dived into the world of React Native and decided to start a project using React Native CLI. However, I was surprised to find out that it uses TypeScript by default. Is there a way for me to create a project using React Native CLI without TypeS ...

Troubleshooting a CORS problem with connecting an Angular application to a Node server that is accessing the Spotify

I am currently working on setting up an authentication flow using the Spotify API. In this setup, my Angular application is making calls to my Node server which is running on localhost:3000. export class SpotifyService { private apiRoot = 'http://lo ...

What is the process for implementing an abstract factory pattern in Typescript?

I’m currently facing a challenge while attempting to incorporate a standard abstract factory pattern in Typescript, only to find that the compiler is not quite on board with my efforts. Below is a simplified version of the code I am working with: abstra ...

Creating a wrapper component to enhance an existing component in Vue - A step-by-step guide

Currently, I am utilizing quasar in one of my projects. The dialog component I am using is becoming redundant in multiple instances, so I am planning to create a dialog wrapper component named my-dialog. my-dialog.vue <template> <q-dialog v-bin ...

default folder location for core modules adjustment

While experimenting with module imports in TypeScript, I encountered an issue when trying to import a module using import { Component, OnInit } from '@angular/core';. The compiler was successfully finding the module in the node_modules folder. I ...

Issue with Angular 4: Radio button defaults not being set

After hardcoding the value in component.ts, I am able to see the pre-selected radio button. However, when attempting to retrieve the value from sessionStorage, it does not work as expected. The value is visible in the console though. Could someone please ...

Ways to make a component gradually appear and disappear in an Angular application

I have developed a task management application using Angular and I wanted to implement a fading effect for each task when it is created and before it is deleted. Despite successfully applying the fade in effect at the todo-item component level, I encounter ...

Angular does not include the ControlGroup feature in its common offerings

I am new to TypeScript and have been following tutorials in an attempt to accomplish simple tasks, but so far without success. Many tutorials seem outdated with changes in Angular or provide instructions that do not work at all. Even the tutorials that do ...

What is the source of the compiler options in tsconfig.json?

Currently utilizing Typescript in NestJs, I have incorporated various packages. However, the specific package responsible for altering these settings remains unknown to me: "checkJs": false, "skipLibCheck": true Is there a method to ...

The BooleanField component in V4 no longer supports the use of Mui Icons

In my React-Admin v3 project, I had a functional component that looked like this: import ClearIcon from '@mui/icons-material/Clear' import DoneIcon from '@mui/icons-material/Done' import get from 'lodash/get' import { BooleanF ...

Issue with Jest: receiving error message "Module cannot be found" despite having the package installed

Recently, I went through a cleanup and update process for a private package to make it compatible with Vite. Initially, the package.json file had the following structure: { "name": "@myRegistry/my-package", "version": &qu ...

Exploring Angular 6 CLI Workspaces: A Guide to Creating Libraries for Exporting Services

Introduction: In Angular CLI 6, a significant feature called workspaces was introduced. A workspace has the ability to house multiple projects within it. All configurations for the workspace and its projects are stored in an 'angular.json' fi ...

how can one exhibit the value of an object in TypeScript

Does anyone know how to properly display object values in forms using Angular? I can see the object and its values fine in the browser developer tools, but I'm having trouble populating the form with these values. In my *.ts file: console.log(this.pr ...