前回、TOPページをいい感じにしました。
今回は他の画面を作って、画面遷移できるようにしてみます。
ブログ一覧/詳細ページの追加
ブログの画面は以下のようなURLになるように作りたいと思います。
一覧:/blogs
詳細:/blogs/:id
サービスの作成
画面を作る前に表示用のデータを取得用サービスを作ります。
ただ、今回はまだFirebaseからデータを取得しないので、ダミーデータを返すようにします。
src/app/blogs/blogs.service.ts
import { Injectable } from '@angular/core';
import { Blog } from 'src/types/blog.interface';
@Injectable()
export class BlogsService {
readonly testData: Blog[] = [
{ id: 1, title: 'ブログ1', contents: 'ブログ1のコンテンツ', tags: ['タグ1'], created_at: '2020/01/01 00:00:00' },
{ id: 2, title: 'ブログ2', contents: 'ブログ2のコンテンツ', tags: ['タグ2', 'タグ3'], created_at: '2020/01/02 00:00:00' },
];
constructor() { }
async getBlogs() {
return this.testData;
}
async getBlog(id: number) {
return this.testData.find(data => data.id === id);
}
}
- getBlogs:ブログ一覧を返却
- getBlog:指定したIDを持つブログを返却
※後々ちゃんとFirebaseから取得するようにします(それを想定してasyncつけてます)
ちなみにBlog型は以下のように定義してます
src/types/blog.interface.ts
export interface Blog {
id: number;
title: string;
contents: string;
tags: string[];
created_at: string;
}
ブログ一覧画面
- 一覧表示用のコンポーネントを作成
- コンストラクタでサービスをDI
- getBlogsで取得した一覧情報をblogsに設定
src/app/blogs/list/list.component.ts
import { Component, OnInit } from '@angular/core';
import { BlogsService } from '../blogs.service';
import { Blog } from 'src/types/blog.interface';
@Component({
selector: 'app-blogs-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.scss']
})
export class BlogsListComponent implements OnInit {
blogs: Blog[];
constructor(private blogsService: BlogsService) { }
async ngOnInit() {
this.blogs = await this.blogsService.getBlogs();
}
}
- HTMLを作成
- コンポーネント側でblogsに一覧を設定するため、項目数分だけngForでループを回す
- 作成日はパイプを使って
yyyy/MM/dd
形式で出力 - ブログタイトルはリンクを表示(表示しているブログIDをリンク先に指定)
src/app/blogs/list/list.component.html
<div class="blog-list">
<h1 class="title">ブログ一覧</h1>
<ul *ngIf="blogs">
<li *ngFor="let blog of blogs">
<span class="create-date">{{blog.created_at | date: 'yyyy/MM/dd'}}</span>
<a class="blog-title" routerLink="/blogs/{{blog.id}}">{{blog.title}}</a>
</li>
</ul>
</div>
詳細画面の追加
- コンポーネントの作成
- コンストラクタでサービスをDI
- URLのパスからブログIDを取得するためActivatedRouteをDI
-
this.activatedRoute.snapshot.params.id
でパスからIDを取得 - getBlogでIDで指定された内容を取得
- params.idはstringのため、Number(id)で数値型に変換
src/app/blogs/detail/detail.component.ts
import { Component, OnInit } from '@angular/core';
import { BlogsService } from '../blogs.service';
import { ActivatedRoute } from '@angular/router';
import { Blog } from 'src/types/blog.interface';
@Component({
selector: 'app-blogs-detail',
templateUrl: './detail.component.html',
styleUrls: ['./detail.component.scss']
})
export class BlogsDetailComponent implements OnInit {
detail: Blog;
constructor(private blogsService: BlogsService, private activatedRoute: ActivatedRoute) { }
async ngOnInit() {
const id = this.activatedRoute.snapshot.params.id;
if (id) {
this.detail = await this.blogsService.getBlog(Number(id));
}
}
}
src/app/blogs/detail/detail.component.html
<div *ngIf="detail" class="blog-detail">
<h1>{{detail.title}}</h1>
<span>{{detail.contents}}</span>
</div>
/blogsルーティング設定
遅延ロードによるモジュール読み込みを行えるようなモジュール構成にしていきます
-
/blogs
のサブパスでモジュールを切るため、BlogsRoutingModuleを作成- 詳細ページは
:id
で動的にブログIDを指定できるようにします
- 詳細ページは
src/app/blogs/blogs-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { BlogsListComponent } from './list/list.component';
import { BlogsDetailComponent } from './detail/detail.component';
const routes: Routes = [
{ path: '', component: BlogsListComponent },
{ path: ':id', component: BlogsDetailComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class BlogsRoutingModule { }
- BlogsModuleを作成し、一覧/詳細コンポーネントの宣言、BlogsRoutingModuleのインポートを行います
src/app/blogs/blogs.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BlogsRoutingModule } from './blogs-routing.module';
import { BlogsService } from './blogs.service';
import { BlogsListComponent } from './list/list.component';
import { BlogsDetailComponent } from './detail/detail.component';
@NgModule({
declarations: [
BlogsListComponent,
BlogsDetailComponent,
],
imports: [
CommonModule,
BlogsRoutingModule,
],
providers: [
BlogsService,
]
})
export class BlogsModule { }
-
app-routing.module.ts
でloadChildrenを用いてBlogsModuleを遅延ロードするようにします- こうすることで、/blogsにアクセスしたときにはじめてBlogsModuleが読み込まれるようになるため、その分初期表示時の負荷が軽減できます。
- また、Moduleのインポートが不要のため、blogsディレクトリ内でコードが完結できるという点もGoodだと思います。
src/app/app-routing.module.ts
・・・
const routes: Routes = [
・・・
{ path: 'blogs', loadChildren: () => import('./blogs/blogs.module').then(m => m.BlogsModule) },
・・・
];
・・・
こんな感じになりました
ブログ一覧
/blogs
ブログ詳細
/blogs/1
自己紹介ページ
ちなみに、自己紹介ページも雑に作りました。
まとめ
だいぶブログの体をなしてきた気がしてきました!
次回はFirestoreからデータをとってきて、画面に出力するところをやってみようと思います。
(追記)
Angular9とFirebaseでブログを作ってみる5(Firestoreからデータを取得して表示してみる)