50
26

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 5 years have passed since last update.

Angular入門 未経験から1ヶ月でサービス作れるようにする その3. ルーティング基礎

Last updated at Posted at 2018-07-23

前回は、

  • ディレクトリ構造
  • コンポーネントの基本的な変更の仕方

を学びました。

本記事では、

  • SCSSの有効化
    • CSSでは不便だと言う人向けに、SCSSを使うように設定を変更します。
  • 新しくページを作って、ページ間の遷移を行う
    • 基本的なルーティングの設定方法
    • 新しいコンポーネントの作り方
    • ページ間のリンクを貼ってみる

をやっていきます。

この記事のソースコード

この記事終了時のソースコードは、下記を参照してください。

https://github.com/seteen/AngularGuides/tree/入門その03

SCSSの有効化

まず Angular内で利用する CSS を SCSS に変更しましょう。
(CSSの方が好きだという方はこの手順はスキップして大丈夫です)

グローバルスタイルの定義(style.css)のSCSSへの変更

まずは、Angularのグローバルなスタイル(このスタイルはすべてのコンポーネントに影響します)を定義している src/style.css を変更します。

まずは、ファイルをリネームします。

mv src/style.css src/style.scss

これはただのファイル名の変更なので、普通にGUIで変更しても問題ありません。

次に、 angular.json を変更します。

angular.json
{
  ...
  "projects": {
    "angular-sample": { # ここは別の名前でプロジェクトを作った人は別になります
      ...
      "architect": {
        ...
        "build": {
          ...
          "options": {
            ...
            "styles": [
              "style.css" # これを styles.scss に変更
            ]
          }
        },
        ...
        "test": {
          ...
          "options": {
            ...
            "styles": [
              "style.css" # これを styles.scss に変更
            ]
          }
        }
      }
    }
  }
}

上記のように変更することで、グローバルなスタイル定義が src/styles.scss に変更されます。

実際のコミット

この変更の実際のコミットが下記なので、よくわからない、という人は参考にしてください。

プロジェクトのデフォルト設定をCSSからSCSSに変更

プロジェクトのデフォルト設定を SCSS に変更することで、後ほど出てくる コンポーネントを作成してくれるコマンドで自動生成されるスタイルファイルをCSSからSCSSに変更してくれます。

変更するのは、下記です。

angular.json
{
  ...
  "projects": {
    "angular-sample": { # ここは別の名前でプロジェクトを作った人は別になります
      ...
      "schematics": { # ここは空なので、下記を追加する
        "@schematics/angular:component": {
          "styleext": "scss"
        }
      }
    }
  }
}

実際のコミット

この変更の実際のコミットが下記なので、よくわからない、という人は参考にしてください。

コンポーネントの作成

では、本題に入っていきましょう。

まずは、ページ(コンポーネント)を2つ作ります。

Angular CLI には、コンポーネントを作成するためのコマンドが用意されているので、使ってみましょう。

ng g component product/product-list

上記コマンドを実行してみると、下記のように表示されます。

# ng g component product/product-list
CREATE src/app/product/product-list/product-list.component.scss (0 bytes)
CREATE src/app/product/product-list/product-list.component.html (32 bytes)
CREATE src/app/product/product-list/product-list.component.spec.ts (671 bytes)
CREATE src/app/product/product-list/product-list.component.ts (297 bytes)

続けて、もう一つページを作成しましょう。

ng g component product/product-detail

上記コマンドを実行します。

# ng g component product/product-detail
CREATE src/app/product/product-detail/product-detail.component.scss (0 bytes)
CREATE src/app/product/product-detail/product-detail.component.html (34 bytes)
CREATE src/app/product/product-detail/product-detail.component.spec.ts (685 bytes)
CREATE src/app/product/product-detail/product-detail.component.ts (305 bytes)
UPDATE src/app/app.module.ts (554 bytes)

これにより、新しくディレクトリとファイルが作成されました。

001.png

TIPS: ディレクトリ構造
今回のプロジェクトでは、 src/app/product というディレクトリに product 関連ページのコンポーネントを入れていきます。
Angularでは、ディレクトリ構造は自由に決められますが、関連するページをディレクトリにまとめるなどはやったほうが良いと思います。
参考↓
https://angular.io/guide/styleguide#style-04-06

実際のコミット

もし、CLIのコマンドがうまく動かない、という人がいたら、下記コミットを参考にしてファイルを作成してください。
特にコマンドによる作成の方が良いというわけではないです。自分でファイルを作成しても変化はありません。

ルーティングファイルの作成

次に、ルーティングファイルを作成します。
ルーティングファイルというのは、AngularにおけるURLとコンポーネントの対応を定義するファイルです。

おそらく、最初は各要素が何を意味しているかわからないと思いますが、まずは書いてみましょう。

src/app/app-routing.module.ts
import { RouterModule, Routes } from '@angular/router';
import { NgModule } from '@angular/core';
import { ProductListComponent } from './product/product-list/product-list.component';
import { ProductDetailComponent } from './product/product-detail/product-detail.component';

const routes: Routes = [
  { path: 'products', component: ProductListComponent },
  { path: 'products/:id', component: ProductDetailComponent },
  { path: '', redirectTo: '/products', pathMatch: 'prefix' },
];
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: []
})
export class AppRoutingModule {}

解説

解説と言いつつ、 @NgModule 以下の行は、とりあえずおまじないと思って無視しましょう。

いったんここでは「なるほどわからん」くらいに思っておいてください。

重要なのは、 const routes: Routes です。
ここで、ルーティングの定義を行っています。

{ path: 'products', component: ProductListComponent },

まず、これは、 http://localhost:4200/products の URL(サーバにあげればホスト名は変わります)を 先程作成した ProductListComponent にマッピングする、という意味です。
ここは非常にわかりやすいですね。

ただ、 まだこの時点では実際にアクセスしてもマッピングされていない ので試すのはもう少し待っておいてください。

{ path: 'products/:id', component: ProductDetailComponent },

次に、この行ですが、これは、 http://localhost:4200/products/xxx (xxxは何でも良い)ProductDetailComponent にマッピングするという意味です。
上記の :id は、コンポーネントからパラメータとして取得できるので、その内容によってコンポーネントの状態を変更させたい場合に利用します。

productid をURLから取得することで、最終的には API を叩いてその idproduct の情報を取得して表示する、というコンポーネントにしたいと思っています。

{ path: '', redirectTo: '/products', pathMatch: 'prefix' },

最後にこの行ですが、上で説明した2つのURL以外のURLが指定されると、自動的に /products にリダイレクトさせるという意味です。

TIPS: pathMatch とは
pathMatch は、 fullprefix が指定できます。

full の場合はURLが path と完全に一致した場合(今回の場合 >http://localhost:4200/ ) にリダイレクトします。

prefix の場合は、URLが path の値で始まる場合 (今回の場合は、>http://localhost:4200/ で始まるすべてのURL。事前に定義されている /products >, /products/:id を除く) にリダイレクトします。

実際のコミット

この変更の実際のコミットが下記なので、よくわからない、という人は参考にしてください。

ルーティングを有効な状態にする

現状では、まだルーティングは有効ではありません。

なぜなら、app-routing.module.ts はプロジェクト上に存在しているだけでどこからも参照されていないからです。

app.module.tsから参照する

このプロジェクトのモジュール群を管理している app.module.tsapp-routing.module.ts を追加します。

src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ProductListComponent } from './product/product-list/product-list.component';
import { ProductDetailComponent } from './product/product-detail/product-detail.component';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
  declarations: [
    AppComponent,
    ProductListComponent,
    ProductDetailComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule, // ここを追加
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.tsを変更する

上記で、 app.module.ts から参照されました。

ただ、現状の app.module.ts は、 app.component.ts(html,css) の内容を表示しています。

このプロジェクトは app.component.ts(html,css) を表示する、というのがこのプロジェクトの起点になっています。
そのため、 app.component.html でルーティングされたコンポーネントを表示する、ということが必要になります。

ルーティングされているコンポーネントを表示するには <router-outlet></router-outlet> という要素を利用します。

app.component.html を書き換えます。

src/app/app.component.html
<router-outlet></router-outlet>

これにより、ルーティングされたコンポーネントが表示されるようになります。

ng serve

でプロジェクトを起動して確認してみましょう。

002.png

http://localhost:4200/ にアクセスすると、上記のように自動で http://localhost:4200/products にリダイレクトされます。

表示されている内容も、 ProductListComponent のものとなっていることが確認できます。

また、 http://localhost:4200/products/test にアクセスしてみましょう。

003.png

今度は ProductDetailComponent の内容が表示されることが確認できます。

実際のコミット

ページ間のリンクを作ってみる

Angularの中で リンクを作ってみましょう。Angularのコンポーネント中では、 <a> 要素を用いてリンクを作らずに、別のやり方でリンクを作成します。
( 実は <a> 要素も動きますが、非推奨です )

準備として、ボタンのCSSを用意

少し見栄えを良くするために、ボタンのCSSを作っておきます。 styles.scss を下記のように修正します。

src/style.scss
/* You can add global styles to this file, and also import other style files */
.button {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 35px;
  width: 135px;
  border-radius: 4px;
  background-color: #2196F3;
  color: #FFFFFF;
  font-size: 14px;
  line-height: 21px;
  cursor: pointer;

  &.black {
    background-color: #212121;
  }

  &.white {
    color: #212121;
    background-color: white;
    border: 1px solid #212121;
  }
}

リンクを作成

では、まずは ProductDetailComponent から ProductListComponent へのリンクを作成します。

src/app/product/product-detail/product-detail.component.html
<p>
  product-detail works!
</p>
<div class="button" routerLink="/products">
  商品一覧へ
</div>

追加した、項目の routerLink というのが、 Angular上でのルートの遷移を行うための属性になります。

とても簡単ですね。

なお、 その1 で紹介した WebStorm のプラグインを使えば、補完が効きます。便利ですね。

004.png

次に、 ProductListComponent から ProductDetailComponent へのリンクを作成します。

今回は、別の指定の方法を行います。

src/app/product/product-list/product-list.component.html
<p>
  product-list works!
</p>
<div class="button" [routerLink]="['/products', 'test']">
  商品詳細へ
</div>

前回とは少し違う書き方をしていることに気づきましたか?

今回は、 [routerLink] という風に routerLink[] で囲いました。

この [] で囲った属性は、Angularでは要素に対して Javascript の要素を入力するという意味になります。

[routerLink] は、配列を受け取ります。配列の各要素は、ルーティングの階層を表していて、これは、 <div class="button" routerLink="/products/test"> と書いたときと全く同じ動きをします。

実際に起動してみましょう。

http://localhost:4200/products にアクセスすると、下記のような画面が表示されます。

005.png

ボタンを押すと、 http://localhost:4200/products/test に遷移します。

006.png

ここまでのコミット

[routerLink] の使いどころ

routerLink[routerLink] の2つのリンクの作り方を紹介しました。

同じなら、なぜこんな書き方をするの?と思った方も多いと思います。

今回は、 /products/test というすでに決まりきっている内容を入れましたが、例えばリンクの内容が Typescript 上で計算された値を入れたいときには、この書き方はとても有用になります。

少し ProductListComponent を変更してみます。

src/app/product/product-list/product-list.component.ts
import { Component, OnInit } from '@angular/core';

 @Component({
   selector: 'app-product-list',
   templateUrl: './product-list.component.html',
   styleUrls: ['./product-list.component.scss']
 })
 export class ProductListComponent implements OnInit {
   id = '100'; // ここを追加

   constructor() { }

   ngOnInit() {
   }

 }
src/app/product/product-list/product-list.component.html
<p>
  product-list works!
</p>
<div class="button" [routerLink]="['/products', id]">
  商品詳細へ
</div>

今回は、リンクの値を Typescript の変数から取得するようにしました。

このように、 Typescript で定義したり、計算したりしている値を使いたいときに、 [routerLink] の書き方は有効です。

ここでも、 WebStorm のプラグインを利用することで、補完が効きます。やっぱり便利ですね。

007.png

ここまでのコミット

終わりに

今回は、ルーティングの基礎を学びました。

まだおまじないのような部分があると思いますが、現状ではそこまで理解しなくても大丈夫なので、説明した部分だけをしっかり覚えておいてください。

次回は、Angularにおけるデータ管理の基礎、およびHTML内での分岐、ループについて解説していきます。

Angular入門 未経験から1ヶ月でサービス作れるようにする その4. モデルとループと分岐と

入門記事一覧

「Angular入門 未経験から1ヶ月でサービス作れるようにする」は、記事数が多いため、まとめ記事 を作っています。
https://qiita.com/seteen/items/43908e33e08a39612a07

50
26
3

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
50
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?