2

I'm actually working on an Angular 2 application but i have a some problems. Indeed, i have a method which get data from a database. However i'm trying to copy this data to an other one, to do that i need to do multiple HTTP request ( the requests number are never the same ).

Here is my migrate method. First I get the data from DB and then I try to post them in the other one

service.getDatas().subscribe( data => {
  let datas = data.json().data; 
  if (datas) {
    let requests = [];
    for (let data of datas) {
      let req = service.addData(data); // addData() return an Observable
      requests.push(req);
    }
    let c: Observable<any> = Observable.forkJoin(requests);
    return c;
  }
});

Or When i'm subribing to the method i have no Response from it.

Here is my subscriber

service.migrateData(targetDB).subscribe(res => {
      console.log(res);
    });

I want my method to return a Response when all the data has been post ! Actually when i'm calling the addData() method it doesn't even trigger the http request, nothing happens. I tryed to use some RxJs method like concat and forkJoin but nothing. Or just i failed using them.

Here is my addData() method

addData(data) {
    let headers = new Headers({
      'Content-Type': 'application/json'
    });
    headers.append('Authorization', 'Basic ' + btoa('username + ':' + 'password));
    let _data = JSON.stringify({data: data});
    return this.http.post('https://something.com', _data, {headers: headers});
  }

This method works very well for others use case.

Thanks for your help !

3
  • I think you need to subscribe to an observable before it is executed. service.addData(data).subscribe() Commented Nov 25, 2016 at 15:06
  • If i do this, forkjoin will have a subscriber array and not an observable array :/ ! Commented Nov 25, 2016 at 16:17
  • How about c.subscribe()? github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/… Commented Nov 26, 2016 at 0:11

2 Answers 2

1

Based on your code this is what I understood:

  1. Get some array from a service (from a rest call)
  2. Make a rest call for every element in that array
  3. Get a single result in the end when everything is done

const migrationStream$ = service.getDatas()
  .map(data => data.json().data || [])        // and alternative to the "|| []" could be a subsequent ".filter(data => data && data.length)"
  .switchMap(datas => Observable.from(datas)) // split up the js-array into a stream
  .concatMap(data => service.addData(data))
  // .map(singleMigrateResponse => doSomethingWith(singleMigrateResponse))  // optional, is called for every data that is migrated
  .toArray() // optional: this will wait for the previous part of the stream to complete and return an array of all results, remove this if you want to receive every result as a single "next"

// run it by using:
migrationStream$.subsribe(next..., error..., complete...);

This method works very well for others use case.

As a genereal note here: rxjs can be very poweful if used properly, almost everything can be written as a stream - as a rule of thumb you can remember to:

  • only use one subscribe per action (in your case the action is steps 1-3), if you are using more than one subscribe, you're not thinking in streams
  • try to avoid data-logic within the subscription, the subscription is best to be used for handling events/emits/results, e.g. migrationStream$.subscribe(..., ..., () => alert("Migration is complete!"));
Sign up to request clarification or add additional context in comments.

Comments

0

Here is my solution for multiple requests stream with 3 parallel requests

import {Component, OnInit} from '@angular/core';
import {HttpClient} from '@angular/common/http';

@Component({
    selector: 'app-multi-http',
    template: `<ul>
    <li *ngFor="let giphy of giphys"> <img src="{{giphy}}"  width="200px"/> </li>
    </ul>`,
})
export class MultiHttpComponent implements OnInit {
    // Requests stream vars
    maxRequests = 3;
    currentRequestsNbr = 0;
    requestsStream = ['run', 'jump', 'hide', 'fight', 'surprise', 'sleep'];

    giphys = [];

    constructor(public http: HttpClient) {
    }

    ngOnInit() {
        this.handleRequestsStream();
    }


    handleRequestsStream() {
        if (this.requestsStream.length > 0) {
            if (this.currentRequestsNbr < this.maxRequests) {
                ++this.currentRequestsNbr;
                const searchTerm = this.requestsStream.shift();
                this.getGiphy(searchTerm).subscribe(
                    url => {
                        this.giphys.push(url);
                    },
                    error => {
                        console.log(error);
                    },
                    () => {
                        --this.currentRequestsNbr;
                        // Try next request on complete
                        this.handleRequestsStream();
                    }
                );
                // Try next request
                this.handleRequestsStream();
            }
        }
    }

    getGiphy(searchTerm) {
        const apiLink = '//api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=' + searchTerm;
        return this.http.get(apiLink).map((response: any) => {
            if (response.data.length > 0) {
                return response.data[0].images.original.url;
            } else {
                return 'https://media.giphy.com/media/YaOxRsmrv9IeA/giphy.gif'; // dancing cat for 404
            }
        });
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.