Discover the process of implementing nested service calls in Angular 2 by utilizing observables

Here are my component file and service file. I am trying to achieve that after the verification() service method is successfully called, I want to trigger another service method signup() within its success callback inside subscribe. However, I am encountering an error message as shown below:

https://i.stack.imgur.com/ORmkB.png

In angular1, this approach used to work but not in this case:

sampleService.meth1().success(function(){
            //statement1...
            sampleService.meth1().success(function(data){
            //statement2...
        }).error(function(){})
    }).error(function(){});
})

Signup.component.ts

import { Component, Input } from '@angular/core';
    import { Router } from '@angular/router';
    import {User} from '../shared/model/user';
    import {SignupService} from './signup.service';
    import 'rxjs/add/operator/map';
    import 'rxjs/add/operator/catch';
    import 'rxjs/add/operator/debounceTime';
    import 'rxjs/add/operator/distinctUntilChanged';
    import 'rxjs/add/operator/switchMap';
    import 'rxjs/add/operator/toPromise';

    @Component({
        moduleId: module.id,
        selector: 'ym-signup',
        templateUrl: 'signup.component.html',
        styleUrls: ['signup.component.css'],
        providers: [SignupService]
    })

    export class SignupComponent {

        @Input()
        user = {};

        constructor(private router:Router, private signupService:SignupService) {
        }

        signup(selectedUser:User) {
            this.signupService.verification(selectedUser)
                .subscribe(data => {
                        swal({
                            title: 'Verify token sent on your Email.',
                            input: 'password',
                            inputAttributes: {
                                'maxlength': 10,
                                'autocapitalize': 'off',
                                'autocorrect': 'off'
                            }
                        }).then(function (password) {

                            this.signupService.signup(password)
                                .subscribe(data => {

                                        localStorage.setItem('user', JSON.stringify(data));
                                        this.router.navigate(['dashboard']);
                                    },
                                    error => alert(error));
                        })
                    },
                    error => alert(error));
        }


        goBack() {
            this.router.navigate(['login']);
        }
    }

Signup.service.ts

import {User} from '../shared/model/user';
import { Headers, Http } from '@angular/http';

import 'rxjs/add/operator/toPromise';
import {Injectable} from '@angular/core';
import {Response} from "angular2/http";
import { Observable }     from 'rxjs/Observable';


@Injectable()
export class SignupService {

    private postUrl:string = '/api/users/signup';
    private verify:string = '/api/users/verify';
    constructor(private http:Http) {
    }

    verification(user:User):Observable<JSON> {
        let headers = new Headers({
            'Content-Type': 'application/json'
        });

        return this.http
            .post(this.verify, JSON.stringify(user), {headers: headers})
            .map(this.extractData)
            .catch(this.handleError);
    }

    signup(token:string):Observable<any> {
        let headers = new Headers({
            'Content-Type': 'application/json'
        });

        return this.http
            .post(this.postUrl, JSON.stringify({verificationToken:token}), {headers: headers})
            .map(this.extractData)
            .catch(this.handleError);
    }

    private extractData(res: Response) {
        let body = res.json();
        return body || { };
    }

    private handleError(error: any) {
        let errMsg = (error.message) ? error.message :
            error.status ? `${error.status} - ${error.statusText}` : 'Server error';
        console.error(errMsg);
        return Observable.throw(errMsg);
    }

}

Answer №1

It appears that the error message

Cannot read property 'signup' of undefined
indicates that you are trying to call signup() on an object that does not exist.

This issue arises because you are defining the closure using

.then(function (password) { ... })
, which does not capture the surrounding context this and results in this = window being used, rather than the intended object.

To resolve this problem, consider using an arrow function instead:

.then(password => {
    this.signupService.signup(password)
        .subscribe(data => {
             localStorage.setItem('user', JSON.stringify(data));
             this.router.navigate(['dashboard']);
        }, error => alert(error));
})

Answer №2

When implementing the signup method, ensure that you are using an arrow function as the callback for the then function to maintain the same context.

 signup(selectedUser:User) {
            this.signupService.verification(selectedUser)
                .subscribe(data => {
                        swal({
                            title: 'Verify token sent on your Email.',
                            input: 'password',
                            inputAttributes: {
                                'maxlength': 10,
                                'autocapitalize': 'off',
                                'autocorrect': 'off'
                            }
                        }).then(password => {

                            this.signupService.signup(password)
                                .subscribe(data => {

                                        localStorage.setItem('user', JSON.stringify(data));
                                        this.router.navigate(['dashboard']);
                                    },
                                    error => alert(error));
                        })
                    },
                    error => alert(error));
        }

Answer №3

To efficiently handle multiple concurrent http.get() requests, you can utilize Observable.forkJoin(). This method allows all requests to run simultaneously, and if any one of them fails, the entire operation will result in an error state.

Check out the example code snippet below:


getBooksAndMovies() {
    Observable.forkJoin(
        this.http.get('/app/books.json').map((res: Response) => res.json()),
        this.http.get('/app/movies.json').map((res: Response) => res.json())
    ).subscribe(
        data => {
            this.books = data[0]
            this.movies = data[1]
        },
        err => console.error(err)
    );
}

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

Instructions on how to implement a readmore button for texts that exceed a specific character length

I am attempting to display a "Read more" button if the length of a comment exceeds 80 characters. This is how I am checking it: <tr repeat.for="m of comments"> <td if.bind="showLess">${m.comment.length < 80 ? m.comment : ...

Error in TypeScript when utilizing generic callbacks for varying event types

I'm currently working on developing a generic event handler that allows me to specify the event key, such as "pointermove", and have typescript automatically infer the event type, in this case PointerEvent. However, I am encountering an error when try ...

PageObjectModel Playwright, execute the locator().all() function - 'The execution context has been terminated, possibly due to navigating to another...'

Hey there, I'm currently working on a basic test using POM. Here is a snippet from one of my PageObjects Class: import { Expect, Page, Locator } from "@playwright/test"; export class InventoryPage { readonly page: Page; readonly addToC ...

Error in vue3 with typescript: unable to assign a ComputeRef<number[]> argument to an iterable<number> in d3.js

This code snippet was originally sourced from an example at https://medium.com/@lambrospd/5-simple-rules-to-data-visualization-with-vue-js-and-d3-js-f6b2bd6a1d40 I attempted to adapt the example to a TypeScript/Vue 3 version, and below is my implementatio ...

Encountering 404 errors when reloading routes on an Angular Azure static web app

After deploying my Angular app on Azure static web app, I encountered an error. Whenever I try to redirect to certain routes, it returns a 404 error. However, if I navigate from one route to another within the app, everything works fine. I have attempted t ...

Creating a regular expression to capture a numerical value enclosed by different characters:

export interface ValueParserResult { value: number, error: string } interface subParseResult { result: (string | number) [], error: string } class ValueParser { parse(eq: string, values: {[key: string] : number}, level?: number) : ValueParse ...

Error in Protractor Typescript: The 'By' type does not share any properties with the 'Locator' type

https://i.stack.imgur.com/8j2PR.png All the different versions Error. Protractor version : 5.2.0 npm : 3.10.10 node :6.9.5 typescript :2.6.0 The 'By' type does not share any properties with the 'Locator' type What is the solution to ...

Extract the JSON array data from the Service and process it within the Component

When passing a response from the Service to the Component for display on the UI, each value needs to be parsed and stored in a variable. This can be achieved by extracting values such as profileId, profileName, regionName, etc. from the response. [{"profi ...

Utilizing Typescript with Angular 2 to efficiently convert JSON data into objects within HTTP requests

I am dealing with a file called location.json, which contains JSON data structured like this: { "locations": [ { "id": 1, "places": [ { "id": 1, "city": "A ...

When working with the "agora-rtc-sdk-ng" package, an error may be thrown by Next.js stating that "window is not defined"

Currently, I am in the process of incorporating the "agora-rtc-sdk-ng" package for live streaming with next.js and typescript. import AgoraRTC from 'agora-rtc-sdk-ng'; However, when I try to import it, an error is thrown as shown below: https:/ ...

You cannot use ca.select(....).from function after the code has been minified

My Angular application utilizes squel.js and functions correctly in development mode. However, upon building the app for production and attempting to use it, I encounter the following error message: ca.select(...).from is not a function This error ref ...

Designing a versatile Angular component for inputting data (Mailing Address)

Currently, I am in the process of developing an Angular 11 application that requires input for three distinct mailing addresses. Initially, I thought I had a clear understanding of what needed to be done, only to encounter warnings about elements with non- ...

Utilizing Typescript DOM library for server-side operations

I've been working on coding a Google Cloud Function that involves using the URL standard along with URLSearchParams. After discovering that they are included in the TypeScript DOM library, I made sure to add it to my tsconfig file under the lib settin ...

I encountered TS2345 error: The argument type X cannot be assigned to the parameter type Y

Currently, I am delving into the world of Angular 8 as a beginner with this framework. In my attempt to design a new user interface with additional elements, I encountered an unexpected linting error after smoothly adding the first two fields. The error m ...

Display a nested component post initialization in Angular

<ng-container *ngIf="isTrue; else notTrue"> <app-child [property1]="value" [property2]="value" [property3]="value" (function1)="func($event)" ></app-child> </ng-container> <ng-t ...

When null is assigned to a type in Typescript, it does not result in an error being triggered

Could someone enlighten me on why this code is not causing an error? import { Injectable } from '@angular/core'; interface Animal{ name: string; } @Injectable() export class AnimalService { lion: Animal = null; constructor() {} get(){ ...

The issue of binding subjects in an Angular share service

I established a shared service with the following Subject: totalCostSource$ = new Subject<number>(); shareCost(cost: number ) { this.totalCostSource$.next(cost); } Within my component, I have the following code: private incomeTax: num ...

Exploring the potential of TypeScript with native dynamic ES2020 modules, all without the need for Node.js, while also enhancing

I have a TypeScript application that utilizes es16 modules, with most being statically imported. I am now looking to incorporate a (validator) module that is only imported in debug mode. Everything seems to be functioning properly, but I am struggling to f ...

Combining Different Types of Errors

Can TypeScript's type system be exploited to provide additional information from a repository to a service in case of errors? I have a service that needs a port for a repository (Interface that the Repository must implement), but since the service mu ...

Creating a Dynamic Example in Scenario Outline Using Typescript and Cypress-Cucumber-Preprocessor

I have a question that is closely related to the following topic: Behave: Writing a Scenario Outline with dynamic examples. The main difference is that I am not using Python for my Gherkin scenarios. Instead, I manage them with Cypress (utilizing the cypre ...