Search code examples
javascriptangularangular2-http

How to make a chained requests(various number) with angular 2


Update Found solution

I want to get all pages from instagram api (https://api.instagram.com/v1/tags/{tag-name}/media/recent?access_token=ACCESS-TOKEN) In it's response there is 'next_url' parameter, using which you can get new page. I tried recursion, but it's killing browser at ~13 step; Component:

import { Component, OnInit } from '@angular/core';
import {InstagramService} from './instagram.service';

import {Search} from '../search';

@Component({
   selector: 'app-test',
   templateUrl: './test.component.html',
   styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {

  posts: Post[];
  tag: String = 'blabla23';
  constructor(
    private instagramService: InstagramService
  ) {}

  ngOnInit() {
    this.getPosts();
    this.posts = [];
  }

  getPosts(nextUrl?: string): void {
    this.instagramService
        .getTagMedia(this.tag, nextUrl)
        .then((result: Search) => {
            this.posts = this.posts.concat(this.posts, result.getMedia());
            if (result.getNextUrl() != null) {
                this.getPosts(result.getNextUrl().toString());
            }
        });
  }

}

Service:

 import { Injectable } from '@angular/core';
 import { Jsonp, Response, Headers, RequestOptions} from '@angular/http';
 import { Observable } from 'rxjs/Observable';
 import 'rxjs/add/operator/toPromise';
 import 'rxjs/add/operator/delay';
 import { Search } from './search';

@Injectable()
export class InstagramService {
  private apiUrl = 'https://api.instagram.com/v1/'; 
  private token = 'blalba';

  constructor (private jsonp: Jsonp) {}

  public getTagMedia(tag: String, url: string|null): Promise<Search> {
    url = url || `${this.apiUrl}tags/${tag}/media/recent?access_token=${this.token}`;
    url = `${url}&callback=JSONP_CALLBACK`
    return this.jsonp.get(url)
                    .toPromise()
                    .then(response => { return new Search(response.json());}) 
  }
}

Search model:

export class Search {
  private data;
  private metadata;
  private pagination;

  constructor(row) {
    this.data = row.data;
    this.metadata = row.metadata;
    this.pagination = row.pagination;
  }

  public getNextUrl(): string | null {
    return this.pagination.next_url || null;
  }

  public getMedia()  {
    return this.data;
  }

}

I know about Observable.flatMap() but failed to use it in this case because of unknown number of requests.

How to get all the api pages? ps I am new to Angular 2 and js at all. pps sorry for my English


Solution

  • I did it (recursion and Promises) wrong. Working solution (Service):

    @Injectable()
    export class InstagramService {
      private apiUrl = 'https://api.instagram.com/v1/';
      private token = 'blabla';
      private pagesLimit = 5;
    
      constructor (private jsonp: Jsonp) {}
    
      public getTagMedia(tag: string): Promise<Post[]> {
        let url = `${this.apiUrl}tags/${tag}/media/recent?access_token=${this.token}`;
        url = `${url}&callback=JSONP_CALLBACK`;
    
        return this.getPosts(url, 0);
      }
    
      public getPosts(url: string, page: number): Promise<Post[]> {
    
        return this.jsonp.get(url)
            .delay(200)
            .toPromise()
            .then(response => {
                let search = new Search(response.json());
                let nextUrl = search.getNextUrl();
    
                if (nextUrl && page < this.pagesLimit) {
                    nextUrl = `${nextUrl}&callback=JSONP_CALLBACK`;
                    return this.getPosts(nextUrl, ++page)
                                .then(res => search.getMedia().concat(res))
                } else {
                    return search.getMedia();
                }
            })
            .catch(this.handleError);
      }
    
      private handleError (error: Response | any) {
        console.log(error);
      }
    }