Angular開発現場のTips-その1

本記事では SEROKU の開発を例に Angular Tips の紹介をしています。(その 3 くらいまで続いています)

関連記事

Angular開発現場のTips-その2

Angular開発現場のTips-その3

AngularとBrowsersyncで複数ブラウザ対応を楽にする

SEROKUでは、フロントエンド開発およびバックエンド開発それぞれにおいてWebアプリケーションフレームワークを使用しています。

フレームワークを使う意義は、ネットを探せばいくらでも見つかると思うのでそこに関しての説明は省きますが、今回はフロントエンド開発で使用しているAngularに関して、SEROKU開発において貯まったTipsを少しでも共有できればと思い記事化することにしました。

あくまで、こう書くべきだという強い意志ではなく、こう書いたら良いんじゃないかな? くらいの気持ちで書きますので参考程度にしてもらえれば幸いです。

Angularとは

いきなりTipsの話をする前に、一応Angularに関しての説明をサクッとしておきます。

AngularはGoogleによって開発されているJavaScriptフレームワークで、2018年6月現在の最新のメジャーバージョンは6です。
※Angularは「セマンティックバージョニング」というものと「タイムベースリリース」を採用しており、これによりどういった周期でどれくらいのアップデートが行われるかというのが、予測可能になっています。

JavaScriptフレームワークと書きましたが、使用する言語はTypeScript((TypeScriptは、マイクロソフトによって開発、メンテナンスされているOSSのプログラミング言語です。))です。

TypeScriptは、JavaScriptのいわゆるスーパーセットで、クラスベースのオブジェクト指向で開発できるのが利点です。

またAngularはフルスタックフレームワークなので(PHPでいうところのCakePHPや、RubyでいうところのRubyOnRails)、学習コストは多少高めですが、独立したフレームワークを組み合わせて動作させることの苦労に比べればそこまでのハードルではないように思います。(これに関しては賛否両論あると思います)

では次の項目からAngularのTipsを書いていこうと思います。

Tips1 :ロジックは極力コンポーネントクラスに寄せよう

初心者が陥りがち?なものとして、htmlに何でもかんでもロジックを詰め込んでしまうのがよく見受けられます。
例えば、あるモデルクラスの特定のフィールドを元に、さらに出し分けたいパターンがあるとします。

例:以下に定義するテストモデルクラスのisSMaleフィールドのT/Fによって、nameに「くん」または「さん」をつけて出力する

class TestModel {
   // このフィールドによって出力を変更する
  isSMale: boolean = false;
  name: string;
}

この場合に以下のように、templateの内部でロジックを駆使し、書いてしまう。

@Component({
  selector: 'ng-if-let',
  template: `
    <div>{{ testModel.name }} {{testModel.isMale ? 'くん' : 'さん'}}</div>
 `
})
class TestComponent {
  testModel: TestModel;
  ・
  ・
  ・
}

まぁこれくらいの処理ならば特に気にせずに書けちゃうのであまりピンと来ないかもしれませんが、以下のように書いたほうがコード的には見やすくなります。

@Component({
  selector: 'ng-if-let',
  template: `
    <div>{{ getNameWithTitle() }}</div>
 `
})
class TestComponent {
  testModel: TestModel;
  ・
  ・
  ・
  /**
  * 敬称を付加して名前を返す
  */
  getNameWithTitle() {
      const title: string = testModel.isMale ? 'くん' : 'さん';
      return this.testModel.name + title;
  }
}

書く行数が増えてるのになんで!?と思われるかもしれませんが、ロジックがhtmlとコンポーネントに分散してしまうと保守性という観点から、見なければいけないファイルが増えるのはよろしくないのでそうした方が無難です。
とはいえAngularでは、コンポーネントという概念で切れているので、部分的に改修を入れようと思ったときに特定するのはそこまで難しくはないのですが^^;)((正しくコンポーネントを分割できていた場合です。))

Tips2 :ある条件によって出力を切り替えたい(ngIf/else)の使い方

Angular 4以降で、(v4)リアクティブプログラミングをサポートするための変更が進み始め、それまでは実現できなかったことができるようになりました。そのうちの一つに、タイトルにあるようなngIf/else が使用できるようになりました。

Angular4以前は、ある条件によって表示を切り替えたい場合は、いずれか2つのパターンで実装していたことが多かったと思います。

パターン1 ngIfを羅列

# 条件その1が真のときにpタグを表示
<p *ngIf=""(条件その1) >条件その1が真のとき表示される </p>

# 条件その1が偽のときにpタグを表示
<p *ngIf="!(条件その1)" >条件その1が偽のとき表示される </p>
・
・
・

パターン2 ngSwitchを使う

<ng-container [ngSwitch]="(条件その1)">
  # 条件その1が真のときにpタグを表示
  <p *ngSwitchDefault>条件その1が真のとき表示される </p>
  # 条件その1が偽のときにpタグを表示
  <p *ngSwitchCase="false">条件その1が偽のとき表示される </p>
</ng-container>
・
・
・

ngIfを羅列するパターンだと、そもそもほぼ同じ条件をチェックしているにもかかわらず、愚直に書いているのでコードが汚くなってしまうし、評価が2度走るためパフォーマンス的にもあまりうれしくはないです。
一方、ngSwitchを使った場合は、コードの視認性という観点ではngSwitchブロックであるということと、条件自体は出し分けしたいタグの親に当たるタグに書くので許容。しかし、本来のngSwitchはT/Fのためというよりかは複数の条件への対応の場合により力を発揮するものなので、この場合には少し役不足な感じが否めません。

ここで登場するのが、紹介したい ngIf/else です!
上記の例をngIf/elseで書いてみたいと思います。

パターン3 ngIf/elseを使う

# 条件その1が真のときにpタグを表示
<p *ngIf="(条件その1);else elseContent" >条件その1が真のとき表示される </p>

# 条件その1が偽のときにpタグを表示
<ng-template #elseContent >
  <p>条件その1が偽のとき表示される </p>
</ng-template>
・
・
・

すっきり!?個人的には、ngIfはpタグに直接書けて、elseのほうはng-template使わないとイケない辺りがしっくりこないです・・・笑
てことで、ここからは個人的にもう少しスッキリした書き方のパターンを紹介します。

パターン4 ngIf/then/elseを使う

はい、突然出てきました。then。これはngIfの時のテンプレートを指定するときに使います。要するに、elseの時だけではなく、ifの時もtemplate使おうぜってことです。

# 条件定義のためだけに使われる
<ng-template *ngIf="(条件その1);then showContent; else elseContent" >ここに書いたものは無視される <ng-template>

# 条件その1が真のときにpタグを表示
<ng-template #showContent >
  <p>条件その1が真のとき表示される </p>
</ng-template>

# 条件その1が偽のときにpタグを表示
<ng-template #elseContent >
  <p>条件その1が偽のとき表示される </p>
</ng-template>
・
・
・

うむ、個人的には満足です。ngIfを記述しているタグ、本家のサンプルやそれを見習って書いているtech系のブログではdivタグを使ってますが、実は何でも良いです(多分)。むしろdivタグ使ったところで、内部的にはそのタグ自体は意味を成さないので(出力されない)、あえてこういう書き方をしてみました。

いかようにも書ける分、チーム開発するときは何かしらのコーディングルールを設けると、ひっちゃかめっちゃかにならずに済みますよね。

まとめ

いかがでしたか?
SEROKUの開発時に利用したAngularに関するTipsを書きましたが、かゆいところに届くような内容にはならず、無難なものに落ちつてしまった感がありますが、少しでも参考になると幸いです^^;

次回以降もこれにめげず書いていこうと思いので乞うご期待?