0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Angular】Angularって何だろう(基本な操作(*ngIf・[hidden]・*ngFor)編)

0
Posted at

1.はじめに

今回は、Angular第二弾で基本的な操作のうちHTML部分に記述する内容をいくつかまとめていきます。
第一弾はこちら

今回もVueでご紹介した時と同じ作りとしているため、是非こちらと比較してみると分かりやすいと思います。
【Vue.js】Vue.jsって何だろう(基本な操作(v-if/v-else-if/v-else・v-show・v-for)編)
バージョンによって書き方の違いはありますが、Anuglar5での書き方でご紹介します。


2. 基本的な書き方

概要

Angular では、コンポーネントは以下のように構成されます。
htmlファイル・tsファイル・cssファイルの3ファイル構成になります。

app.component.html

// 今回はここに書くことをまとめていきます。
<h1 [ngClass]="titleClass">{{ value }}</h1>
<button (click)="pushButton()">
  ボタンを押してください
</button>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root', // HTMLタグの名前
  templateUrl: './app.component.html', // HTMLテンプレート
  styleUrls: ['./app.component.css'] // スタイルシート
})

export class AppComponent {
  value: string = '';
  titleClass: string = 'title';

  // ボタンをクリックしたときの処理
  pushButton() {
    this.value = 'ボタンが押されました!';
  }
}

app.component.css

.title {
  color: red;
}

3.基本的な操作

① *ngIf

条件に応じてHTMLの表示・非表示を切り替えることが出来るコードです。

<基本的な書き方>

*ngIfは=""内の条件が「true」のときだけ表示するコードです。

<p *ngIf="condition">
  この文章は条件がtrueのときだけ表示されます
</p>

AngularにはVueのような v-else-if はありません。

代わりに ng-template を利用して条件分岐を行います。

<div *ngIf="condition1; else secondCheck">
  この文章は条件①がtrueのときに表示されます
</div>

<ng-template #secondCheck>
  <div *ngIf="condition2; else finalTemplate">
    この文章は条件①がfalseで条件②がtrueのときに表示されます
  </div>
</ng-template>

<ng-template #finalTemplate>
  <div>
    この文章は条件①・条件②どちらもfalseのときに表示されます
  </div>
</ng-template>

:ok:

<div *ngIf="ok; else closeCheck">
  はい
</div>

<ng-template #closeCheck>
  <div *ngIf="close; else ngTemplateNo">
    惜しい
  </div>
</ng-template>

<ng-template #ngTemplateNo>
  <div>いいえ</div>
</ng-template>

:ng:

<div *ngIf="ok">
  はい
</div>

<div *ngIf="close">
  惜しい
</div>

<div>
  いいえ
</div>

※この書き方だと条件分岐ではなく、それぞれ独立した判定になってしまいます。

<テストコード>

sample.component.html

<!-- app.component.html -->

<div *ngIf="isAdmin; else userCheck">
  管理者としてログインしています
</div>

<ng-template #userCheck>
  <div *ngIf="isLoggedIn; else logoutTemplate">
    一般ユーザーとしてログインしています
  </div>
</ng-template>

<ng-template #logoutTemplate>
  <div>ログインしていません</div>
</ng-template>

<div>
  <button (click)="loginAsUser()">
    ユーザーとしてログイン
  </button>
</div>

<br>

<div>
  <button (click)="loginAsAdmin()">
    管理者としてログイン
  </button>
</div>

<br>

<div>
  <button (click)="logout()">
    ログアウト
  </button>
</div>

sample.component.ts

// ここは次回以降説明します

export class AppComponent {

  isLoggedIn = false;
  isAdmin = false;

  loginAsUser() {
    this.isLoggedIn = true;
    this.isAdmin = false;
  }

  loginAsAdmin() {
    this.isLoggedIn = true;
    this.isAdmin = true;
  }

  logout() {
    this.isLoggedIn = false;
    this.isAdmin = false;
  }
}

最初に表示したときにはisLoggedInもisAdminもfalseのため、「ログインしていません」が表示されます。
image.png

次に「ユーザーとしてログイン」ボタンを押すと、isLoggedInのみtrueになるため、「一般ユーザーとしてログインしています」が表示されます。

image.png

次に「管理者としてログイン」ボタンを押すとisAdminもtrueになるため、「管理者としてログインしています」が表示されます。

image.png

最後に「ログアウト」ボタンを押すとisAdminもfalseになるため、「ログインしていません」が表示されます。

image.png

② [hidden]

[hidden]はVueのv-showと同様HTMLの要素を表示・非表示にするためのコードです。

<基本的な書き方>

<p [hidden]="!condition">
  この文章は条件がtrueのときだけ表示されます
</p>

<*ngIfとの違い>

*ngIfとの違いは要素を非表示に切り替える際に要素が存在するかしないかの違いになります。

*ngIf : 要素を 実際に出したり消したり する

[hidden] : 要素はずっとあるがCSSで 見えなくするだけ

[hidden]の場合要素を見えなくするだけのため、表示の切り替えが多い場合はこちらの方が向いています。

少しわかりづらいかもしれないので、演劇に例えて説明してみます。

🧍‍♂️ *ngIf:必要なときだけ「人を呼ぶ」

たとえば舞台の演劇で、あるシーンになったら「役者Aさん登場!」と舞台袖から呼んできます。

シーンが終わったらまた退場して、いなくなります。

  • 登場するとき → 舞台に出てくる
  • いないとき → 本当にいない

これが *ngIf の動きです。

見えないときは完全に存在しません。


👻 [hidden]:カーテンで「隠すだけ」

今度は役者さんはずっと舞台上にいます。

でも「見せないとき」はカーテンやライトで見えなくしてるだけです。

  • 見せるとき → カーテンを開ける
  • 見せないとき → カーテンを閉める

これが [hidden] の動きです。

見えなくても実はずっとそこにいます。


実際のコードで見ていきましょう。

<テストコード>

sample.component.html

<h2>*ngIfと[hidden] 比較</h2>

<div>
  <button (click)="visible = !visible">
    表示切り替え(現在:{{ visible ? '表示中' : '非表示' }})
  </button>
</div>

<br>

<div *ngIf="visible">
  <strong>これは *ngIf で表示されています</strong>
</div>

<br>

<div [hidden]="!visible">
  <strong>これは [hidden] で表示されています</strong>
</div>

sample.component.ts

export class AppComponent {

  visible = true;

}

これを実行し、WindowsだとCtrl+Shift+Iキーを同時押ししてデベロッパーツールを開き、Elementsから要素の確認をすると違いがよく分かります。

条件がtrueの場合はどちらも要素は表示されます。
image.png

表示切り替えボタンを押し、非表示にすると、

*ngIfで囲んだところは要素が消えていますが、[hidden]で囲んだところは要素自体は残ったままとなります。
image.png


③ *ngFor

*ngForはリストを繰り返し表示するコードです。

<説明>

下のリストを箇条書きで表示したいと考えています。

箇条書きのリストをHTMLで書こうとしたとき、下記のように表示します。

<ul>
  <li>りんご</li>
  <li>みかん</li>
  <li>バナナ</li>
</ul>

ただし、箇条書きに表示したい項目数が増えたり変更があった時にいちいち修正するのは面倒です・・・

そこで、*ngForで表示することで、配列に要素を追加しておけば、Angularが配列を読み取り、リストの中身の個数分、自動で <li> を繰り返し出力してくれるようになります。

fruits = ['りんご', 'みかん', 'バナナ'];
<ul>
  <li *ngFor="let fruit of fruits">
    {{ fruit }}
  </li>
</ul>
  • りんご
  • みかん
  • バナナ

また、下記のように書くと、

<ul>
  <div *ngFor="let fruit of fruits; let index = index">
    {{ index + 1 }}. {{ fruit }}
  </div>
</ul>

その値が何番目であるかも取得・表示することが出来ます。
image.png

<基本的な書き方>

<p *ngFor="let item of items"></p>
<p *ngFor="let item of items; let index = index"></p>

<テストコード>

sample.component.html

<h2>好きな果物リスト</h2>

<ul>
  <li *ngFor="let fruit of fruits">
    {{ fruit }}
  </li>
</ul>

<ul>
  <div *ngFor="let fruit of fruits; let index = index">
    {{ index + 1 }}. {{ fruit }}
  </div>
</ul>

sample.component.ts

export class AppComponent {

  fruits = ['りんご', 'みかん', 'バナナ'];

}

fruits = ['りんご', 'みかん', 'バナナ'] の最後にももを追加して、

fruits = ['りんご', 'みかん', 'バナナ', 'もも'];

のようにすると、画面にももが追加されます。

  • りんご
  • みかん
  • バナナ
  • もも

image.png


また、Vueの :key に近い役割として、Angularには trackBy があります。

sample.component.html

<h3>trackByなし</h3>

<div *ngFor="let user of users">
  {{ user.name }}
  <input type="text">
</div>

<br>

<h3>trackByあり</h3>

<div *ngFor="let user of users; trackBy: trackById">
  {{ user.name }}
  <input type="text">
</div>

<br>

<button (click)="reload()">
  データ再取得
</button>

sample.component.ts

export class AppComponent {

  users = [
    { id: 1, name: '田中' },
    { id: 2, name: '佐藤' },
    { id: 3, name: '鈴木' }
  ];

  reload() {
    // API再取得を想定
    this.users = [
      { id: 1, name: '田中' },
      { id: 2, name: '佐藤' },
      { id: 3, name: '鈴木' }
    ];
  }

  trackById(index: number, user: any): number {
    return user.id;
  }
}

上記のコードを書いたうえで、それぞれの入力欄に何かしら入力後、「データ再取得」ボタンを押した場合に、trackByを指定していない方では入力した値が消えてしまいます。

image.png

それは、Angularがデータを再取得した際に、

[
  { id: 1, name: '田中' },
  { id: 2, name: '佐藤' },
  { id: 3, name: '鈴木' }
]

[
  { id: 1, name: '田中' },
  { id: 2, name: '佐藤' },
  { id: 3, name: '鈴木' }
]

を別のオブジェクトとして扱うためです。

人間から見ると同じデータに見えますが、Angularから見ると新しく作られたデータであるため、

「前回表示していた要素ではなく、新しい要素として表示しよう」

と判断します。

その結果、入力欄を含めた要素が作り直され、入力していた値が消えてしまいます。

一方で、trackByを指定すると、

trackById(index: number, user: any): number {
  return user.id;
}

のように、

「idが同じなら同じデータですよ」

とAngularへ伝えることができます。

するとAngularは、

  • id=1 → 前回の田中さん
  • id=2 → 前回の佐藤さん
  • id=3 → 前回の鈴木さん

と認識できるため、既存の要素を再利用するようになります。
そのため、不要な要素の作り直しを防ぐことができます。
ですので基本的にtrackByは指定しておくのが無難です。

4.さいごに

今回はAngular5のHTML側でよく使用する

  • *ngIf
  • [hidden]
  • *ngFor

を紹介しました。

次回はTypeScript側で記述する内容についてまとめていきたいと思います。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?