FrankfromDenmark
FrankfromDenmark

Reputation: 170

Converting multiple nested promises and array of promises to Observables

I am in the process of converting a AngularJS app to Angular 7 in TypeScript.

I am having some problems with converting some complex nested promises to Observables.

Here is an example of the code I'm dealing with:

signup.component.js

function SomethingSignupController(somethingApplication) {
    function activate() {
        getApplication();
    } 

    function getApplication() {
        vm.getFromServer = false;
        vm.promises = [];
        SomethingRepo.get().then(function(application) {
            vm.getFromServer = true;
            vm.application = application;
            vm.promises.push(Something.getCompany().then(function(company) {
                vm.company = company;
                if (vm.company.structure === ‘more_25’) {
                    return SomethingRepo.getAllOwners().then(function(owners) {
                        vm.owners = owners;
                        for(var i = 0; i < vm.owners.length; i++) {
                            vm.promises.push(getOwnerFiles(vm.owners[i]));
                        }
                    }
                }
            }
            vm.promises.push(SomethingRepo.getSomethingOne().then(function(somethingOne) {
                vm.somethingOne = somethingOne;
            }
            vm.promises.push(SomethingRepo.getSomethingTwo().then(function(somethingTwo) {
                vm.somethingTwo = somethingTwo;
            }
            vm.promises.push(SomethingRepo.getSomethingThree().then(function(somethingThree) {
                vm.somethingThree = somethingThree;
            }
            /* and a few more like the above */
            $q.all(vm.promises).then(function(){
                postGet();
            }).finally(function() {
                vm.promises = [];
            });
        }
    }

    function postGet() {
        /* does something with the data acquired from SomethingRepo */
    }

    /* when an application is send */
    function send() {
        somethingApplication.promises = [];
        somethingApplication.errors = [];
        if (vm.getFromServer) {
            update();
        } else { 
            create();
        }
    }

    function update() {
        somethingApplication.promises.push(SomethingRepo.update(vm.application).then(angular.noop, function(error) {
            somethingApplication.parseErrors(error, ‘Some error’);
        }));
        patchInfo();
    }

    function create() {

    }

    function patchInfo() {
        somethingApplication.promises.push(SomethingRepo.patchAccount(vm.account).then(angular.noop, function(error) {
            somethingApplication.parseErrors(error, ‘Account error: ‘);
        }
        /* a few more patches */
        $q.all(somethingApplication.promises).then(function() {
            /* display dialog */
        }, angular.noop).finally(function() {
            postGet();
            somethingApplication.promises = [];
            if (somethingApplication.errors.length >= 1) {
                vm.errors = somethingApplication.errors;
            }
        });
    }
}

somethingApplication.service.js

function somethingApplication(SomethingRepo) {
    var promises = [], errors = [];

    var service = {
        promises: promises;
        errors = errors;
        parseErrors: parseErrors;
    };

    return service; 


    function parseErrors(error, base_string) {
        angular.forEach(error.data.erros, function(value_params, key_params) {
            this.errors.push(base_string + ‘ ‘ + key_params.replace(/_/g, ‘ ‘) + ‘ ‘ + value_params);
        }, this);
    }
}

somethingRepo.js

function SomethingRepo(Server) {
    function get() {
        return Server.get(‘/something/application’, null, {noGlobal: true});
    }
}

I have reduced the files, but they consist of more code like this. The point of the controller is to create or update an application for another website. On my website I have a form of fields corresponding to the form on the other website. If you already have filed for an application, but want to update it, the info you already filed are loaded from the other website.

The problem is, in order to create or update an application, a lot of different endpoints requested og posted to.

In AngularJS I store the promises from each request and run them asynchronously in the end. In TypeScript and Angular I want to use Observables and subscribe to the data change.

How do I get started? How do I subscribe to an Observable the requires parameters from another Observable? Any advice how to proceed?

Upvotes: 2

Views: 1198

Answers (1)

Tushar Walzade
Tushar Walzade

Reputation: 3809

Here's an example demonstrating how you can easily use observables in your scenario -

Your service would be something like this -

import { Injectable } from '@angular/core';
import { AppConstants } from '../../app.constants';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ExampleService {
    constructor(private appconstants: AppConstants, private http: HttpClient) { }

    get() {
        return this.http.get(this.appconstants.apiUrl);
    }

    getSomethingOne() {
        return this.http.get(this.appconstants.apiUrl1);
    }

    getSomethingTwo() {
        return this.http.get(this.appconstants.apiUrl2);
    }
}

Then simply use it in your component as follows -

import { Component } from '@angular/core';
import { forkJoin } from 'rxjs';
import { ExampleService } from '../services/example.service';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent {

    data;
    dataOne;
    dataTwo;

    constructor(private exampleService: ExampleService) { }

    getApplication() {
        const combined = forkJoin([
            this.exampleService.get(),
            this.exampleService.getSomethingOne(),
            this.exampleService.getSomethingTwo()
        ]);
        combined.subscribe(res => {
            this.data = res[0];
            this.dataOne = res[1];
            this.dataTwo = res[2];
        });
    }
}

Upvotes: 2

Related Questions