Angular4 + Django1.11 vol.2
参考サイト
https://www.codingforentrepreneurs.com/projects/angular-django/
ng build to Django Static
$ ng build --prod
で、production versionのbuildを実行する。(結果、bundle.jsが作成される)buildしたファイルの出力先をdjangoのstaciファイル内にする。
$ ng build --prod --output-path /Users/yassy/Desktop/djangular4/backend/src/static/ang --watch --output-hashing none // --output-path で出力先を指定 // --watchで、変更があったら自動でbuildするモードに切り替えられる // --output-hashing none で、build時に作成されるhashをなくすことができる。
- deploy.sh ファイルを作成する。deployのときに実行するコマンドを記載する。
ng build --prod --output-path /Users/yassy/Desktop/djangular4/backend/src/static/ang --watch --output-hashing none
Django render Angular
- static/ang/index.htmlをang_home.htmlにコピペする。さらに、load staticで、django templateで、staticfileを読み込むようにする。
{% load static %} <!doctype html> <html> <head> <meta charset="utf-8"> <title>Srvup</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <!-- index.html --> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <link href="{% static 'ang/styles.bundle.css' %}" rel="stylesheet"/></head> <body> <app-root>Loading...</app-root> <script type="text/javascript" src="{% static 'ang/inline.bundle.js' %}"></script> <script type="text/javascript" src="{% static 'ang/polyfills.bundle.js' %}"></script> <script type="text/javascript" src="{% static 'ang/vendor.bundle.js' %}"></script> <script type="text/javascript" src="{% static 'ang/main.bundle.js' %}"></script> </body> </html>
- 無事表示された!しかし、image ファイルなどが読み込まれていない。。。ang/assets/videos.jsonの中のpathがdjangoと一致してないのが原因ぽい。なので、そのimage のpathを修正する。
{ "name": "Welcome", "slug": "item-1", "embed": "1hyjLD7pk10", "image": "/static/ang/assets/images/nature/4.jpg", "featured": true } ...
- 次に、vides.service.ts内のendpoint(videos.jsonにアクセスするpath)も修正する。
const endpoint = '/static/ang/assets/json/videos.json'
http://127.0.0.1:8000/
にアクセスしてみる。。。error!というか画像が表示されない。。。原因は、videos.jsonをbuildあとのファイル(angフォルダ以下のファイル)を修正していたため、buildが実行されるたびに、上書きされていたためだった(^^; なので、client/assets/json/videos.jsonの方のpathを修正して再度buildする。無事表示された(^^)
home.component.tsの、defaultImageのpathも修正する。
videoListDefaultImage = '/static/ang/assets/images/videos/1.jpg'
まとめ
- angularアプリと、djangoアプリは別物と考える。
- angularアプリ作成→build→deployという流れだが、django backendに使うときは、angularアプリ作成→build output→outputしたファイルを、djangoに静的ファイルとして扱わせる という流れになるのか。
- build –watch にしておくことで、常にtranscompile + outputされる。そのため、基本的に、django側にoutputされたファイルを修正ではなく、angularアプリの方のファイルを修正する(djangoは、angularアプリからoutputされるファイルを扱うという役割)
Angular4 + Django1.11 vol.1
参考サイト
https://www.codingforentrepreneurs.com/projects/angular-django/
Getting Started Angular4+Django
djangular4というフォルダを作成する。さらに、djangular4/client, djangular4/backend というサイトをそれぞれ作成する。
clientフォルダに、joincfe/github のtry-angular-v4をgit cloneしてくる。
$ git clone https://github.com/codingforentrepreneurs/Try-Angular-v4.git . // ここのピリオドがポイント $ npm install // package.jsonに記載があるmoduleをinstallする。 $ ng serve // angularのコードをtranscompileして、localserverを起動する。 $ rm -rf .git // gitのrepositoryを削除する
- djangoの環境を作成する。
$ pyenv virtualenv djangular4 // 仮想環境を作成する $ pip install django djangorestframework // django djangorestframework をpip installする
A Django URL Catch-all
django startprojectで、新しいprojectを開始する。
$ django-admin.py startproject tryangular .
settings.pyにstaticfileの設定を追記する。
STATIC_URL = '/static/' STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'static-root') STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ]
- urls.pyにangularで表示するurlをcatchするための設定をする。
from django.conf.urls import url from django.contrib import admin from django.views.generic.base import TemplateView #template viewをimportする urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^.*', TemplateView.as_view(template_name="ang_home.html"), name='home'), # ]
- templatesフォルダを作成して、その中にang_home.htmlを作成する。
<h1>Hello Django!</h1>
- またsettings.pyにtemplatesのフォルダの場所を指定する。
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
http://127.0.0.1:8000/
でも、http://127.0.0.1:8000/ddd
でも、表示されるページが、ang_home.htmlになっていればOK。今後は、個別に表示したいurlがある場合は、(adminのように)、
r'^.*'
より上に書く。
まとめ
- これで一通りの準備は完了ぽい。
- .(ピリオド)を使うのがポイントだったな。
Angular4入門_Vol.20
参考サイト
https://www.codingforentrepreneurs.com/projects/try-angular-v4/
ngBuild and Deploy to Heroku
packageが完成したら、
$ ng build --prod
で、deploy用に、bundle.jsを作成する。prodオプションは、minファイルにするためか。bundle.jsには、typescriptファイルを役割ごとにまとめて、javascriptにtrans compileしたコードが記載されている。$ ng build --prod --output-path /Users/username/Desktop/try_angular4/ngSrvupTest
というコマンドでpathを指定して、ファイルを出力する。さらに、
$ ng build --prod --output-path /Users/username/Desktop/try_angular4/ngSrvupTest --watch
で、watchもできる。$ ng build --prod --output-path /Users/yassy/Desktop/try_angular4/ngSrvupTest/public/
というように、publicにしておいたほうがデプロイのときに楽ぽい。ngSrvupTest フォルダに、Procfileを作成する。
web: node index.js
- package.jsonを作成する(requirements.txtみたいなもんかな)
{ "name": "try-angular-4", "version": "1.0.0", "main": "index.js", "engines": { "node": "5.9.1" }, "dependencies": { "ejs": "2.4.1", "express": "4.13.3", "path": "0.12.7", "mongoose": "4.9.3", "body-parser": "1.17.1", "compression": "1.6.2" } }
- index.jsを作成する。
var express = require('express'); var path = require('path'); var app = express(); const port = process.env.PORT || '5000'; app.set('port', port); app.use(express.static(__dirname + '/public')); // staticファイルの置き場所? app.get('/[^\.]+$', function(req, res){ res.set('Content-Type', 'text/html') .sendFile(path.join(__dirname, '/public/index.html')) }); app.listen(app.get('port'), function(){ console.log("Node app is running at localhost:" + app.get('port')) });
$ node index.js
を実行してみる。。。error! express確認できないとのこと。$ npm install
で、package.jsonから必要なpackageをinstallする。$ node index.js
再度実行する。。。localhost:5000にアクセスしたところ無事表示された(^^).gitignore
ファイルを作成する。
node_modules .DS_Store
- herokuにデプロイするために、git repositoryをlocalに作成する。
$git init $git add --all $git commit -m "initial commit"
- herokuのrepositoryを作成する。
$ heroku create tryangular4 Creating ⬢ tryangular4yassy... done https://tryangular4.herokuapp.com/ | https://git.heroku.com/tryangular4.git
$ git push heroku master
で、deployする。。。デプロイ成功!上記で作成されたurlにアクセスすると、デプロイされているか確認できる(^^)
Angular4入門_Vol.19
参考サイト
https://www.codingforentrepreneurs.com/projects/try-angular-v4/ https://angular.io/docs/ts/latest/api/router/index/RouterLink-directive.html https://angular.io/docs/ts/latest/guide/router.html#!#basics-router-links
Router Link & Improved Navigation
- Router Linkを使ってみる。video-list.component.htmlに追記してみる。
<p> {{ title }} </p> <div *ngFor='let item of videoList'> <h1><a routerLink="/videos/{{ item.slug }}" routerLinkActive="active" >{{ item.name }}</a></h1> <!-- <div [innerHTML]='item.embed'></div> <div [innerHTML]='someItem'></div> --> <iframe *ngIf='item.embed' width="560" height="315" [src]="getEmbedUrl(item) | safe" frameborder="0" allowfullscreen></iframe> <hr> </div>
hrefの代わりに、routerLinkを使うという感じになっているが、hrefとの違いは何なんだろう。。。
routerLinkActiveを使うことによって、よってより柔軟にlinkの切り替えができるとかそんな感じなのかな。。。。
とりあえず、動画講義では、hrefになっていた箇所を片っ端から、routerLinkに変えていっていた。
Improve Styling
- interfaceだけを修正するだけなので、割愛
ngClass
- ngClassを使ってみる。ngClassは、たぶん、classをangularで双方向データバインディングできるようなモジュールだと思われる。
<p> {{ title }} </p> <div *ngFor='let item of videoList; let i = index' [ngClass]="{'row': (i+1)%3 == 0}"> <div class="col-sm-4"> <div class="thumbnail"> <a routerLink="/videos/{{ item.slug }}" routerLinkActive="active" *ngIf='item.image'><img [src]='item.image' alt="{{ item.name }} image"></a> <div class="caption"> <h3><a routerLink="/videos/{{ item.slug }}" routerLinkActive="active" >{{ item.name }}</a></h3> <p>...</p> <p><a routerLink="/videos/{{ item.slug }}" routerLinkActive="active" class="btn btn-primary" role="button">View</a></p> </div> </div> </div> </div>
Angular4入門_Vol.18
参考サイト
https://www.codingforentrepreneurs.com/projects/try-angular-v4/
Video Item Model
- video classを作成するために、video.tsファイルを作成する。これはdjangoで言うと、modelsを使うようなものか。
export class VideoItem { slug: string; name: string; image: string; embed?: string; //optionalな場合は、最後に?をつけるということか? featured?: Boolean; }
- video-list.component.tsのvideoListの型定義を、VideoItemに設定する。
import { Component, OnInit, OnDestroy } from '@angular/core'; import { VideoItem } from '../videos/video'; // VideoItem class を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: [VideoItem]; // VideoItemのリスト型を定義する。 constructor(private _video:VideoService) { } ngOnInit() { // this.todayDate = new Date(); this.req = this._video.list().subscribe(data=>{ this.videoList = data as [VideoItem]; // VideoItemのリスト型を定義する。 }); // } ngOnDestroy(){ this.req.unsubscribe() } getEmbedUrl(item){ return 'https://www.youtube.com/embed/' + item.embed; } }
- video-detail.component.tsも同様にVideoItem classを追記する。
import { Component, OnInit, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { VideoItem } from '../videos/video'; import { VideoService } from '../videos/videos.service'; @Component({ selector: 'video-detail', templateUrl: './video-detail.component.html', styleUrls: ['./video-detail.component.css'], providers:[VideoService] }) export class VideoDetailComponent implements OnInit, OnDestroy { private routeSub:any; private req:any; video: VideoItem; slug: string; constructor(private route: ActivatedRoute, private _video:VideoService) { } ngOnInit() { this.routeSub = this.route.params.subscribe(params => { this.slug = params['slug'] this.req = this._video.get(this.slug).subscribe(data=>{ this.video = data as VideoItem }) }) } ngOnDestroy(){ this.routeSub.unsubscribe() this.req.unsubscribe() } }
- search-detail.component.ts にも追記する。
import { Component, OnInit, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { VideoItem } from '../videos/video'; // VideoItemをimport する import { VideoService } from '../videos/videos.service'; @Component({ selector: 'app-search-detail', templateUrl: './search-detail.component.html', styleUrls: ['./search-detail.component.css'], providers: [VideoService] }) export class SearchDetailComponent implements OnInit, OnDestroy { private routeSub:any; private req:any; query: string; videoList: [VideoItem]; // VideoItem のリスト型を定義する constructor(private route: ActivatedRoute, private _video:VideoService) { } ngOnInit() { this.routeSub = this.route.params.subscribe(params=>{ console.log(params) this.query = params['q'] this.req = this._video.search(this.query).subscribe(data=>{ this.videoList = data as [VideoItem]; // VideoItemのリスト型を定義する。 }) }) } ngOnDestroy(){ this.routeSub.unsubscribe() } getEmbedUrl(item){ return 'https://www.youtube.com/embed/' + item.embed; } }
- home.component.tsにも追加する。
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { VideoItem } from '../videos/video'; // VideoItem import import { VideoService } from '../videos/videos.service'; // VideoService import @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.css'], providers: [VideoService] //providersに、VideoServiceを定義する }) export class HomeComponent implements OnInit, OnDestroy { private req: any; homeImageList: [VideoItem] = [] as [VideoItem] ; //VideoItemのリスト型を定義する。さらに、初期値として、空のリストを渡しておく // [] のあとに、as [VideoItem]は必須の模様。代入するときはそのデータのclass定義が必要なのか?よくわからないな。 // homeImageList = [] as [VideoItem] ;は通った。 // あ〜そうか、VideoItemで定義された homeImageListには、何も型定義していない空のリストは、型が不明のため、VideoItem classで定義された空のリストでないと代入できないのか。 constructor(private http:Http, private router:Router, private _video:VideoService) { } //_video を定義する ngOnInit() { this.req = this._video.list().subscribe(data=>{ // _video.list()で、呼び出す。 // console.log(data.json()) //this.homeImageList = [] as [VideoItem] data.filter(item=>{ if(item.featured){ this.homeImageList.push(item) } }) // this.homeImageList = data.json(); }) } ngOnDestroy(){ this.req.unsubscribe() } preventNormal(event:MouseEvent, image:any){ if (!image.prevented){ event.preventDefault() // image.link = '/videos' // image.prevented = true; this.router.navigate(['./videos']) } } }
まとめ
- angularのclassは、djangoのmodelのような使い方ができる。
- 型の定義が厳密になるため、エラーチェックなどに有効
Angular4入門_Vol.17
参考サイト
https://www.codingforentrepreneurs.com/projects/try-angular-v4/
Search Video List
- search methodを、videos.service.tsに追記する。methodの処理の方法は、get methodと似てるので、中身をコピペして再利用する。
search(query){ return this.http.get(endpoint) // get methodで、endpointにアクセス .map(response=>{ // responseを代入して結果をmappingする let data = [] // data に空のリストを代入 let req = response.json().filter(item=>{ // response.json()のデータをitemのname if (item.name.indexOf(query) >= 0 ){ //indexOf data.push(item) // itemをpushする。 } }) return data }) .catch(this.handleError) }
indexOfは、
indexOf() メソッドは、呼び出す String オブジェクト中で、fromIndex から検索を始め、指定された値が最初に現れたインデックスを返します。値が見つからない場合は -1 を返します。
とのことなので、>=0
としてある場合は、文字列を少なくとも1つは含む場合でfilterをかけていることになる。試しに、video-list.component.tsにsearch methodを記載してみる。
ngOnInit() { this.todayDate = new Date(); this.req = this._video.search("テスト1").subscribe(data=>{ this.videoList = data as [any]; }); //search("テスト1") で、引数として文字列を与えてみる。 }
無事テスト1だけ表示された!テストは成功したので、searchからlist()methodに戻しておく。
search-detailに、search methodを追記する。
import { Component, OnInit, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { VideoService } from '../videos/videos.service'; //VideoServiceをimportする @Component({ selector: 'app-search-detail', templateUrl: './search-detail.component.html', styleUrls: ['./search-detail.component.css'], providers: [VideoService] //VideoServiceをprovidersとして、定義する }) export class SearchDetailComponent implements OnInit, OnDestroy { private routeSub:any; private req:any; query: string; videoList: [any]; constructor(private route: ActivatedRoute, private _video:VideoService) { } //_vidoe にVideoServiceを型定義する。 ngOnInit() { this.routeSub = this.route.params.subscribe(params=>{ console.log(params) this.query = params['q'] this.req = this._video.search(this.query).subscribe(data=>{ //searchメソッドを、引数をqueryとして組み込む this.videoList = data as [any]; }) }) } ngOnDestroy(){ this.routeSub.unsubscribe() } }
search boxに、キーワードを入れて検索してみる。。。。何も表示されない。。。
video-list.component.html の、video listを表示する箇所のhtmlのコードをコピペしてみる。
<p *ngIf='query'> Searched for <b>{{ query }}</b> </p> <div *ngFor='let item of videoList'> <h1><a href="videos/{{ item.slug }}" >{{ item.name }}</a></h1> <!-- <div [innerHTML]='item.embed'></div> <div [innerHTML]='someItem'></div> --> <iframe *ngIf='item.embed' width="560" height="315" [src]="getEmbedUrl(item) | safe" frameborder="0" allowfullscreen></iframe> <hr> </div>
- Error発生!
ERROR TypeError: co.getEmbedUrl is not a function
とのこと。なので、getEmbedUrlを定義する。
import { Component, OnInit, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { VideoService } from '../videos/videos.service'; @Component({ selector: 'app-search-detail', templateUrl: './search-detail.component.html', styleUrls: ['./search-detail.component.css'], providers: [VideoService] }) export class SearchDetailComponent implements OnInit, OnDestroy { private routeSub:any; private req:any; query: string; videoList: [any]; constructor(private route: ActivatedRoute, private _video:VideoService) { } ngOnInit() { this.routeSub = this.route.params.subscribe(params=>{ console.log(params) this.query = params['q'] this.req = this._video.search(this.query).subscribe(data=>{ this.videoList = data as [any]; }) }) } ngOnDestroy(){ this.routeSub.unsubscribe() } getEmbedUrl(item){ return 'https://www.youtube.com/embed/' + item.embed; } }
- これで再度検索してみる。。。できた〜!
まとめ
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 が基本セットになるのかも