3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Angular9とFirebaseでブログを作ってみる4(画面遷移をできるようにしてみる)

Last updated at Posted at 2020-01-25

前回、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

image.png

ブログ詳細

/blogs/1

image.png

自己紹介ページ

ちなみに、自己紹介ページも雑に作りました。

image.png

まとめ

だいぶブログの体をなしてきた気がしてきました!

次回はFirestoreからデータをとってきて、画面に出力するところをやってみようと思います。

(追記)
Angular9とFirebaseでブログを作ってみる5(Firestoreからデータを取得して表示してみる)

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?