前回に続き、今回は 第2回「Webフロントエンド開発勉強会」 で作成した楽曲検索アプリを Angular で実装することを目的として、コンポーネント、サービス、HTTP通信について説明します。
第1回 Angular勉強会を実施していない方は事前に実施しておいてください。
前回の復習
検索ボタンを押したら固定の楽曲情報を表示するページを作成してください。
$ ng generate component study2/music-search
import { EcSiteComponent } from './study2/ec-site/ec-site.component';
const routes: Routes = [
:
{ path: 'study2/music-search', component: MusicSearchComponent },
];
<h1>第1回 Angular勉強会</h1>
<ul>
<li><a routerLink="/type-script">TypeScript</a></li>
<li><a routerLink="/data-binding">data-binding</a></li>
<li><a routerLink="/pipe">pipe</a></li>
<li><a routerLink="/directive">directive</a></li>
</ul>
<h1>第2回 Angular勉強会</h1>
<ul>
<li><a routerLink="/study2/music-search">music-search</a></li>
</ul>
<div>
<button>検索</button>
<div id="resultContent">
</div>
</div>
import { Component, OnInit } from '@angular/core';
class MusicItem {
trackName: string;
artistName: string;
artworkUrl100: string;
}
@Component({
selector: 'app-music-search',
templateUrl: './music-search.component.html',
styleUrls: ['./music-search.component.css']
})
export class MusicSearchComponent implements OnInit {
constructor() { }
ngOnInit() {
}
/**
* 検索実行
*/
onSearch() {
const results = [
{ artistName: 'アーティスト名1', trackName: '楽曲名1', artworkUrl100: 'https://is5-ssl.mzstatic.com/image/thumb/Music6/v4/a5/df/97/a5df97ec-b7e4-7f78-625a-f331603b0756/source/100x100bb.jpg' },
{ artistName: 'アーティスト名2', trackName: '楽曲名2', artworkUrl100: 'https://is4-ssl.mzstatic.com/image/thumb/Music/v4/fb/d8/04/fbd8047c-293e-1f90-4b06-929bbeca20b1/source/100x100bb.jpg' },
{ artistName: 'アーティスト名3', trackName: '楽曲名3', artworkUrl100: 'https://is2-ssl.mzstatic.com/image/thumb/Music/v4/4d/2e/39/4d2e39ef-fd24-a902-e704-cb7dc2ae6c5b/source/100x100bb.jpg' },
{ artistName: 'アーティスト名4', trackName: '楽曲名4', artworkUrl100: 'https://is5-ssl.mzstatic.com/image/thumb/Music/v4/54/ff/d6/54ffd6b2-3f3f-ce92-189d-20c3143b2380/source/100x100bb.jpg' },
{ artistName: 'アーティスト名5', trackName: '楽曲名5', artworkUrl100: 'https://is2-ssl.mzstatic.com/image/thumb/Music6/v4/ae/4a/fd/ae4afdd5-0dc7-31a4-ab96-eacc806a32d5/source/100x100bb.jpg' }
];
}
}
答え
import { Component, OnInit } from '@angular/core';
class MusicItem {
trackName: string;
artistName: string;
artworkUrl100: string;
}
@Component({
selector: 'app-music-search',
templateUrl: './music-search.component.html',
styleUrls: ['./music-search.component.css']
})
export class MusicSearchComponent implements OnInit {
results: Array<MusicItem>;
constructor() { }
ngOnInit() {
}
/**
* 検索実行
*/
onSearch() {
this.results = [
{ artistName: 'アーティスト名1', trackName: '楽曲名1', artworkUrl100: 'https://is5-ssl.mzstatic.com/image/thumb/Music6/v4/a5/df/97/a5df97ec-b7e4-7f78-625a-f331603b0756/source/100x100bb.jpg' },
{ artistName: 'アーティスト名2', trackName: '楽曲名2', artworkUrl100: 'https://is4-ssl.mzstatic.com/image/thumb/Music/v4/fb/d8/04/fbd8047c-293e-1f90-4b06-929bbeca20b1/source/100x100bb.jpg' },
{ artistName: 'アーティスト名3', trackName: '楽曲名3', artworkUrl100: 'https://is2-ssl.mzstatic.com/image/thumb/Music/v4/4d/2e/39/4d2e39ef-fd24-a902-e704-cb7dc2ae6c5b/source/100x100bb.jpg' },
{ artistName: 'アーティスト名4', trackName: '楽曲名4', artworkUrl100: 'https://is5-ssl.mzstatic.com/image/thumb/Music/v4/54/ff/d6/54ffd6b2-3f3f-ce92-189d-20c3143b2380/source/100x100bb.jpg' },
{ artistName: 'アーティスト名5', trackName: '楽曲名5', artworkUrl100: 'https://is2-ssl.mzstatic.com/image/thumb/Music6/v4/ae/4a/fd/ae4afdd5-0dc7-31a4-ab96-eacc806a32d5/source/100x100bb.jpg' }
];
}
}
<div>
<button (click)="onSearch()">検索</button>
<div id="resultContent">
<div *ngFor="let item of results">
<img [src]="item?.artworkUrl100">
<div class="track-name">{{item?.trackName}}</div>
<div class="artist-name">{{item?.artistName}}</div>
</div>
</div>
</div>
.track-name {
font-weight: bold;
}
コンポーネント
HTMLの要素をカプセル化して再利用可能なパーツを提供するための仕組みをコンポーネントといいます。
これまで作ってきた各ページもコンポーネントですが、コンポーネントを複数組み合わせて利用することで、それぞれが持つ機能や役割が明確になったり、パーツの再利用が可能になったりします。
以下のコンポーネントを作成してページに追加してください。
$ ng generate component study2/ec-site
$ ng generate component study2/product
import { EcSiteComponent } from './study2/ec-site/ec-site.component';
const routes: Routes = [
:
{ path: 'study2/ec-site', component: EcSiteComponent },
];
<h1>第1回 Angular勉強会</h1>
<ul>
<li><a routerLink="/type-script">TypeScript</a></li>
<li><a routerLink="/data-binding">data-binding</a></li>
<li><a routerLink="/pipe">pipe</a></li>
<li><a routerLink="/directive">directive</a></li>
</ul>
<h1>第2回 Angular勉強会</h1>
<ul>
<li><a routerLink="/study2/ec-site">ec-site</a></li>
</ul>
コンポーネントを作成する
ECサイトの商品を想定した商品コンポーネント ProductComponent
を作成してみましょう。
product.component.ts
の selector: 'app-product'
の部分が、ProductComponent
を利用するためのセレクタ名(タグ名)となり、@Input('product') product: ProductInfo;
が、このコンポーネントへ渡すプロパティとなります。
コンポーネントを利用する場合は、 <app-product [product]="商品オブジェクト"></app-product>
のように指定します。
import { Component, OnInit, Input } from '@angular/core';
export class ProductInfo {
id: number;
name: string;
image?: string;
}
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
@Input('product') product: ProductInfo;
constructor() { }
ngOnInit() {
}
}
<div class="product">
<img [src]="product?.image">
<p>{{product?.name}}</p>
</div>
.product {
width: 130px;
margin: 8px;
padding: 8px;
border: 1px solid gray;
background-color: #f7f7f7;
text-align: center;
}
import { Component } from '@angular/core';
import { ProductInfo } from './../product/product.component'
@Component({
selector: 'app-ec-site',
templateUrl: './ec-site.component.html',
styleUrls: ['./ec-site.component.css']
})
export class EcSiteComponent {
products: ProductInfo[] = [
{ id: 0, name: 'TシャツA', image: 'data:image/png;base64,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' },
{ id: 1, name: 'TシャツB', image: 'data:image/png;base64,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' },
{ id: 2, name: 'TシャツC', image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAHBElEQVR4Xu2dX3LjRBDGe+zKvhJOQMQF2JyA7Ak2VFmufSN7AuAEhBMQTkDytmW7CucEm5wA5wLI3CC8OhsP1Ro5dhL/7ZHkmdanF6qIe9z9fT+NWvJo1hCORitgGl09iicA0HAIAAAAaLgCDS8fMwAAaLgCDS8fMwAAaLgCDS8fMwAAaLgCDS8fMwAACFeB7PT0kN68eU9Ep0R0l/R65+FmO88s63Y5z++IaEiTyXUyHN6HmndwM0D24cMRPT6+J2NOCuOddtaOkn7/OFQhF/PK0vRvMubt0/+z9iaHod2+Tj59GodUQxAAZGnKYn1PRGfPhHut1JisvQhRyBzc6ZRr4LP/aKXJ1o7ImCFZe530+6N9w7A3AHLTjfmxOMtXC7ZaIYZhTMbc0HTKot5Tu/1v1WdYflk6OODpnYpZ6i1Ze7QB3FVV8GzAMFztC4ZaAcg6HZ7a+Xp+SsYcVko/n2lE82svA0K07Rl3SNbOp3CXKANbXc7Wcn4MwzAZDK4r1WZh8EoBeNbEWXviIeBd0VTVpUsZ3yPPmWHgma2GJrJ0ABauhe5M9zystf+Zh4cje3AwNsZ85TlcLeF5zkQnluimpJyHOQyt1m3Zl7hSAHjq3Dc3cbsbYO1t0u+fFN9xScZwoxXuYe0ttdtnbFSWpjel5+subZdlNcJiAEpo4rYz0XXLTzNJlqZnxd1CWCCw8cZcJL0en635UQkAz1XzbiJ3AuCpiXP36JLOfTvTn3/qt2UPgHIAXV/BDeV+YGDTrR3y9XpZF188EPpVUrQghu+KbnZtItcC8NTEsdB1dO7Lq75Kej0+69cexYzEUDIY3K3nXbwlOjLGfLMpfsXf78h153y4W03+r7XjbW7bsjRlOPhJZr3Hwh0Ffflyu+5J5CsAXjx+9W7ivCsvegDvcfYwQA2XgG2rck3kksfSOQCVNnHbprj6c+Ok10v8h6l/hKzbzWq8VG5X4Ism0rx6br3dMPV+ajL5OuQfVJaJUdwOMwDhHtaOTNbt2nAzLDKz9mPS718Gn+dCgvndijF/hp5zLABwl/0udDEX88vS9HPxW0HQaccBAEto7fE2nXcIamedzgm1Wp9DyGVTDjEBEM0sEMvZz3DEA4BD+YfFJ22b6N7H37Nul2+d/9rHd0u+My4A+AFHu31c9g8iEuFWdv6Pj7waqLqfjctKthgnLgBcLzCih4d3od0WFgtFuPF7uY6gZMvKHS4+AAKEIFbzY+wB5vgHMhPEbH7cADgUxjSdfkwGA149U/tR3O7xw566fhktvcY4LwGvZTinyeSPuvqC4gezn4oVwKWbUueAWgBwswHRedLrXVUpYNbt8krm9Uu/q0yg5LE1ATCThkG4pFbrqqzbxeKHHTae1yVEO90vY0cjAIuNoltZS8RvFd3ucvJkacqrjPiWbtPLKrsMG9xndQPwUm73iha/0LG8aXQrn2YvfARnVhUJNQuAKhSMfEwAELmBvukDAF8FI48HAJEb6Js+APBVMPJ4ABC5gb7pAwBfBSOPBwCRG+ibPgDwVTDyeAAQuYG+6QMAXwUjjwcAkRvomz4A8FUw8ngAELmBvukDAF8FI48HAJEb6Js+APBVMPJ4ABC5gb7pAwBfBSOPBwCRG+ibfpkAzLdUmy265O3a3J6CbndtHLsqwJrybqNuq7r5olV++7gUTdcCUOx5O9the7ZPHtF0Oltde7/Nrh1Zp/MztVq/71p9oz8/nf6SDAYXmzQoNsx0r6O3Wm5V8/N9Et+u26+YAeANDXj9+4im05y0Kt61q3nXzE26hf33Lc3ftYj8XUYHymwjzdFOW8Xu+oUvP/9Pmt6XtHu2byrBxvOs+22/X9sGE7UCENDOmcECQDXvjFovAO5f06pr8+RwTV6f2dLNsasqBgBUpax8XAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CL0AyDVBZFUK1PovhlRVBMaVKwAA5NqpiAQAKmyUFwEA5NqpiAQAKmyUFwEA5NqpiAQAKmyUFwEA5NqpiAQAKmyUFwEA5NqpiAQAKmyUF/E/lhlG06YKCNIAAAAASUVORK5CYII=' },
{ id: 3, name: 'ボトムスA', image: 'data:image/png;base64,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' },
{ id: 4, name: 'ボトムスB', image: 'data:image/png;base64,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' },
];
constructor() { }
onAddProduct(product: ProductInfo) {
alert(`「${product.name}」を買い物かごへ追加`);
}
}
<div class="products">
<app-product *ngFor="let product of products" [product]="product"></app-product>
</div>
.products {
display: flex;
flex-wrap: wrap;
}
コンポーネントにコンテンツを表示
コンポーネント内に <ng-content>
を利用することで、呼び出し元で指定したコンテンツを表示することができます。
<div class="product">
<img [src]="product?.image">
<p>{{product?.name}}</p>
<ng-content></ng-content>
</div>
<div class="products">
<app-product *ngFor="let product of products" [product]="product">
<p>セール中!</p>
</app-product>
</div>
<ng-content>
に select="セレクタ"
を付けることで、複数のコンテンツを表示することもできます。
<div class="product">
<img [src]="product?.image">
<p>{{product?.name}}</p>
<ng-content select=".sale"></ng-content>
<ng-content select="div"></ng-content>
</div>
<div class="products">
<app-product *ngFor="let product of products" [product]="product">
<p class="sale">セール中!</p>
<div>お知らせ</div>
</app-product>
</div>
コンポーネントのイベントを処理する
コンポーネント内で発生したイベントを呼び出し元のコンポーネントへ伝えるには Output
と EventEmitter
を使用します。
@Output() プロパティ名 = new EventEmitter<型>();
で定義して、emit(オブジェクト)
でイベントを伝えます。
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
export class ProductInfo {
id: number;
name: string;
image?: string;
}
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
@Input('product') product: ProductInfo;
@Output() onAddProduct = new EventEmitter<ProductInfo>();
constructor() { }
ngOnInit() {
}
onAddClick() {
this.onAddProduct.emit(this.product);
}
}
<div class="product">
<img [src]="product?.image">
<p>{{product?.name}}</p>
<button (click)="onAddClick()">追加</button>
</div>
<div class="products">
<app-product *ngFor="let product of products" [product]="product" (onAddProduct)="onAddProduct($event)">
</app-product>
</div>
import { Component, OnInit } from '@angular/core';
import { ProductInfo } from './../product/product.component'
@Component({
selector: 'app-component',
templateUrl: './ec-site.component.html',
styleUrls: ['./ec-site.component.css']
})
export class EcSiteComponent implements OnInit {
products: ProductInfo[] = [
{ id: 0, name: 'TシャツA', image: 'data:image/png;base64,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' },
{ id: 1, name: 'TシャツB', image: 'data:image/png;base64,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' },
{ id: 2, name: 'TシャツC', image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAHBElEQVR4Xu2dX3LjRBDGe+zKvhJOQMQF2JyA7Ak2VFmufSN7AuAEhBMQTkDytmW7CucEm5wA5wLI3CC8OhsP1Ro5dhL/7ZHkmdanF6qIe9z9fT+NWvJo1hCORitgGl09iicA0HAIAAAAaLgCDS8fMwAAaLgCDS8fMwAAaLgCDS8fMwAAaLgCDS8fMwAACFeB7PT0kN68eU9Ep0R0l/R65+FmO88s63Y5z++IaEiTyXUyHN6HmndwM0D24cMRPT6+J2NOCuOddtaOkn7/OFQhF/PK0vRvMubt0/+z9iaHod2+Tj59GodUQxAAZGnKYn1PRGfPhHut1JisvQhRyBzc6ZRr4LP/aKXJ1o7ImCFZe530+6N9w7A3AHLTjfmxOMtXC7ZaIYZhTMbc0HTKot5Tu/1v1WdYflk6OODpnYpZ6i1Ze7QB3FVV8GzAMFztC4ZaAcg6HZ7a+Xp+SsYcVko/n2lE82svA0K07Rl3SNbOp3CXKANbXc7Wcn4MwzAZDK4r1WZh8EoBeNbEWXviIeBd0VTVpUsZ3yPPmWHgma2GJrJ0ABauhe5M9zystf+Zh4cje3AwNsZ85TlcLeF5zkQnluimpJyHOQyt1m3Zl7hSAHjq3Dc3cbsbYO1t0u+fFN9xScZwoxXuYe0ttdtnbFSWpjel5+subZdlNcJiAEpo4rYz0XXLTzNJlqZnxd1CWCCw8cZcJL0en635UQkAz1XzbiJ3AuCpiXP36JLOfTvTn3/qt2UPgHIAXV/BDeV+YGDTrR3y9XpZF188EPpVUrQghu+KbnZtItcC8NTEsdB1dO7Lq75Kej0+69cexYzEUDIY3K3nXbwlOjLGfLMpfsXf78h153y4W03+r7XjbW7bsjRlOPhJZr3Hwh0Ffflyu+5J5CsAXjx+9W7ivCsvegDvcfYwQA2XgG2rck3kksfSOQCVNnHbprj6c+Ok10v8h6l/hKzbzWq8VG5X4Ism0rx6br3dMPV+ajL5OuQfVJaJUdwOMwDhHtaOTNbt2nAzLDKz9mPS718Gn+dCgvndijF/hp5zLABwl/0udDEX88vS9HPxW0HQaccBAEto7fE2nXcIamedzgm1Wp9DyGVTDjEBEM0sEMvZz3DEA4BD+YfFJ22b6N7H37Nul2+d/9rHd0u+My4A+AFHu31c9g8iEuFWdv6Pj7waqLqfjctKthgnLgBcLzCih4d3od0WFgtFuPF7uY6gZMvKHS4+AAKEIFbzY+wB5vgHMhPEbH7cADgUxjSdfkwGA149U/tR3O7xw566fhktvcY4LwGvZTinyeSPuvqC4gezn4oVwKWbUueAWgBwswHRedLrXVUpYNbt8krm9Uu/q0yg5LE1ATCThkG4pFbrqqzbxeKHHTae1yVEO90vY0cjAIuNoltZS8RvFd3ucvJkacqrjPiWbtPLKrsMG9xndQPwUm73iha/0LG8aXQrn2YvfARnVhUJNQuAKhSMfEwAELmBvukDAF8FI48HAJEb6Js+APBVMPJ4ABC5gb7pAwBfBSOPBwCRG+ibPgDwVTDyeAAQuYG+6QMAXwUjjwcAkRvomz4A8FUw8ngAELmBvukDAF8FI48HAJEb6Js+APBVMPJ4ABC5gb7pAwBfBSOPBwCRG+ibfpkAzLdUmy265O3a3J6CbndtHLsqwJrybqNuq7r5olV++7gUTdcCUOx5O9the7ZPHtF0Oltde7/Nrh1Zp/MztVq/71p9oz8/nf6SDAYXmzQoNsx0r6O3Wm5V8/N9Et+u26+YAeANDXj9+4im05y0Kt61q3nXzE26hf33Lc3ftYj8XUYHymwjzdFOW8Xu+oUvP/9Pmt6XtHu2byrBxvOs+22/X9sGE7UCENDOmcECQDXvjFovAO5f06pr8+RwTV6f2dLNsasqBgBUpax8XAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CL0AyDVBZFUK1PovhlRVBMaVKwAA5NqpiAQAKmyUFwEA5NqpiAQAKmyUFwEA5NqpiAQAKmyUFwEA5NqpiAQAKmyUFwEA5NqpiAQAKmyUF/E/lhlG06YKCNIAAAAASUVORK5CYII=' },
{ id: 3, name: 'ボトムスA', image: 'data:image/png;base64,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' },
{ id: 4, name: 'ボトムスB', image: 'data:image/png;base64,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' },
];
constructor() { }
ngOnInit() {
}
onAddProduct(product: ProductInfo) {
alert(`「${product.name}」を買い物かごへ追加`);
}
}
ライフサイクル
Angularには、コンポーネントの生成時や、状態の変更時など、特定のタイミングで呼ばれるライフサイクルメソッドが用意されています。
メソッド名 | 実行タイミング |
---|---|
ngOnChanges | コンポーネントの入力プロパティ(@Input )変更時 |
ngOnInit | コンポーネントの初期化時 |
ngDoCheck | 変更を検知したとき |
ngAfterContentInit | 外部コンテンツ初期化時 |
ngAfterContentChecked | 外部コンテンツ変更時 |
ngAfterViewInit | 自分自身と子コンポーネントのビュー初期化時 |
ngAfterViewChecked | 自分自身と子コンポーネントのビュー変更時 |
ngOnDestroy | コンポーネントが破棄されるとき |
詳細は以下で説明されています。
https://qiita.com/ksh-fthr/items/ccd9861f919c4aa30ae8
サービス
共通のビジネスロジックを提供する仕組みをサービスといいます。
コンポーネントやディレクティブの constructor
にサービス型の引数を指定することで、依存性注入(Dependency Injection、DI とも呼ばれます)され、使うことができます。
アクセス修飾子を指定しない場合は constructor内のみ、private
を指定した場合はクラス内、public
を指定した場合はクラス外へ公開されます。
$ ng generate service study2/product/product
import { Injectable } from '@angular/core';
import { ProductInfo } from './product.component'
@Injectable({
providedIn: 'root'
})
export class ProductService {
private _products: ProductInfo[] = [
{ id: 0, name: 'TシャツA', image: 'data:image/png;base64,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' },
{ id: 1, name: 'TシャツB', image: 'data:image/png;base64,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' },
{ id: 2, name: 'TシャツC', image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAHBElEQVR4Xu2dX3LjRBDGe+zKvhJOQMQF2JyA7Ak2VFmufSN7AuAEhBMQTkDytmW7CucEm5wA5wLI3CC8OhsP1Ro5dhL/7ZHkmdanF6qIe9z9fT+NWvJo1hCORitgGl09iicA0HAIAAAAaLgCDS8fMwAAaLgCDS8fMwAAaLgCDS8fMwAAaLgCDS8fMwAACFeB7PT0kN68eU9Ep0R0l/R65+FmO88s63Y5z++IaEiTyXUyHN6HmndwM0D24cMRPT6+J2NOCuOddtaOkn7/OFQhF/PK0vRvMubt0/+z9iaHod2+Tj59GodUQxAAZGnKYn1PRGfPhHut1JisvQhRyBzc6ZRr4LP/aKXJ1o7ImCFZe530+6N9w7A3AHLTjfmxOMtXC7ZaIYZhTMbc0HTKot5Tu/1v1WdYflk6OODpnYpZ6i1Ze7QB3FVV8GzAMFztC4ZaAcg6HZ7a+Xp+SsYcVko/n2lE82svA0K07Rl3SNbOp3CXKANbXc7Wcn4MwzAZDK4r1WZh8EoBeNbEWXviIeBd0VTVpUsZ3yPPmWHgma2GJrJ0ABauhe5M9zystf+Zh4cje3AwNsZ85TlcLeF5zkQnluimpJyHOQyt1m3Zl7hSAHjq3Dc3cbsbYO1t0u+fFN9xScZwoxXuYe0ttdtnbFSWpjel5+subZdlNcJiAEpo4rYz0XXLTzNJlqZnxd1CWCCw8cZcJL0en635UQkAz1XzbiJ3AuCpiXP36JLOfTvTn3/qt2UPgHIAXV/BDeV+YGDTrR3y9XpZF188EPpVUrQghu+KbnZtItcC8NTEsdB1dO7Lq75Kej0+69cexYzEUDIY3K3nXbwlOjLGfLMpfsXf78h153y4W03+r7XjbW7bsjRlOPhJZr3Hwh0Ffflyu+5J5CsAXjx+9W7ivCsvegDvcfYwQA2XgG2rck3kksfSOQCVNnHbprj6c+Ok10v8h6l/hKzbzWq8VG5X4Ism0rx6br3dMPV+ajL5OuQfVJaJUdwOMwDhHtaOTNbt2nAzLDKz9mPS718Gn+dCgvndijF/hp5zLABwl/0udDEX88vS9HPxW0HQaccBAEto7fE2nXcIamedzgm1Wp9DyGVTDjEBEM0sEMvZz3DEA4BD+YfFJ22b6N7H37Nul2+d/9rHd0u+My4A+AFHu31c9g8iEuFWdv6Pj7waqLqfjctKthgnLgBcLzCih4d3od0WFgtFuPF7uY6gZMvKHS4+AAKEIFbzY+wB5vgHMhPEbH7cADgUxjSdfkwGA149U/tR3O7xw566fhktvcY4LwGvZTinyeSPuvqC4gezn4oVwKWbUueAWgBwswHRedLrXVUpYNbt8krm9Uu/q0yg5LE1ATCThkG4pFbrqqzbxeKHHTae1yVEO90vY0cjAIuNoltZS8RvFd3ucvJkacqrjPiWbtPLKrsMG9xndQPwUm73iha/0LG8aXQrn2YvfARnVhUJNQuAKhSMfEwAELmBvukDAF8FI48HAJEb6Js+APBVMPJ4ABC5gb7pAwBfBSOPBwCRG+ibPgDwVTDyeAAQuYG+6QMAXwUjjwcAkRvomz4A8FUw8ngAELmBvukDAF8FI48HAJEb6Js+APBVMPJ4ABC5gb7pAwBfBSOPBwCRG+ibfpkAzLdUmy265O3a3J6CbndtHLsqwJrybqNuq7r5olV++7gUTdcCUOx5O9the7ZPHtF0Oltde7/Nrh1Zp/MztVq/71p9oz8/nf6SDAYXmzQoNsx0r6O3Wm5V8/N9Et+u26+YAeANDXj9+4im05y0Kt61q3nXzE26hf33Lc3ftYj8XUYHymwjzdFOW8Xu+oUvP/9Pmt6XtHu2byrBxvOs+22/X9sGE7UCENDOmcECQDXvjFovAO5f06pr8+RwTV6f2dLNsasqBgBUpax8XAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CAAg105FJABQYaO8CL0AyDVBZFUK1PovhlRVBMaVKwAA5NqpiAQAKmyUFwEA5NqpiAQAKmyUFwEA5NqpiAQAKmyUFwEA5NqpiAQAKmyUFwEA5NqpiAQAKmyUF/E/lhlG06YKCNIAAAAASUVORK5CYII=' },
{ id: 3, name: 'ボトムスA', image: 'data:image/png;base64,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' },
{ id: 4, name: 'ボトムスB', image: 'data:image/png;base64,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' },
];
constructor() { }
products() {
return this._products;
}
}
import { Component } from '@angular/core';
import { ProductInfo } from './../product/product.component'
import { ProductService } from '../product/product.service';
@Component({
selector: 'app-ec-site',
templateUrl: './ec-site.component.html',
styleUrls: ['./ec-site.component.css']
})
export class EcSiteComponent {
constructor(public productService: ProductService) { }
onAddProduct(product: ProductInfo) {
alert(`「${product.name}」を買い物かごへ追加`);
}
}
<div class="products">
<app-product *ngFor="let product of productService.products()" [product]="product" (onAddProduct)="onAddProduct($event)">
</app-product>
</div>
インスタンス生成方法
サービスは、モジュールやコンポーネントの providers
プロパティでインスタンスの生成方法を指定することができます。
デフォルトで useClass
が指定され、providedIn
で root
を指定した場合、または app.module で指定した場合は、アプリケーション全体で1つのインスタンス(シングルトン)となります。
指定方法 | 説明 |
---|---|
useClass | クラスを指定して、Injectされるたびにそのクラスのインスタンスを生成。 |
useValue | オブジェクトを指定して、Injectされるたびにそのオブジェクトを参照。 |
useExisting | DIトークン(サービス)を指定して、エイリアス(別名)で生成。 |
useFactory | ファクトリー関数を指定して、Injectの際にオブジェクトを生成。 |
HTTP通信
Angular の HTTP通信は @angular/common/http
の HttpClientModule
で提供されています。
app.module.ts
に HttpClientModule
のインポートを追加してください。
Angular 4.2 までのHTTP通信は
@angular/http
のHttpModule
を利用していましたが、Angular 4.3 からは改良された@angular/common/http
のHttpClientModule
が追加され、これまでのHttpModule
は非推奨となりました。
import { HttpClientModule } from '@angular/common/http';
:
@NgModule({
declarations: [
:
],
imports: [
:
HttpClientModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
新にコンポーネントを生成し、http.component.ts
で HttpClient
をインポートし、constructor で DI (Dependency Injection)してください。
this.http.get(url, option)
で HTTP の GETリクエストが送信でき、.subscribe()
で結果を処理できます。
get<型>()
で、レスポンスの型を指定できます。(指定しない場合は any となる)
HttpClient
には get
の他に post
, put
, delete
などのメソッドが用意されています。
https://angular.io/api/common/http/HttpClient
$ ng generate component study2/http
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
class ResponseBody {
resultCount: number;
results: Array<any>;
}
@Component({
selector: 'app-http',
templateUrl: './http.component.html',
styleUrls: ['./http.component.css']
})
export class HttpComponent implements OnInit {
url = 'https://itunes.apple.com/lookup?id=292706922';
response: ResponseBody;
error: any;
// HttpClient を DI する
constructor(private http: HttpClient) { }
ngOnInit() {
// HTTP GETリクエスト
this.http.get<ResponseBody>(this.url).subscribe(
// 成功時のコールバック
response => this.response = response,
// 失敗時のコールバック
error => this.error = error
);
}
}
<p>{{url}}</p>
<pre *ngIf="response">
{{response | json}}
</pre>
<pre *ngIf="error">
{{error | json}}
</pre>
https://itunes.apple.com/lookup?id=292706922
{
"resultCount": 1,
"results": [
{
"wrapperType": "artist",
"artistType": "Artist",
"artistName": "AKB48",
"artistLinkUrl": "https://itunes.apple.com/us/artist/akb48/292706922?uo=4",
"artistId": 292706922,
"amgArtistId": 989429,
"primaryGenreName": "J-Pop",
"primaryGenreId": 27
}
]
}
レスポンスのフォーマットはデフォルトでは JSON ですが、オプションの responseType
で指定することもできます。
this.http.get(this.url, { responseType: 'text' })
レスポンスの内容はデフォルトでは body だけですが、オプションの observe
に response
を指定することで、ヘッダーやステータスコード等を含むレスポンスを取得できます。
import { Component, OnInit } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
class ResponseBody {
resultCount: number;
results: Array<any>;
}
@Component({
selector: 'app-http',
templateUrl: './http.component.html',
styleUrls: ['./http.component.css']
})
export class HttpComponent implements OnInit {
url = 'https://itunes.apple.com/lookup?id=292706922';
response: HttpResponse<ResponseBody>;
error: any;
// HttpClient を DI する
constructor(private http: HttpClient) { }
ngOnInit() {
// HTTP GETリクエスト
this.http.get<ResponseBody>(this.url, { observe: 'response' }).subscribe(
// 成功時のコールバック
response => this.response = response,
// 失敗時のコールバック
error => this.error = error
);
}
}
https://itunes.apple.com/lookup?id=292706922
{
"headers": {
"normalizedNames": {},
"lazyUpdate": null
},
"status": 200,
"statusText": "OK",
"url": "https://itunes.apple.com/lookup?id=292706922",
"ok": true,
"type": 4,
"body": {
"resultCount": 1,
"results": [
{
"wrapperType": "artist",
"artistType": "Artist",
"artistName": "AKB48",
"artistLinkUrl": "https://itunes.apple.com/us/artist/akb48/292706922?uo=4",
"artistId": 292706922,
"amgArtistId": 989429,
"primaryGenreName": "J-Pop",
"primaryGenreId": 27
}
]
}
}
楽曲検索アプリ作成
Step1. 楽曲情報を Component化
前回の復習で作成したページの楽曲情報を Component で作成してください。
$ ng generate component study2/music-search/music-item
答え
<div>
<img [src]="item?.artworkUrl100">
<div class="track-name">{{item?.trackName}}</div>
<div class="artist-name">{{item?.artistName}}</div>
</div>
.track-name {
font-weight: bold;
}
import { Component, OnInit, Input } from '@angular/core';
import { MusicItem } from '../music-search.service';
@Component({
selector: 'app-music-item',
templateUrl: './music-item.component.html',
styleUrls: ['./music-item.component.css']
})
export class MusicItemComponent implements OnInit {
@Input() item: MusicItem;
constructor() { }
ngOnInit() {
}
}
<div>
<input type="text">
<button (click)="onSearch()">検索</button>
<div id="resultContent">
<app-music-item *ngFor="let item of results" [item]="item"></app-music-item>
</div>
</div>
Step2. データ取得処理を Service化
データ取得処理を Service で作成してください。
$ ng generate service study2/music-search/music-search
答え
import { Injectable } from '@angular/core';
export class MusicItem {
trackName: string;
artistName: string;
artworkUrl100: string;
}
@Injectable({
providedIn: 'root'
})
export class MusicSearchService {
constructor() { }
search() {
return [
{ artistName: 'アーティスト名1', trackName: '楽曲名1', artworkUrl100: 'https://is5-ssl.mzstatic.com/image/thumb/Music6/v4/a5/df/97/a5df97ec-b7e4-7f78-625a-f331603b0756/source/100x100bb.jpg' },
{ artistName: 'アーティスト名2', trackName: '楽曲名2', artworkUrl100: 'https://is4-ssl.mzstatic.com/image/thumb/Music/v4/fb/d8/04/fbd8047c-293e-1f90-4b06-929bbeca20b1/source/100x100bb.jpg' },
{ artistName: 'アーティスト名3', trackName: '楽曲名3', artworkUrl100: 'https://is2-ssl.mzstatic.com/image/thumb/Music/v4/4d/2e/39/4d2e39ef-fd24-a902-e704-cb7dc2ae6c5b/source/100x100bb.jpg' },
{ artistName: 'アーティスト名4', trackName: '楽曲名4', artworkUrl100: 'https://is5-ssl.mzstatic.com/image/thumb/Music/v4/54/ff/d6/54ffd6b2-3f3f-ce92-189d-20c3143b2380/source/100x100bb.jpg' },
{ artistName: 'アーティスト名5', trackName: '楽曲名5', artworkUrl100: 'https://is2-ssl.mzstatic.com/image/thumb/Music6/v4/ae/4a/fd/ae4afdd5-0dc7-31a4-ab96-eacc806a32d5/source/100x100bb.jpg' }
];
}
}
import { Component, OnInit } from '@angular/core';
import { MusicSearchService, MusicItem } from './music-search.service';
@Component({
selector: 'app-music-search',
templateUrl: './music-search.component.html',
styleUrls: ['./music-search.component.css']
})
export class MusicSearchComponent implements OnInit {
constructor(private musicSearch: MusicSearchService) { }
/** 検索結果 */
results: MusicItem[];
ngOnInit() {
}
/**
* 検索実行
*/
onSearch() {
this.results = this.musicSearch.search();
}
}
Step3. APIで取得した結果を表示
iTunes Search API を呼び出し、テキストボックスに入力したキーワードのアーティストの楽曲を検索し取得結果を表示してください。
答え
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
export class ResponseBody {
resultCount: number;
results: MusicItem[];
}
export class MusicItem {
trackName: string;
artistName: string;
artworkUrl100: string;
}
@Injectable({
providedIn: 'root'
})
export class MusicSearchService {
constructor(private http: HttpClient) { }
search(keyword: string) {
var url = `https://itunes.apple.com/search?term=${keyword}&country=jp&media=music&attribute=artistTerm`;
return this.http.get<ResponseBody>(url);
}
}
<div>
<input type="text" #keyword>
<button (click)="onSearch(keyword.value)">検索</button>
<div id="resultContent">
<app-music-item *ngFor="let item of results" [item]="item"></app-music-item>
</div>
</div>
import { Component, OnInit } from '@angular/core';
import { MusicSearchService, MusicItem } from './music-search.service';
@Component({
selector: 'app-music-search',
templateUrl: './music-search.component.html',
styleUrls: ['./music-search.component.css']
})
export class MusicSearchComponent implements OnInit {
constructor(private musicSearch: MusicSearchService) { }
/** 検索結果 */
results: MusicItem[];
ngOnInit() {
}
/**
* 検索実行
* @param keyword 検索キーワード
*/
onSearch(keyword: string) {
this.musicSearch.search(keyword).subscribe(response => {
this.results = response.results;
});
}
}
Step4. 検索対象の切り替え
アーティスト名、曲名のラジオボタンを追加して、選択した値を対象として検索するようにしてください。
答え
<div>
<input type="text" #keyword>
<button (click)="onSearch(keyword.value)">検索</button>
<div>
<input type="radio" name="attribute" value="artistTerm" [(ngModel)]="attribute">アーティスト名
<input type="radio" name="attribute" value="songTerm" [(ngModel)]="attribute">曲名
</div>
<div id="resultContent">
<app-music-item *ngFor="let item of results" [item]="item"></app-music-item>
</div>
</div>
import { Component, OnInit } from '@angular/core';
import { MusicSearchService, MusicItem } from './music-search.service';
@Component({
selector: 'app-music-search',
templateUrl: './music-search.component.html',
styleUrls: ['./music-search.component.css']
})
export class MusicSearchComponent implements OnInit {
attribute = 'artistTerm';
constructor(private musicSearch: MusicSearchService) { }
/** 検索結果 */
results: MusicItem[];
ngOnInit() {
}
/**
* 検索実行
* @param keyword 検索キーワード
*/
onSearch(keyword: string) {
this.musicSearch.search(keyword, this.attribute).subscribe(response => {
this.results = response.results;
});
}
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
export class ResponseBody {
resultCount: number;
results: MusicItem[];
}
export class MusicItem {
trackName: string;
artistName: string;
artworkUrl100: string;
}
@Injectable({
providedIn: 'root'
})
export class MusicSearchService {
constructor(private http: HttpClient) { }
search(keyword: string, attribute: string) {
var url = `https://itunes.apple.com/search?term=${keyword}&country=jp&media=music&attribute=${attribute}`;
return this.http.get<ResponseBody>(url);
}
}
Step5. iTunes ページ表示
検索結果の楽曲をクリックしたときに、新しいウィンドウで iTunes の楽曲ページを表示してください。
答え
import { Component, OnInit } from '@angular/core';
import { MusicSearchService, MusicItem } from './music-search.service';
@Component({
selector: 'app-music-search',
templateUrl: './music-search.component.html',
styleUrls: ['./music-search.component.css']
})
export class MusicSearchComponent implements OnInit {
attribute = 'artistTerm';
constructor(private musicSearch: MusicSearchService) { }
/** 検索結果 */
results: MusicItem[];
ngOnInit() {
}
/**
* 検索実行
* @param keyword 検索キーワード
*/
onSearch(keyword: string) {
this.musicSearch.search(keyword, this.attribute).subscribe(response => {
this.results = response.results;
});
}
/**
* 楽曲クリック時
* @param item 楽曲情報
*/
onItemClick(item: MusicItem) {
// iTunesのページを新しいウィンドウで開く
window.open(item.trackViewUrl, 'trackView', 'width=400, height=600');
}
}
Step6. 横並びレイアウト
検索結果を横に並べて表示してください。
答え
#resultContent {
display: flex;
flex-wrap: wrap;
}
app-music-item {
width: 200px;
margin-bottom: 16px;
}
Extra1. ページング
ページング機能を追加してください。
答え
<div>
<input type="text" [(ngModel)]="keyword">
<button (click)="onSearch(0)">検索</button>
<div>
<input type="radio" name="attribute" value="artistTerm" [(ngModel)]="attribute">アーティスト名
<input type="radio" name="attribute" value="songTerm" [(ngModel)]="attribute">曲名
</div>
<div id="resultContent">
<app-music-item *ngFor="let item of results" [item]="item" (click)="onItemClick(item)"></app-music-item>
</div>
<div id="pager">
<button (click)="onPrev()">←</button>
<span id="pageIndex">{{currentPage + 1}}</span>
<button (click)="onNext()">→</button>
</div>
</div>
#resultContent {
display: flex;
flex-wrap: wrap;
}
app-music-item {
width: 200px;
margin-bottom: 16px;
}
#resultContent {
display: flex;
flex-wrap: wrap;
}
#pager {
display: flex;
justify-content: space-around;
}
import { Component, OnInit } from '@angular/core';
import { MusicSearchService, MusicItem } from './music-search.service';
@Component({
selector: 'app-music-search',
templateUrl: './music-search.component.html',
styleUrls: ['./music-search.component.css']
})
export class MusicSearchComponent implements OnInit {
keyword: string;
attribute = 'artistTerm';
currentPage = 0;
constructor(private musicSearch: MusicSearchService) { }
/** 検索結果 */
results: MusicItem[];
ngOnInit() {
}
/**
* 検索実行
*/
onSearch(page = 0) {
this.currentPage = page;
this.musicSearch.search(this.keyword, this.attribute, page).subscribe(response => {
this.results = response.results;
});
}
/**
* 楽曲クリック時
* @param item 楽曲情報
*/
onItemClick(item: MusicItem) {
// iTunesのページを新しいウィンドウで開く
window.open(item.trackViewUrl, 'trackView', 'width=400, height=600');
}
onPrev() {
if (0 < this.currentPage) {
this.onSearch(this.currentPage - 1);
}
}
onNext() {
this.onSearch(this.currentPage + 1);
}
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
export class ResponseBody {
resultCount: number;
results: MusicItem[];
}
export class MusicItem {
trackName: string;
artistName: string;
artworkUrl100: string;
trackViewUrl: string;
}
@Injectable({
providedIn: 'root'
})
export class MusicSearchService {
limit = 10;
constructor(private http: HttpClient) { }
search(keyword: string, attribute: string, page: number) {
var url = `https://itunes.apple.com/search?term=${keyword}&country=jp&media=music&attribute=${attribute}&limit=${this.limit}&offset=${this.limit * page}`;
return this.http.get<ResponseBody>(url);
}
}