読者です 読者をやめる 読者になる 読者になる

Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Angular4入門_Vol.16

参考サイト

https://www.codingforentrepreneurs.com/projects/try-angular-v4/

Video Service

  • app/videos フォルダを作成する

  • $ ng g service videosで、serviceの雛形を作成する。

  • videos.service.tsと、videos.service.spec.tsを、app/videosフォルダに移動させる。

  • videos.service.tsにコードを追記する。

import { Injectable } from '@angular/core';
import { Http } from '@angular/http'; // Httpをimportする

import 'rxjs/add/operator/map'; // mapをimportする。
import 'rxjs/add/operator/catch'; //catchをimportする。

const endpoint = 'assets/json/videos.json' // yourdomain.com/api/videos
// constは変更不可な変数

@Injectable()
export class VideoService {
  constructor(private http: Http) { } // httpに、Httpclassを定義する。

  list(){ //list methodを使う(getでも可と言っていた)
    return this.http.get(endpoint) //httpのgetメソッドで、endpointにアクセスする。
            .map(response=>response.json()) //responseをjsonデータに変換して、mappingする。
            .catch(this.handleError) // handleErrorをcatchする。
  }

  private handleError(error:any, caught:any): any{ //handleErrorを定義しておく。
    console.log(error, caught)
  }

}
  • video-list.component.ts に、VideoServiceをimportして使ってみる。
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Http } from '@angular/http';

import { VideoService } from '../videos/videos.service'; //importする

@Component({
  selector: 'video-list',
  templateUrl: './video-list.component.html',
  styleUrls: ['./video-list.component.css'],
  providers: [VideoService] // providersとして、VideoServiceを定義しておく。
})
export class VideoListComponent implements OnInit {
  private req:any;
  title = "Video List!";
  someItem = "<h1>HiHi</h1>";
  todayDate;
  videoList: [any];

  constructor(private http:Http, private _video:VideoService) { } // _videoを、VideoService classとして定義する。

  ngOnInit() {
    this.todayDate = new Date();
    this.req = this._video.list().subscribe(data=>{ //
      console.log(data) // data.json() は、すでにservice側で処理済みのため外す
    // this.req = this.http.get('assets/json/videos.json').subscribe(data=>{
    //   console.log(data.json())
      this.videoList = data as [any]; // data.json() は、すでにservice側で処理済みのため外す
    }); //
  }

  ngOnDestroy(){
    this.req.unsubscribe()
  }

  getEmbedUrl(item){
    return 'https://www.youtube.com/embed/' + item.embed;
  }

}
  • 4200/vidoesにアクセスする。。。無事表示された!

  • これで、video-listのhttpメソッドは不要になったので、削除しておく。

import { Component, OnInit, OnDestroy } from '@angular/core'; // OnDestroyをimportする
// httpのimportを削除
import { VideoService } from '../videos/videos.service';

@Component({
  selector: 'video-list',
  templateUrl: './video-list.component.html',
  styleUrls: ['./video-list.component.css'],
  providers: [VideoService]
})
export class VideoListComponent implements OnInit {
  private req:any; // req のアノテーション
  title = "Video List!";
  someItem = "<h1>HiHi</h1>";
  todayDate;
  videoList: [any];

  constructor(private _video:VideoService) { } //Httpを削除

  ngOnInit() {
    this.todayDate = new Date();
    this.req = this._video.list().subscribe(data=>{
      console.log(data)
      this.videoList = data as [any];
    }); //
  }

  ngOnDestroy(){
    this.req.unsubscribe()
  }

  getEmbedUrl(item){
    return 'https://www.youtube.com/embed/' + item.embed;
  }

}
  • video-detailにも同様に、VideoServiceをimportする。
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Http } from '@angular/http';
import { VideoService } from '../videos/videos.service'; // VideoServiceをimportする


@Component({
  selector: 'video-detail',
  templateUrl: './video-detail.component.html',
  styleUrls: ['./video-detail.component.css'],
  providers:[VideoService] // VideoServiceをprovidersとして定義する
})
export class VideoDetailComponent implements OnInit, OnDestroy {
  private routeSub:any;
  private req:any;
  // video = {
  //   name: "Default",
  //   slug: "item-1",
  //   embed: "kzjMI00A1f8"
  // };
  video:any;
  slug: string;
  // _vidoeをVideoServiceとして定義する
  constructor(private route: ActivatedRoute, private http: Http, private _video:VideoService) { }

  ngOnInit() {
    this.routeSub = this.route.params.subscribe(params => {
      console.log(params)
      this.slug = params['slug']
      this.req = this._video.list().subscribe(data=>{ //http.getmethodの箇所を_video.list()に修正する
        data.filter(item=>{ // data.json()のjson()変換は不要なので、削除する。
          // console.log(item)
          if (item.slug == this.slug){
            this.video = item
          }
        })
      })
    })
  }
  ngOnDestroy(){
    this.routeSub.unsubscribe()
    this.req.unsubscribe()
  }

}
  • videos.service.tsに、get メソッドを追加する。
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

const endpoint = 'assets/json/videos.json' // yourdomain.com/api/videos

@Injectable()
export class VideoService {
  constructor(private http: Http) { }

  list(){
    return this.http.get(endpoint)
            .map(response=>response.json())
            .catch(this.handleError)
  }
  // get methodを定義する
  get(slug){ // slugを引数に取る
    return this.http.get(endpoint) // endpointにアクセスする
            .map(response=>{
              let data = response.json().filter(item=>{
                //responseをjsonデータに変換、item.slug = 引数のslugが一致した場合に、itemを返すfilterを作成する
                                if (item.slug == slug ){
                                  return item
                                }
                              })
              console.log(data) // dataをlogに表示する
              return data // get(slug)の結果としてdataを戻り値として返す
              })
            .catch(this.handleError)
  }

  private handleError(error:any, caught:any): any{
    console.log(error, caught)
  }

}
  • video-detailに, get methodを追記する。
...
ngOnInit() {
  this.routeSub = this.route.params.subscribe(params => {
    // console.log(params)
    this.slug = params['slug']
    this.req = this._video.get(this.slug).subscribe(data=>{ // getメソッドに引数のslugを渡す
      this.video = data // video変数に、dataを渡す (ここのdataは、videos.serviceのlet dataで定義したdata)
      // data.filter(item=>{
      //   // console.log(item)
      //   if (item.slug == this.slug){
      //     this.video = item
      //   }
      // })
    })
  })
}
...
  • video-detailページにアクセスしてみる。。。errorは発生してないが、何も表示されない。これは、data がarrayで渡されており、単体のobjectとして渡されていないことが原因の模様。なので, videos.service.tsのget methodを修正する。
get(slug){
  return this.http.get(endpoint)
          .map(response=>{
            let data = response.json().filter(item=>{
                              if (item.slug == slug ){
                                return item
                              }
                            })
            console.log(data)
            if (data.length == 1){
              return data[0]
            }
            return {}
            })
          .catch(this.handleError)
}
  • video-detailのページにアクセスしてみる。。。無事表示された!(^^)そしてdataに無いitemは表示されないことも確認。

  • 最後に、video-detail.component.ts からHttpを削除しておく。

まとめ

  • angularのserviceは、apiなどにアクセスして、データを取得 と そのデータをcomponentに渡すという役割がある模様
  • componentで、serviceからデータを受け取る場合は、providers:[service名]で指定する。
  • detailpageのようなcomponentにも、serviceで取得してfileterをかけてデータをcomponentに渡す方がよさそう。
  • mapとcatch が基本セットになるのかも