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

Encountering a unique webpack error while attempting to upgrade Angular from version 11 to version

Struggling to upgrade my Angular version from 11.1.1 to 12.1.1 and encountering a build error. "CustomWebpackDevServerSchema" schema is using the keyword "id" which its support is deprecated. Use "$id" for schema ID. "BuildCustomWebpackBrowserSchema" sche ...

Understanding the Use of Promises and Async/Await in Typescript

Struggling with asynchronous libraries in Typescript, I find myself looking for a way to wait for promises to be resolved without turning every method into an async function. Rather than transforming my entire object model into a chain of Promises and asyn ...

Having trouble importing a tailwind CSS file into a Remix.js project without TypeScript throwing an error

I've attempted to implement the solution found here but unfortunately, it's still not working for me. Below are my configuration files: remix.config.ts: /** @type {import('@remix-run/dev').AppConfig} */ module.exports = { postcss: t ...

Angular is facing a challenge in locating the main parent based on its class interface

After reading the angular documentation here, I implemented a Parent class like this: export abstract class Parent {} In the AlexComponent, I set this component as the Parent for its children with the following code: providers: [{ provide: Parent, useExis ...

Troubleshooting Angular modal fade not functioning

I am facing an issue while trying to display a component called "Login", which belongs to the class "modal fade", from another component named "navbar". Despite my attempts to trigger it by calling data-bs-toggle="modal" data-bs-target="#LoginModal" from t ...

What is the process for installing both highcharts-angular and highcharts together?

UPDATE: Issue resolved - the problem was that the package.json file was read-only (refer to my answer). I have an Angular application (version 7) and I am attempting to integrate Highcharts. I am following the guidelines provided by highcharts-angular her ...

Creating a dynamic TypeScript signature that includes an optional argument

For some unknown reason, I am attempting to implement a reduce method on a subclass of Map: const nah = Symbol('not-an-arg'); class MapArray<A, B> extends Map<A, B> { reduce<T = [A, B]>(f: (prev: T, next: [A, B]) => any ...

Failure to log in to Facebook via Angular and Google Firebase due to URL being blocked

I am currently in the process of developing a web application that aims to gauge political popularity. To ensure accurate polling data, users will need to authenticate their social media accounts including Facebook, Twitter, and Google. For the front-end ...

Utilizing TypeScript code to access updatedAt timestamps in Mongoose

When querying the database, I receive the document type as a return. const table: TableDocument = await this.tableSchema.create({ ...createTableDto }) console.log(table) The structure of the table object is as follows: { createdBy: '12', cap ...

Components in Ionic used in app.component.ts and various pages

Struggling with integrating a custom component in Ionic. In my app.html, I have a menu and I'm using lazy-loading for the pages. I am trying to include the component in both the menu in app.html and on some pages. However, I'm facing an issue ...

Utilizing classes as types in TypeScript

Why is it possible to use a class as a type in TypeScript, like word: Word in the provided code snippet? class Dict { private words: Words = {}; // I am curious about this specific line add(word: Word) { if (!this.words[word.term]) { this.wor ...

Having issues with Angular material autocomplete feature - not functioning as expected, and no error

I have set up my autocomplete feature, and there are no error messages. However, when I type something in the input field, nothing happens - it seems like there is no action being triggered, and nothing appears in the console. Here is the HTML code: ...

Angular 6: utilizing the input field value in the component

I am having trouble passing the input field value to the component class. The code I have is not working as expected. Take a look below: todoinput.component.html <mat-card> <form> <mat-form-field class="example-full-width"> ...

Using Typescript Type Guard will not modify the variable type if it is set in an indirect manner

TL;DR Differentiation between link1 (Operational) vs link2 (not functional) TypeGuard function validateAllProperties<T>(obj: any, props: (keyof T)[]): obj is T { return props.every((prop) => obj.hasOwnProperty(prop)) } Consider a variable ms ...

There is an issue with the type candidate in the Notion API, resulting in

In this instance, the troublesome code causing issues is displayed below: import {Client, LogLevel} from "@notionhq/client"; const notion = new Client({ auth: process.env.NOTION_TOKEN, logLevel: process.env.NODE_ENV !== 'product ...

The browser is failing to load the login page, however, the method is functioning properly when accessed through Postman

I am facing an issue in my angular project with the login component - it is not loading the login page and instead showing a HTTP ERROR 401. Curiously, when I try to log in using Postman, everything works perfectly fine. However, I can't seem to figu ...

Utilizing Dynamic Variables in Angular Module Declarations

I am facing an issue with importing a module in my @NgModule setup. Currently, I have the following code: MqttModule.forRoot(environment.MQTT_SERVICE_OPTIONS) However, I want to retrieve the value from a configuration file instead of the environment. To ...

Issue in Ionic 2: typescript: The identifier 'EventStaffLogService' could not be located

I encountered an error after updating the app scripts. Although I've installed the latest version, I am not familiar with typescript. The code used to function properly before I executed the update. cli $ ionic serve Running 'serve:before' ...

Utilizing Angular 7 to implement table and pagination as separate entities, with distinct components

After referencing the link at https://material.angular.io/components/table/overview, I successfully implemented pagination, sort, and filter properties on a table. Now, I am looking to create a separate component specifically for pagination that will int ...

Encountered an issue resolving the dependency while executing npm i

I encountered an issue while trying to run the npm i command: npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead. npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: <a ...