Angular2: Speech IMDB using Angular2, Typescript, Web API and ASP.NET MVC

Standard

Speech based Search Movie Web App using Angular2, TypeScript, BING API, ASP.NET MVC, Web API & Web Speech API

This web application assist you to search movies and seasons through voice. Just say any keyword from movie and season name and then command by saying term search to look from millions of record rapidly.

Project Website

Project Code


Dashboard

This is the homepage of application and displays latest Hollywood news at the moment. BING API has been used over here to retrieve latest Hollywood news.

screenshot_1


Manual Search

Just for the ease, manual search has been provided with parameter likes searching content name, year, content type(movie, series, episode). Please note year and type are optional.

screenshot_2


Voice Search

Awesome part starts from here, you may say any thing to search for movie, series and episode. You will also able to see on runtime in message box and console window what keyword your have voiced out to search.

screenshot_8

screenshot_9

screenshot_10

screenshot_11


Movie List Page

This page shows list of all movies, series and episode relevant to your search keyword, pagination has been implemented in case of large returned data set along with sorting functionality. Thumbnail associated with each record will help you to quickly pick your content.

screenshot_6


Movie Detail Page

This page shows full detail of user selected movie/series/episode. It displays unique url to checkout content’s reviews on IMDB , content’s rating, votes and full fledged poster.

screenshot_7

Angular2: Using Speech Recognition of Web Speech API in Angular2

Standard

Speech Recognition functionality of the Web Speech API in Angular2 application

Speech Recognition

Speech recognition involves receiving speech through a device’s microphone, which is then checked by a speech recognition service against a list of grammar (basically, the vocabulary you want to have recognised in a particular app.) When a word or phrase is successfully recognised, it is returned as a result (or list of results) as a text string, and further actions can be initiated as a result.

The Web Speech API has a main controller interface for this — SpeechRecognition — plus a number of closely-related interfaces for representing grammar, results, etc. Generally, the default speech recognition system available on the device will be used for the speech recognition — most modern OSes have a speech recognition system for issuing voice commands. Think about Dictation on Mac OS X, Siri on iOS, Cortana on Windows 10, Android Speech, etc.


Chrome support

As mentioned earlier, Chrome currently supports speech recognition with prefixed properties, therefore at the start of our code we include these lines to feed the right objects to Chrome, and non-prefix browsers, like Firefox:

var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition
var SpeechGrammarList = SpeechGrammarList || webkitSpeechGrammarList
var SpeechRecognitionEvent = SpeechRecognitionEvent || webkitSpeechRecognitionEvent  

Properties

  • SpeechRecognition.lang: Sets the language of the recognition. Setting this is good practice, and therefore recommended.
  • SpeechRecognition.interimResults: Defines whether the speech recognition system should return interim results, or just final results. Final results are good enough for this simple demo.
  • SpeechRecognition.maxAlternatives: Sets the number of alternative potential matches that should be returned per result.
          recognition.continuous = false;
          recognition.lang = 'en-US';
          recognition.interimResults = false;
          recognition.maxAlternatives = 1;
    

Event handlers

  • SpeechRecognition.onaudiostartFired when the user agent has started to capture audio.
  • SpeechRecognition.onaudioendFired when the user agent has finished capturing audio.
  • SpeechRecognition.onendFired when the speech recognition service has disconnected.
  • SpeechRecognition.onerrorFired when a speech recognition error occurs.
  • SpeechRecognition.onnomatchFired when the speech recognition service returns a final result with no significant recognition. This may involve some degree of recognition, which doesn’t meet or exceed the confidence threshold.
  • SpeechRecognition.onresultFired when the speech recognition service returns a result — a word or phrase has been positively recognized and this has been communicated back to the app.
  • SpeechRecognition.onstartFired when the speech recognition service has begun listening to incoming audio with intent to recognize grammars associated with the current SpeechRecognition.

Method

  • SpeechRecognition.abort()Stops the speech recognition service from listening to incoming audio, and doesn’t attempt to return a SpeechRecognitionResult.
  • SpeechRecognition.start()Starts the speech recognition service listening to incoming audio with intent to recognize grammars associated with the current SpeechRecognition.
  • SpeechRecognition.stop()Stops the speech recognition service from listening to incoming audio, and attempts to return a SpeechRecognitionResult using the audio captured so far.

Starting the speech recognition

recognition.start();

Receiving and handling results

recognition.onresult = function(event) {
  var last = event.results.length - 1;
  console.log(event.results[last][0].transcript);
  console.log('Confidence: ' + event.results[0][0].confidence);
}

The SpeechRecognitionEvent.results property returns a SpeechRecognitionResultList object containing SpeechRecognitionResult objects. It has a getter so it can be accessed like an array — so the [last] returns the SpeechRecognitionResult at the last position. Each SpeechRecognitionResult object contains SpeechRecognitionAlternative objects that contain individual recognised words. These also have getters so they can be accessed like arrays — the [0] therefore returns the SpeechRecognitionAlternative at position 0

Stopping the speech recognition

recognition.stop(); 

Handling error in the speech recognition

SpeechRecognition.onerror handles cases where there is an actual error with the recognition successfully — the SpeechRecognitionError.error property contains the actual error returned:

recognition.onerror = function(event) {
  console.log(event.error);
}

Web Speech API in Angular2

See extended DEMO on Github

Angular2 Service using Web Speech API

import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import * as _ from "lodash";

interface IWindow extends Window {
    webkitSpeechRecognition: any;
    SpeechRecognition: any;
}

@Injectable()
export class SpeechRecognitionService {
    speechRecognition: any;

    constructor(private zone: NgZone) {
    }

    record(): Observable<string> {

        return Observable.create(observer => {
            const { webkitSpeechRecognition }: IWindow = <IWindow>window;
            this.speechRecognition = new webkitSpeechRecognition();
            //this.speechRecognition = SpeechRecognition;
            this.speechRecognition.continuous = true;
            //this.speechRecognition.interimResults = true;
            this.speechRecognition.lang = 'en-us';
            this.speechRecognition.maxAlternatives = 1;

            this.speechRecognition.onresult = speech => {
                let term: string = "";
                if (speech.results) {
                    var result = speech.results[speech.resultIndex];
                    var transcript = result[0].transcript;
                    if (result.isFinal) {
                        if (result[0].confidence < 0.3) {
                            console.log("Unrecognized result - Please try again");
                        }
                        else {
                            term = _.trim(transcript);
                            console.log("Did you said? -> " + term + " , If not then say something else...");
                        }
                    }
                }
                this.zone.run(() => {
                    observer.next(term);
                });
            };

            this.speechRecognition.onerror = error => {
                observer.error(error);
            };

            this.speechRecognition.onend = () => {
                observer.complete();
            };

            this.speechRecognition.start();
            console.log("Say something - We are listening !!!");
        });
    }

    DestroySpeechObject() {
        if (this.speechRecognition)
            this.speechRecognition.stop();
    }

}

Component using above service

import { Component, OnInit, OnDestroy} from '@angular/core';
import { SpeechRecognitionService } from './speech-recognition.service';

@Component({
    selector: 'my-app',
    templateUrl: './App/app.component.html'
})

export class AppComponent implements OnInit, OnDestroy {
    showSearchButton: boolean;
    speechData: string;

    constructor(private speechRecognitionService: SpeechRecognitionService) {
        this.showSearchButton = true;
        this.speechData = "";
    }

    ngOnInit() {
        console.log("hello")
    }

    ngOnDestroy() {
        this.speechRecognitionService.DestroySpeechObject();
    }

    activateSpeechSearchMovie(): void {
        this.showSearchButton = false;

        this.speechRecognitionService.record()
            .subscribe(
            //listener
            (value) => {
                this.speechData = value;
                console.log(value);
            },
            //errror
            (err) => {
                console.log(err);
                if (err.error == "no-speech") {
                    console.log("--restatring service--");
                    this.activateSpeechSearchMovie();
                }
            },
            //completion
            () => {
                this.showSearchButton = true;
                console.log("--complete--");
                this.activateSpeechSearchMovie();
            });
    }

}

Usage

Before using project Install dependencies by typing below command in CMD:

npm install --save --save-dev

Output

Initial State:

screenshot_19

Example1:

screenshot_20

Example2:

screenshot_21

Reference

Text Reference.

API Reference

Angular2: Error – Can’t bind to ‘ngModel’ since it isn’t a known property of ‘input’.

Standard

In order to implement two way binding in Angular2 application, you have to use [(ngModel)] binding in html code, but in case if you have receive below error:

“Can’t bind to ‘ngModel’ since it isn’t a known property of ‘input’.”

screenshot_18

Solution:

You need to import the FormsModule package in your Angular module

import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';

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

@NgModule({
    imports: [
        //angular builtin module
        BrowserModule,
        FormsModule
    ],
    declarations: [
        AppComponent
    ],
    providers: [
    ],
    bootstrap: [
        AppComponent
    ]
})

export class AppModule {
}

Angular2: Error in firefox – EXCEPTION: SyntaxError: JSON.parse: unexpected character of the JSON data

Standard

While working with webservices in Angular2 using promises or observable, if you have receive below issue in Firefox browser, it is most likely, you need to set accept header in http get/post request

“EXCEPTION: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data”

Solution:

You need to append Accept headers to your get request in order for Firefox to render the json that comes back.

In the headers object, the Content-Type specifies that the body represents JSON. The headers object is used to configure the options object. The options object is a new instance of RequestOptions, a class that allows you to specify certain settings when instantiating a request. In this way, headers is one of the RequestOptions.

In the return statement, options is the third argument of the post method, as shown above.

    ngOnInit() {
        let headers = new Headers();
        headers.append('Accept', 'q=0.8;application/json;q=0.9');
        return this.http.get(this.url, { headers: headers } )
                   .map(data => console.log(data.json()))
                   .subscribe(err => console.log(err));
    }

Angular2: Restful Webservice For Angular2 Using Observable

Standard

Restful implementation of GET, POST, DELETE, PATCH, PUT in Angular2 using Observable

The Angular Http client communicates with the server using a familiar HTTP request/response protocol. The Http client is one of a family of services in the Angular HTTP library. When importing from the @angular/http module, SystemJS knows how to load services from the Angular HTTP library because the systemjs.config.js file maps to that module name. The HttpModule is necessary for making HTTP calls.

Benefits of using Global Service (web-api-observable.service.ts):

  • This will contain shared/global service which will be consumed by all modules for executing CRUD operation, Request Type, URL, Parameter Object will be passed to this shared service, so it will make code more maintainable, readable and scalable
  • If we dont go through this method then we have to use $http.get() or $http.post method every where in services files of each module
  • content negotiation issues can be simply handled over here
  • If you want to append anything with each URL like ‘Http:\mydomain\’ then instead of copy it on every service file just hard-code this thing in this file and append URL from their respective services.
  • We don’t need to mention protocol and host-name now in every URL request.

Observable

Think of an Observable as a stream of events published by some source. To listen for events in this stream, subscribe to the Observable. These subscriptions specify the actions to take when the web request produces a success event or a fail event (with the error in the payload).

  • The observable’s map callback moves to the success parameter and its catch callback to the fail parameter in this pattern.
  • The errorHandler forwards an error message as a failed promise instead of a failed observable.

Observable vs Promises

The less obvious but critical difference is that these two methods return very different results.

  • The promise-based then returns another promise. You can keep chaining more then and catch calls, getting a new promise each time.
  • The subscribe method returns a Subscription. A Subscription is not another Observable. It’s the end of the line for observables. You can’t call map on it or call subscribe again. The Subscription object has a different purpose, signified by its primary method, unsubscribe.

RxJS library

  • RxJS (“Reactive Extensions”) is a 3rd party library, endorsed by Angular, that implements the asynchronous observable pattern.
  • RxJS npm package loaded via system.js because observables are used widely in Angular applications.
  • The app needs it when working with the HTTP client. Additionally, you must take a critical extra step to make RxJS observables usable.
  • The RxJS library is large. Size matters when building a production application and deploying it to mobile devices. You should include only necessary features.
  • Accordingly, Angular exposes a stripped down version of Observable in the rxjs/Observable module that lacks most of the operators such as the map method.
  • You could add every RxJS operator with a single import statement. While that is the easiest thing to do, you’d pay a penalty in extended launch time and application size because the full library is so big.
  • Since this app only uses a few operators, it’s better to import each Observable operator and static class method, one-by-one, for a custom Observable implementation tuned precisely to the app’s requirements. Put the import statements in one app/rxjs-operators.ts file.

See extended DEMO on Github

HTTP GET Code (web-api-observable.service.ts)

The Http.get method takes an object that implements RequestOptionsArgs as a second parameter.

  • Plain HTTP GET using Observable without any parameters

    getService(url: string): Observable<any> {
    return this.http
        .get(url, this.options)
        .map(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

    this.movieObservableService .getService(‘api/Movie/TestGetNo’) .subscribe( result => console.log(result), error => this.errorMessage = error );

  • HTTP GET using Observable with single query string term

    getServiceWithDynamicQueryTerm(url: string, key: string, val: string): Observable<any> {
    return this.http
        .get(url + "/?" + key + "=" + val, this.options)
        .map(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

    this.movieObservableService
        .getServiceWithDynamicQueryTerm('api/Movie/TestGetParam', "query", "hello")
        .subscribe(
            result => console.log(result),
            error => this.errorMessage = <any>error
    );    
    
  • HTTP GET using Observable with multiple query string term

    getServiceWithMultipleQueryTerm(url: string, query: string): Observable<any> {
          return this.http
              .get(url + "/?" + query, this.options)
              .map(this.extractData)
              .catch(this.handleError);
    }
    

    Consumer Code in custom component:

    this.movieObservableService
        .getServiceWithMultipleQueryTerm('api/Movie/TestGetParam', "id=1&&name=abc")
        .subscribe(
            result => console.log(result),
            error => this.errorMessage = <any>error
    ); 
    
  • HTTP GET using Observable with hardcode query string term

    The search field of that object can be used to set a string or a URLSearchParams object.

      getServiceWithFixedQueryString(url: string, param: any): Observable<any> {
      this.options = new RequestOptions({ headers: this.headers, search: 'query=' + param });
      return this.http
          .get(url, this.options)
          .map(this.extractData)
          .catch(this.handleError);
      }         
    

    Consumer Code in custom component:

      this.movieObservableService
          .getServiceWithFixedQueryString('api/Movie/TestGetParam', 'abc')
          .subscribe(
              result => console.log(result),
              error => this.errorMessage = <any>error
      );
    
  • HTTP GET using Observable with complex object as query string

    The search field of that object can be used to set a string or a URLSearchParams object.

      getServiceWithComplexObjectAsQueryString(url: string, param: any): Observable<any> {
      let params: URLSearchParams = new URLSearchParams();
      for (var key in param) {
          if (param.hasOwnProperty(key)) {
              let val = param[key];
              params.set(key, val);
          }
      }
      this.options = new RequestOptions({ headers: this.headers, search: params });
      return this.http
          .get(url, this.options)
          .map(this.extractData)
          .catch(this.handleError);
      }     
    

    Consumer Code in custom component:

      this.movieObservableService
          .getServiceWithComplexObjectAsQueryString('api/Movie/TestGet', "{ id: '1', name: 'abc'}")
          .subscribe(
              result => console.log("4. getServiceWithComplexObjectAsQueryString: " + result),
              error => this.errorMessage = <any>error
      );
    

HTTP POST Producer Code (web-api-observable.service.ts)

The Http.post method takes body as second parameter and an object that implements RequestOptionsArgs as a third parameter.

  • HTTP POST using Observable with body object as parameter

    createService(url: string, param: any): Observable<any> {
    let body = JSON.stringify(param);
    return this.http
        .post(url, body, this.options)
        .map(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

    this.movieObservableService
        .createService('api/Movie/TestPost', "{ id: '1', name: 'abc'}")
        .subscribe(
            result => console.log(result),
            error => this.errorMessage = <any>error
    );
    

HTTP PUT Producer Code (web-api-observable.service.ts)

The Http.put method takes body as second parameter and an object that implements RequestOptionsArgs as a third parameter.

  • HTTP PUT using Observable with body object as parameter

    updateService(url: string, param: any): Observable<any> {
    let body = JSON.stringify(param);
    return this.http
        .put(url, body, this.options)
        .map(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

     this.movieObservableService
        .updateService('api/Movie/TestPost', "{ id: '1', name: 'abc'}")
        .subscribe(
            result => console.log(result),
            error => this.errorMessage = <any>error
    );
    

HTTP PATCH Producer Code (web-api-observable.service.ts)

The Http.patch method takes body as second parameter and an object that implements RequestOptionsArgs as a third parameter.

  • HTTP PATCH using Observable with body object as parameter

    patchService(url: string, param: any): Observable<any> {
    let body = JSON.stringify(param);
    return this.http
        .patch(url, body, this.options)
        .map(this.extractData)
        .catch(this.handleError);
    }   
    

    Consumer Code in custom component:

    this.movieObservableService
        .patchService('api/Movie/TestPost', "{ id: '1', name: 'abc'}")
        .subscribe(
            result => console.log(result),
            error => this.errorMessage = <any>error
    );
    

HTTP DELETE Producer Code (web-api-observable.service.ts)

The Http.delete method takes an object that implements RequestOptionsArgs as a second parameter.

  • HTTP DELETE using Observable with ID as parameter

    deleteServiceWithId(url: string, key: string, val: string): Observable<any> {
    return this.http
        .delete(url + "/?" + key + "=" + val, this.options)
        .map(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

     this.movieObservableService
        .deleteServiceWithId('api/Movie/TestDeleteWithId', "id", "8631")
        .subscribe(
            result => console.log(result),
            error => this.errorMessage = <any>error
      );
    
  • HTTP DELETE using Observable with complex object as parameter

    The search field of that object can be used to set a string or a URLSearchParams object.

    deleteService(url: string, param: any): Observable<any> {
    let params: URLSearchParams = new URLSearchParams();
    for (var key in param) {
        if (param.hasOwnProperty(key)) {
            let val = param[key];
            params.set(key, val);
        }
    }
    this.options = new RequestOptions({ headers: this.headers, search: params });
    return this.http
        .delete(url, this.options)
        .map(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

     this.movieObservableService
        .deleteService('api/Movie/TestPost', "{ id: '1', name: 'abc'}")
        .subscribe(
            result => console.log(result),
            error => this.errorMessage = <any>error
    );
    

Important Note

You need to append Accept headers to your get request in order for Firefox to render the json that comes back.

In the headers object, the Content-Type specifies that the body represents JSON. The headers object is used to configure the options object. The options object is a new instance of RequestOptions, a class that allows you to specify certain settings when instantiating a request. In this way, headers is one of the RequestOptions.

In the return statement, options is the third argument of the post method, as shown above.

    ngOnInit() {
        let headers = new Headers();
        headers.append('Accept', 'q=0.8;application/json;q=0.9');
        return this.http.get(this.url, { headers: headers } ).map(res => {
                  return res.json();
                }).subscribe((response) => { console.log(response) });
    }

Restful HTTP Service using Observable

Angular injects a WebApiObservableService into the constructor and the component calls that service to fetch and save data. The component does not talk directly to the Angular Http client. The component doesn’t know or care how it gets the data. It delegates to the WebApiObservableService. This is a golden rule: always delegate data access to a supporting service class.

See extended DEMO on Github

  import { Injectable } from '@angular/core';
  import { Http, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
  import { Observable } from 'rxjs/Observable';

  // Observable class extensions
  import 'rxjs/add/observable/of';
  import 'rxjs/add/observable/throw';

  // Observable operators
  import 'rxjs/add/operator/catch';
  import 'rxjs/add/operator/debounceTime';
  import 'rxjs/add/operator/distinctUntilChanged';
  import 'rxjs/add/operator/do';
  import 'rxjs/add/operator/filter';
  import 'rxjs/add/operator/map';
  import 'rxjs/add/operator/switchMap';

  import { ToasterService } from './alert.service';
  import { LoaderService } from './loader.service';

  @Injectable()
  export class WebApiObservableService {
      headers: Headers;
      options: RequestOptions;

      constructor(private http: Http,
          private toasterService: ToasterService,
          private loaderService: LoaderService) {
          this.headers = new Headers({ 'Content-Type': 'application/json', 
                                    'Accept': 'q=0.8;application/json;q=0.9' });
          this.options = new RequestOptions({ headers: this.headers });
      }

      getService(url: string): Observable<any> {
          return this.http
              .get(url, this.options)
              .map(this.extractData)
              .catch(this.handleError);
      }

      getServiceWithDynamicQueryTerm(url: string, key: string, val: string): Observable<any> {
          return this.http
              .get(url + "/?" + key + "=" + val, this.options)
              .map(this.extractData)
              .catch(this.handleError);
      }

      getServiceWithMultipleQueryTerm(url: string, query: string): Observable<any> {
          return this.http
              .get(url + "/?" + query, this.options)
              .map(this.extractData)
              .catch(this.handleError);
      }

      getServiceWithFixedQueryString(url: string, param: any): Observable<any> {
          this.options = new RequestOptions({ headers: this.headers, search: 'query=' + param });
          return this.http
              .get(url, this.options)
              .map(this.extractData)
              .catch(this.handleError);
      }

      getServiceWithComplexObjectAsQueryString(url: string, param: any): Observable<any> {
          let params: URLSearchParams = new URLSearchParams();
          for (var key in param) {
              if (param.hasOwnProperty(key)) {
                  let val = param[key];
                  params.set(key, val);
              }
          }
          this.options = new RequestOptions({ headers: this.headers, search: params });
          return this.http
              .get(url, this.options)
              .map(this.extractData)
              .catch(this.handleError);
      }

      createService(url: string, param: any): Observable<any> {
          let body = JSON.stringify(param);
          return this.http
              .post(url, body, this.options)
              .map(this.extractData)
              .catch(this.handleError);
      }

      updateService(url: string, param: any): Observable<any> {
          let body = JSON.stringify(param);
          return this.http
              .put(url, body, this.options)
              .map(this.extractData)
              .catch(this.handleError);
      }

      patchService(url: string, param: any): Observable<any> {
          let body = JSON.stringify(param);
          return this.http
              .patch(url, body, this.options)
              .map(this.extractData)
              .catch(this.handleError);
      }

      deleteService(url: string, param: any): Observable<any> {
          let params: URLSearchParams = new URLSearchParams();
          for (var key in param) {
              if (param.hasOwnProperty(key)) {
                  let val = param[key];
                  params.set(key, val);
              }
          }
          this.options = new RequestOptions({ headers: this.headers, search: params });
          return this.http
              .delete(url, this.options)
              .map(this.extractData)
              .catch(this.handleError);
      }

      deleteServiceWithId(url: string, key: string, val: string): Observable<any> {
          return this.http
              .delete(url + "/?" + key + "=" + val, this.options)
              .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);
          this.toasterService.showToaster('error', 'Oops!! An error occurred', errMsg);
          this.loaderService.displayLoader(false);
          return Observable.throw(errMsg);
      }
  }

Text Reference

Angular2: Restful Webservice For Angular2 Using Promises

Standard

Restful implementation of GET, POST, DELETE, PATCH, PUT in Angular2 using Promises

The Angular Http client communicates with the server using a familiar HTTP request/response protocol. The Http client is one of a family of services in the Angular HTTP library. When importing from the @angular/http module, SystemJS knows how to load services from the Angular HTTP library because the systemjs.config.js file maps to that module name. The HttpModule is necessary for making HTTP calls.

Benefits of using Global Service (web-api-promise.service.ts):

  • This will contain shared/global service which will be consumed by all modules for executing CRUD operation, Request Type, URL, Parameter Object will be passed to this shared service, so it will make code more maintainable, readable and scalable
  • If we dont go through this method then we have to use $http.get() or $http.post method every where in services files of each module
  • content negotiation issues can be simply handled over here
  • If you want to append anything with each URL like ‘Http:\mydomain\’ then instead of copy it on every service file just hard-code this thing in this file and append URL from their respective services.
  • We don’t need to mention protocol and host-name now in every URL request.

Promise

Although the Angular http client API returns an Observable you can turn it into a Promise. It’s easy to do, and in simple cases, a promise-based version looks much like the observable-based version:

  • You can follow the promise then(this.extractData).catch(this.handleError) pattern.
  • Alternatively, you can call toPromise(success, fail). i.e. -> .toPromise(this.extractData, this.handleError).
  • The errorHandler forwards an error message as a failed promise instead of a failed promises.

See extended DEMO on Github

HTTP GET Code (web-api-promise.service.ts)

The Http.get method takes an object that implements RequestOptionsArgs as a second parameter.

  • Plain HTTP GET using Promises without any parameters

    getService(url: string): Promise<any> {
    return this.http
        .get(url, this.options)
        .toPromise()
        .then(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

    this.moviePromiseService
      .getService('api/Movie/TestGetNo')
      .then(result => console.log(result))
      .catch(error => console.log(error));
    
  • HTTP GET using Promises with single query string term

    getServiceWithDynamicQueryTerm(url: string, key: string, val: string): Promise<any> {
    return this.http
        .get(url + "/?" + key + "=" + val, this.options)
        .toPromise()
        .then(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

    this.moviePromiseService
      .getServiceWithDynamicQueryTerm('api/Movie/TestGetParam', "query","hello")
      .then(result => console.log(result))
      .catch(error => console.log(error));     
    
  • HTTP GET using Promises with multiple query string term

    getServiceWithMultipleQueryTerm(url: string, query: string): Promise<any> {
    return this.http
        .get(url + "/?" + query, this.options)
        .toPromise()
        .then(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

    this.moviePromiseService
      .getServiceWithMultipleQueryTerm('api/Movie/TestGetParam', "id=1&&name=abc")
      .then(result => console.log(result))
      .catch(error => console.log(error));
    
  • HTTP GET using Promises with hardcode query string term

    The search field of that object can be used to set a string or a URLSearchParams object.

      getServiceWithFixedQueryString(url: string, param: any): Promise<any> {
      this.options = new RequestOptions({ headers: this.headers, search: 'query=' + param });
      return this.http
          .get(url, this.options)
          .toPromise()
          .then(this.extractData)
          .catch(this.handleError);
      }          
    

    Consumer Code in custom component:

      this.moviePromiseService
        .getServiceWithFixedQueryString('api/Movie/TestGetParam', 'abc')
        .then(result => console.log(result))
        .catch(error => console.log(error));
    
  • HTTP GET using Promises with complex object as query string

    The search field of that object can be used to set a string or a URLSearchParams object.

      getServiceWithComplexObjectAsQueryString(url: string, param: any): Promise<any> {
      let params: URLSearchParams = new URLSearchParams();
      for (var key in param) {
          if (param.hasOwnProperty(key)) {
              let val = param[key];
              params.set(key, val);
          }
      }
      this.options = new RequestOptions({ headers: this.headers, search: params });
      return this.http
          .get(url, this.options)
          .toPromise()
          .then(this.extractData)
          .catch(this.handleError);
      }      
    

    Consumer Code in custom component:

      this.moviePromiseService
        .getServiceWithComplexObjectAsQueryString('api/Movie/TestGet', "{ id: '1', name: 'abc'}")
        .then(result => console.log(result))
        .catch(error => console.log(error));
    

HTTP POST Producer Code (web-api-promise.service.ts)

The Http.post method takes body as second parameter and an object that implements RequestOptionsArgs as a third parameter.

  • HTTP POST using Promises with body object as parameter

    createService(url: string, param: any): Promise<any> {
    let body = JSON.stringify(param);
    return this.http
        .post(url, body, this.options)
        .toPromise()
        .then(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

    this.moviePromiseService
      .createService('api/Movie/TestPost', "{ id: '1', name: 'abc'}")
      .then(result => console.log(result))
      .catch(error => console.log(error));
    

HTTP PUT Producer Code (web-api-promise.service.ts)

The Http.put method takes body as second parameter and an object that implements RequestOptionsArgs as a third parameter.

  • HTTP PUT using Promises with body object as parameter

    updateService(url: string, param: any): Promise<any> {
    let body = JSON.stringify(param);
    return this.http
        .put(url, body, this.options)
        .toPromise()
        .then(this.extractData)
        .catch(this.handleError);
    } 
    

    Consumer Code in custom component:

    this.moviePromiseService
      .updateService('api/Movie/TestPost', "{ id: '1', name: 'abc'}")
      .then(result => console.log(result))
      .catch(error => console.log(error));
    

HTTP PATCH Producer Code (web-api-promise.service.ts)

The Http.patch method takes body as second parameter and an object that implements RequestOptionsArgs as a third parameter.

  • HTTP PATCH using Promises with body object as parameter

    patchService(url: string, param: any): Promise<any> {
    let body = JSON.stringify(param);
    return this.http
        .patch(url, body, this.options)
        .toPromise()
        .then(this.extractData)
        .catch(this.handleError);
    }    
    

    Consumer Code in custom component:

    this.moviePromiseService
      .patchService('api/Movie/TestPost', "{ id: '1', name: 'abc'}")
      .then(result => console.log(result))
      .catch(error => console.log(error));
    

HTTP DELETE Producer Code (web-api-promise.service.ts)

The Http.delete method takes an object that implements RequestOptionsArgs as a second parameter.

  • HTTP DELETE using Promises with ID as parameter

    deleteServiceWithId(url: string, val: string): Promise<any> {
    return this.http
        .delete(url + "/?id=" + val, this.options)
        .toPromise()
        .then(this.extractData)
        .catch(this.handleError);
    } 
    

    Consumer Code in custom component:

    this.moviePromiseService
      .deleteServiceWithId('api/Movie/TestGetNo', 111)
      .then(result => console.log(result))
      .catch(error => console.log(error));
    
  • HTTP DELETE using Promises with complex object as parameter

    The search field of that object can be used to set a string or a URLSearchParams object.

    deleteService(url: string, param: any): Promise<any> {
    let params: URLSearchParams = new URLSearchParams();
    for (var key in param) {
        if (param.hasOwnProperty(key)) {
            let val = param[key];
            params.set(key, val);
        }
    }
    this.options = new RequestOptions({ headers: this.headers, search: params });
    return this.http
        .delete(url, this.options)
        .toPromise()
        .then(this.extractData)
        .catch(this.handleError);
    }
    

    Consumer Code in custom component:

    this.moviePromiseService
      .deleteService('api/Movie/TestPost', "{ id: '1', name: 'abc'}")
      .then(result => console.log(result))
      .catch(error => console.log(error));
    

Important Note

You need to append Accept headers to your get request in order for Firefox to render the json that comes back.

In the headers object, the Content-Type specifies that the body represents JSON. The headers object is used to configure the options object. The options object is a new instance of RequestOptions, a class that allows you to specify certain settings when instantiating a request. In this way, headers is one of the RequestOptions.

In the return statement, options is the third argument of the post method, as shown above.

    ngOnInit() {
        let headers = new Headers();
        headers.append('Accept', 'q=0.8;application/json;q=0.9');
        return this.http.get(this.url, { headers: headers } )
                   .map(data => console.log(data.json()))
                   .subscribe(err => console.log(err));
    }

Restful HTTP Service using Promises

Angular injects a WebApiPromiseService into the constructor and the component calls that service to fetch and save data. The component does not talk directly to the Angular Http client. The component doesn’t know or care how it gets the data. It delegates to the WebApiPromiseService. This is a golden rule: always delegate data access to a supporting service class.

See extended DEMO on Github

  import { Injectable } from '@angular/core';
  import { Http, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
  import 'rxjs/add/operator/toPromise';

  import { ToasterService } from './alert.service';
  import { LoaderService } from './loader.service';

  @Injectable()
  export class WebApiPromiseService {
      headers: Headers;
      options: RequestOptions;

      constructor(private http: Http,
          private toasterService: ToasterService,
          private loaderService: LoaderService) {
          this.headers = new Headers({ 'Content-Type': 'application/json', 
                                       'Accept': 'q=0.8;application/json;q=0.9' });
          this.options = new RequestOptions({ headers: this.headers });
      }

      getService(url: string): Promise<any> {
          return this.http
              .get(url, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      getServiceWithDynamicQueryTerm(url: string, key: string, val: string): Promise<any> {
          return this.http
              .get(url + "/?" + key + "=" + val, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      getServiceWithMultipleQueryTerm(url: string, query: string): Promise<any> {
          return this.http
              .get(url + "/?" + query, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      getServiceWithFixedQueryString(url: string, param: any): Promise<any> {
          this.options = new RequestOptions({ headers: this.headers, search: 'query=' + param });
          return this.http
              .get(url, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      getServiceWithComplexObjectAsQueryString(url: string, param: any): Promise<any> {
          let params: URLSearchParams = new URLSearchParams();
          for (var key in param) {
              if (param.hasOwnProperty(key)) {
                  let val = param[key];
                  params.set(key, val);
              }
          }
          this.options = new RequestOptions({ headers: this.headers, search: params });
          return this.http
              .get(url, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      createService(url: string, param: any): Promise<any> {
          let body = JSON.stringify(param);
          return this.http
              .post(url, body, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      updateService(url: string, param: any): Promise<any> {
          let body = JSON.stringify(param);
          return this.http
              .put(url, body, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      patchService(url: string, param: any): Promise<any> {
          let body = JSON.stringify(param);
          return this.http
              .patch(url, body, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      deleteService(url: string, param: any): Promise<any> {
          let params: URLSearchParams = new URLSearchParams();
          for (var key in param) {
              if (param.hasOwnProperty(key)) {
                  let val = param[key];
                  params.set(key, val);
              }
          }
          this.options = new RequestOptions({ headers: this.headers, search: params });
          return this.http
              .delete(url, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      deleteServiceWithId(url: string, key: string, val: string): Promise<any> {
          return this.http
              .delete(url + "/?" + key + "=" + val, this.options)
              .toPromise()
              .then(this.extractData)
              .catch(this.handleError);
      }

      private extractData(res: Response) {
          let body = res.json();
          return body || {};
      }

      private handleError(error: any): Promise<any> {
          console.error('An error occurred', error);
          this.toasterService.showToaster('error', 'Oops!! An error occurred', error);
          this.loaderService.displayLoader(false);
          return Promise.reject(error.message || error);
      }
  }

Text Reference

Angular2: HTTP DELETE with complex object Using Observable in Angular 2 Application

Standard

The Angular Http client communicates with the server using a familiar HTTP request/response protocol. The Http client is one of a family of services in the Angular HTTP library. When importing from the @angular/http module, SystemJS knows how to load services from the Angular HTTP library because the systemjs.config.js file maps to that module name. The HttpModule is necessary for making HTTP calls.

Observable

Think of an Observable as a stream of events published by some source. To listen for events in this stream, subscribe to the Observable. These subscriptions specify the actions to take when the web request produces a success event or a fail event (with the error in the payload).

  • The observable’s map callback moves to the success parameter and its catch callback to the fail parameter in this pattern.
  • The errorHandler forwards an error message as a failed promise instead of a failed observable.

Observable vs Promises

The less obvious but critical difference is that these two methods return very different results.

  • The promise-based then returns another promise. You can keep chaining more then and catch calls, getting a new promise each time.
  • The subscribe method returns a Subscription. A Subscription is not another Observable. It’s the end of the line for observables. You can’t call map on it or call subscribe again. The Subscription object has a different purpose, signified by its primary method, unsubscribe.

RxJS library

  • RxJS (“Reactive Extensions”) is a 3rd party library, endorsed by Angular, that implements the asynchronous observable pattern.
  • RxJS npm package loaded via system.js because observables are used widely in Angular applications.
  • The app needs it when working with the HTTP client. Additionally, you must take a critical extra step to make RxJS observables usable.
  • The RxJS library is large. Size matters when building a production application and deploying it to mobile devices. You should include only necessary features.
  • Accordingly, Angular exposes a stripped down version of Observable in the rxjs/Observable module that lacks most of the operators such as the map method.
  • You could add every RxJS operator with a single import statement. While that is the easiest thing to do, you’d pay a penalty in extended launch time and application size because the full library is so big.
  • Since this app only uses a few operators, it’s better to import each Observable operator and static class method, one-by-one, for a custom Observable implementation tuned precisely to the app’s requirements. Put the import statements in one app/rxjs-operators.ts file.

The Http.delete method takes an object that implements RequestOptionsArgs as a second parameter.

The search field of that object can be used to set a string or a URLSearchParams object.

HTTP DELETE using Observable with body object as parameter

See extended DEMO on Github

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions, URLSearchParams } 
from '@angular/http';
import { Observable } from 'rxjs/Observable';

// Observable class extensions
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/throw';

// Observable operators
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';

@Injectable()
export class WebApiObservableService {
    headers: Headers;
    options: RequestOptions;

    constructor(private http: Http) {
        this.headers = new Headers({ 'Content-Type': 'application/json', 
                                     'Accept': 'q=0.8;application/json;q=0.9' });
        this.options = new RequestOptions({ headers: this.headers });
    }

    deleteService(url: string, param: any): Observable<any> {
    let params: URLSearchParams = new URLSearchParams();
    for (var key in param) {
        if (param.hasOwnProperty(key)) {
            let val = param[key];
            params.set(key, val);
        }
    }
    this.options = new RequestOptions({ headers: this.headers, search: params });
    return this.http
        .delete(url, this.options)
        .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);
    }
}

Usage Code:

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

import { SearchMovieModel } from './search-movie.model';
import { WebApiObservableService } from './web-api-observable.service';

@Component({
    selector: 'search-movie-list',
    templateUrl: '../../Scripts/app/search-list.component.html'
})

export class SearchMovieListComponent implements OnInit {
    searchMovieModel: SearchMovieModel;
    
    constructor(
        private movieObservableService: WebApiObservableService) {
       
        this.searchMovieModel = {id: '12' , name: 'abc'};
    }

    ngOnInit() {
        this.movieObservableService
            .deleteService('api/Movie/TestPost', this.searchMovieModel)
            .subscribe(
                result => console.log(result),
                error => this.errorMessage = <any>error
        );  
    }
}