How to make a simple JSONP asynchronous request in Angular 2?

50,319

Solution 1

In the latest version of Angular

  1. Import HttpClientModule and HttpClientJsonpModule modules in your app module's definition file

     import {
         HttpClientModule,
         HttpClientJsonpModule
     } from '@angular/common/http';
    
     @NgModule({
     declarations: [
         //... List of components that you need.
     ],
     imports: [
         HttpClientModule,
         HttpClientJsonpModule,
         //...
     ],
     providers: [
         //...
     ],
     bootstrap: [AppComponent]
     })
    
  2. Inject http and map rxjs operator into your service:

     import {Injectable} from '@angular/core';
     import {HttpClient} from '@angular/http';
     import 'rxjs/add/operator/map';
    
     @Injectable()
     export class MegaSuperService {
        constructor(private _http: HttpClient) {}
     }
    
  3. Make JSONP requests in the following way:

     // inside your service
     this._http.jsonp('/api/get', 'callback').map(data => {
     // Do stuff.
     });
    

In Angular version 2 - version 4.3

  1. Import JSONP module in your app module's definition file:

     import {JsonpModule} from '@angular/http';
    
     @NgModule({
     declarations: [
         //... List of components that you need.
     ],
     imports: [
         JsonpModule,
         //...
     ],
     providers: [
         //...
     ],
     bootstrap: [AppComponent]
     })
    
  2. Inject jsonp service and map rxjs operator into your service:

     import {Injectable} from '@angular/core';
     import {Jsonp} from '@angular/http';
     import 'rxjs/add/operator/map';
    
     @Injectable()
     export class MegaSuperService {
        constructor(private _jsonp: Jsonp) {}
     }
    
  3. Make requests using "JSONP_CALLBACK" as a callback property:

     // inside your service
     this._jsonp.get('/api/get?callback=JSONP_CALLBACK').map(data => {
     // Do stuff.
     });
    

Solution 2

In Angular 4.3 and up you should use HttpClientModule because the JsonpModule is deprecated.

  1. Import HttpClientModule and HttpClientJsonpModule into your module.
  2. Inject HttpClient into your service.
  3. Pass the callback key as the second argument for the jsonp method.

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
// Import relevant http modules
import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http';

import { AppComponent } from './app.component';

import { ExampleService } from './example.service';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    // Import relevant http modules
    HttpClientModule,
    HttpClientJsonpModule
  ],
  providers: [ExampleService],
  bootstrap: [AppComponent]
})
export class AppModule { }

example.service.ts

import { Injectable } from '@angular/core';
// Import HttpClient class
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ExampleService {

  // Inject HttpClient class
  constructor(private http: HttpClient) { }

  getData() {
    const url = "https://archive.org/index.php?output=json&callback=archive";

    // Pass the key for your callback (in this case 'callback')
    // as the second argument to the jsonp method
    return this.http.jsonp(url, 'callback');
  }
}

Solution 3

If this endpoint is jsonp-compliant, you can use the following. You need to find out the parameter to use to provide the jsonp callback. In the code below, I call it c.

After having registered JSONP_PROVIDERS when calling the bootstrap function:

import {bootstrap} from 'angular2/platform/browser'
import {JSONP_PROVIDERS} from 'angular2/http'
import {AppComponent} from './app.component'

bootstrap(AppComponent, [ JSONP_PROVIDERS ]);

You can then execute your request using an instance of the Jsonp class you injected from constructor:

import {Component} from 'angular2/core';
import {Jsonp} from 'angular2/http';

@Component({
  selector: 'my-app',
  template: `
    <div>
      Result: {{result | json}}
    </div>
  `
})
export class AppComponent {
  constructor(jsonp:Jsonp) {
    var url = 'https://accounts.google.com/logout&c=JSONP_CALLBACK';
    jsonp.request(url, { method: 'Get' })
     .subscribe((res) => {
       (...)
     });
  }
}

See this question for more details:

Share:
50,319
nunoarruda
Author by

nunoarruda

Result-Oriented Front End Angular Engineer with a strong technical skill-set, attention to detail, and 17 years of experience. I have a passion for translating beautiful designs into functional user interfaces and building great web applications. I actively seek out new technologies and stay up-to-date on industry trends and advancements. Continued education has allowed me to stay ahead of the curve and deliver exceptional work to each employer I’ve worked for. I've successfully delivered projects like a CSS UI library used by 17,000 employees, a mobile app that has 120,000+ users, and a web app serving over 100 million images. I've done frontend work for Adobe, Webflow, Bayer, among other companies. I'm originally from Portugal but I've been working remotely for the last 6 years for companies worldwide. I can be flexible in order to have overlapping working hours with a distributed team.

Updated on February 27, 2021

Comments

  • nunoarruda
    nunoarruda about 3 years

    I'm trying to convert the following Angular 1 code to Angular 2:

    $http.jsonp('https://accounts.google.com/logout');
    

    It needs to be a JSONP request to skip the CORS policy issue.

  • MoshMage
    MoshMage over 7 years
    any idea why this "exact same code" can throw a EXCEPTION: Response with status: 200 Ok for URL: null, never entering in the map function ?
  • Gaston K
    Gaston K over 7 years
    I'm getting the follow error: Uncaught ReferenceError: __ng_jsonp____req0_finished is not defined and JSONP injected script did not invoke callback. Any idea? My api call has the jsonp parameter. api.instagram.com/v1/users/self/…{myAccesToken} I'm importing jsonp from angular/http and injecting in into the constructor. Also I added to the imports in the app.module.ts file.
  • nebulae
    nebulae about 7 years
    @MoshMage are you seeing that behavior in both IE & Chrome? Chrome is working fine for me, IE is throwing an error behind the scenes yet returning a response 200: OK to the subscription.
  • nebulae
    nebulae about 7 years
    @GastonK is the API expecting the callback to be "JSONP_CALLBACK"? angular overwrites this with the __ng_jsonp____req<count>_finished if it sees this exact string. see: github.com/angular/angular/blob/…
  • Rahul Upadhyay
    Rahul Upadhyay over 6 years
    Thank you. Just an addition to this answer, we need to replace 'callback' with 'JSONP_CALLBACK'.
  • Courtney Pattison
    Courtney Pattison over 6 years
    @RahulUpadhyay I've updated the answer with your correction. Thank you!
  • kcrisman
    kcrisman over 6 years
    As a data point, I found that not only was &callback=JSONP_CALLBACK unnecessary, it broke things - but perhaps that was in a different/newer/older version of Angular; anyway, it just "knew" to add and then remove the callback info for some reason. YMMV.
  • Courtney Pattison
    Courtney Pattison about 6 years
    @kcrisman Good catch! Looking at line 1124 of the HttpClient JSONP_CALLBACK is appended to the callback parameter. I'll update my answer now.
  • alex351
    alex351 over 3 years
    Now there is a new issue. Cross-Origin Read Blocking (CORB) blocked cross-origin response
  • workaholic
    workaholic almost 3 years
    This has changed little over time. However, 3rd-parties may have their own name for the callback parameter, that second argument to http.jsonp. I have seen 'callback' or 'c' most commonly. And so in the url in this answer, &callback=archive doesn't need to exist. Angular will add that parameter you name to the passed url, such as &callback=ng_jsonp_callback_0. The actual callback function should be the success function of the http.jsonp Observable. This extra bit helped me to deal with Pardot form submissions.