Jump to the content

Angular2でAjaxを使ってデータを取得する(Httpクライアント)

Angular2

    画面遷移のないシングルページのWebアプリケーションでは、Ajaxが使えないと話にならないですよね。 Angular2ではHttpクライアントが機能として含まれています。

    今回はAngular2でのHttpクライアントでデータを取得する方法を紹介します。

    Httpクライアント

    これから全部で3つのコードを紹介します。

    今回例で使うソースコードは公式リファレンスで紹介されているものです。
    Ajaxで取得したデータをリストで表示します。

    app/toh.component.ts

    import { Component }         from '@angular/core';
    import { HTTP_PROVIDERS }    from '@angular/http';
    import { HeroListComponent } from './hero-list.component';
    import { HeroService }       from './hero.service';
    
    @Component({
        selector: 'my-toh',
        template: `
            <h1>Tour of Heroes</h1>
            <hero-list></hero-list>
        `,
        directives: [HeroListComponent],
        providers:  [
            HTTP_PROVIDERS,
            HeroService,
        ]
    })
    export class TohComponent { }
    

    ではまずはじめに、ベースとなるリスト表示のコンポーネントを定義します。

    なんかいっぱい書いてあって、よくわからないですよねw
    大丈夫です、ひとつずつ見ていきましょう。

    まず、 HTTP_PROVIDERS をimportします。これは、Httpクライアントを使うための処理が定義されています。 @Componentproviders プロパティに指定しておきます。

    実際にHttpクライアントで通信する機能は、HeroService に任せます。これも providers に追加します。
    これは、Angular2のDependency Injection(依存的注入) という機能で外部化しています。 (Dependency Injectionについては後日詳しく紹介します。ここでは、処理を使いまわせる仕組みと考えていれば大丈夫です。)

    Angular2ではコンポーネント志向の設計なので、処理を独立させることが簡単にできます。
    コードを見ると、すっきりしていてストレスフリーですね。

    app/toh/hero-list.component.ts (class)

    次に、先ほど定義した TohComponent のリスト部分を定義します。 TohComponent内の <hero-list></hero-list> の部分がこれにあたります。

    import { Component, OnInit } from '@angular/core';
    import { Hero}               from './hero';
    import { HeroService }       from './hero.service';
    
    @Component({
        selector: 'hero-list',
        template: `
            <h1>Tour of Heroes ()</h1>
            <h3>Heroes:</h3>
            <ul>
                <li *ngFor="let hero of heroes">
                    {{hero.name}}
                </li>
            </ul>
            New hero name:
            <input #newHeroName />
            <button (click)="addHero(newHeroName.value); newHeroName.value=''">
                Add Hero
            </button>
            <div class="error" *ngIf="errorMessage">{{errorMessage}}</div>
        `
        ...
    })
    export class HeroListComponent implements OnInit {
    
        constructor (private heroService: HeroService) {}
    
        errorMessage: string;
        heroes: Hero[];
    
        ngOnInit() { this.getHeroes(); }
    
        getHeroes() {
            this.heroService.getHeroes()
                .subscribe(
                    heroes => this.heroes = heroes,
                    error =>  this.errorMessage = <any>error
                );
        }
    
    }
    

    初期化のタイミングで、getHeroes メソッドで heroService.getHeroes() を実行して、Http通信をしています。
    ngOnInit についてはAngular2のLifecycle Hooksを理解するを参考にしてください。

    getHeroes メソッド内の subscribe() というのはRxJSの機能です。今はHttpの処理が終わった後に、 実行されるものだと思っていれば問題ありません。

    Httpでデータを取得した後は、HeroListComponent自身の heroes メンバーに保存しています。 データが保存されれば、<li *ngFor="let hero of heroes"></li>heroes に自動的に反映されて、リストが生成されます。

    app/toh/hero.service.ts

    最後にHttpサービス本体です。

    import { Injectable }     from '@angular/core';
    import { Http, Response } from '@angular/http';
    import { Hero }           from './hero';
    import { Observable }     from 'rxjs/Observable';
    
    @Injectable()
    export class HeroService {
    
        constructor (private http: Http) {}
    
        private heroesUrl = 'app/heroes';  // URL to web api
    
        getHeroes (): Observable<Hero[]> {
            return this.http.get(this.heroesUrl)
                .map(this.extractData)
                .catch(this.handleError);
        }
    
        // レスポンスデータの整形処理
        private extractData(res: Response) {
            if (res.status < 200 || res.status >= 300) {
                throw new Error('Bad response status: ' + res.status);
            }
            let body = res.json();
            return body.data || { };
        }
    
        // エラー処理
        private handleError (error: any) {
            // In a real world app, we might send the error to remote logging infrastructure
            let errMsg = error.message || 'Server error';
            console.error(errMsg); // log to console instead
            return Observable.throw(errMsg);
        }
    }
    

    はじめに、@Injectable で他のコンポーネントからimportできるように宣言しています。

    Httpを使うためには、import { Http } でHttpオブジェクトをimportする必要があります。
    そして、constructorの引数で、Httpオブジェクトをクラスのhttpメンバーに追加します。
    ※TypeScriptでは、constructorの引数でprivatepublic などのキーワードをつけると、そのクラスのメンバーに追加されます。

    ここでは、getHeroes メソッドに注目しましょう。 http.get()get メソッドでの通信を行います。第1引数にはURLを指定します。
    返り値はRxJSのObservableというデータになりますが、今は理解できなくても大丈夫です。 ObservableのmapメソッドでAjaxでのレスポンスをチェック、json化しています。 RxJSは理解が難しいので、ここではレスポンスデータを整形していると認識できればOKです。 catch() ではエラーハンドリングをしています。

    レスポンスデータをコンポーネントで受け取る

    HeroListComponentgetHeroes メソッドがあったのを覚えていますか?

        getHeroes() {
            this.heroService.getHeroes()
                .subscribe(
                    heroes => this.heroes = heroes,
                    error =>  this.errorMessage = <any>error
                );
        }
    

    この中の subscribe メソッドの第1引数に渡す関数の内で、レスポンスデータにアクセス出来ます。 データがコンポーネントに保存されると、自動的にリスト表示されるという仕組みです。

    複雑だけど、まずは使って慣れよう

    ファイルが複数に分かれていたり、 いろんな技術が一気に出てきてかなり複雑ですが、 要点を抑えて慣れてしまえばこっちのもの。
    Httpクライアントはとても頻繁に使うので、ぜひとも理解してもらいたいです。

    今回は get メソッドの紹介でしたが、今後 post メソッドなども紹介します。

    参考

    注目記事

    最近の記事

    ぼくが書いてます

    フロントエンドエンジニア

    イソップ

    ページの先頭に戻る

    Search results

    ×