|||||||||||||||||||||

なんぶ電子

- 更新: 

Angularのif,for,イベント,クラスバインディング

Angularのチュートリアルアプリ

Vue.jsと比較をするために、Angularのチュートリアルに従って、構文を勉強しています。

前回はAngularのコンポーネントの作成から、インターフェース、双方向データバインディングまでを学びました。

今回は*ngFor、*ngIf、イベント設定、クラスバインディング(条件文によるclassの付与)を学びます。

サンプルデータの作成

データが1件だけだと、全体像をつかみづらいのでもう少し多くのサンプルーデータを作ります。サンプルデータはsrc¥app¥フォルダにmock-heroes.tsという名前で作成します。

ちなみにモック(mock)とは偽物という意味でAngularの用語ではありません。日本でも、商品としては機能しない外観だけの商品見本を「モック」と呼んだりします。

HEROESという定数を作って、そこにHeroインターフェースの配列(Hero[])を定義して、そのあとのデータで初期化します。

同じ階層にある、hero.tsのHeroインターフェースを利用するのでインポートしてから定義します。

ここでは定数値であるHEROESは変数と区別するためにすべて大文字で記述しています。

mock-heroes.ts

import { Hero } from './hero';

export const HEROES: Hero[] = [
  { id: 11, name: 'Dr Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];

*ngFor

前回の[(ngModel)]もそうでしたが、HTMLファイルに記述するAngularの命令文をディレクティブと呼びます。

*ngForもその一つで、ディレクティブを記述した要素をfor文のように繰り返します。

このディレクティブを使って、前回登場したheroes.component.htmlの中身を書き換えるのですが、そのまえにheroes.component.tsにHEROES定数を定義しなくてはいけません。

heroes.component.ts

import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HEROES } from '../mock-heroes';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
  heroes: HEROES;
  
  constructor() { }

  ngOnInit(): void {
  }

}

heroes.component.htmlを次のようにします。liに対して*ngForを利用することで繰り返します。"let h of heroes"とすることで、heroesの中にある要素がなくなるまで繰り返します。取り出された値はhに入ります。

heroes.component.html

<h2>Heroes</h2>
<ul class="heroes">
  <li *ngFor="let h of heroes">
    <span class="badge">{{h.id}}</span>{{h.name}}
  </li>
</ul>

コンポーネントのCSS

ここまでほとんど触れてきませんでしたが、コンポーネントのcss(heroes.component.css)は、対象のコンポーネントだけに有効です。CSSファイルの指定は、.tsファイルの@Component内のstyleUrls:として記述すると以前書きましたが、styleUrlsをstylesとすることで中の配列に直接CSSを書くこともできます。

heroes.component.ts

import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HEROES } from '../mock-heroes';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  //styleUrls: ['./heroes.component.css']
  styles: ['h1,h2 {color: yellow;}','li {color: red;}']
})
export class HeroesComponent implements OnInit {
  heroes: Hero[] = HEROES;
  
  constructor() { }

  ngOnInit(): void {
  }

}

上記のようにした時「Tour of Heroes」の文字はh1の要素ですが、コンポーネントの外なので元の色のままです。

Angularのチュートリアルアプリ

*ngIfとイベント

リストを表示することができたので、今度はそれぞれにクリックイベントを設定してみます。

heroのそれぞれの行をクリックしたとき、その詳細をリストの下段に表示するようにします。

その際に利用できるのが*ngIfです。*ngIfは設定された値が真の時のみ出力をし、そうでない場合はDOMから除去してくれるものです。

liクリックで詳細表示用の変数に値をセットする仕組にし、その値が存在する時は*ngIfで表示させるようにします。

クリックイベントを拾うには(click)="関数名(パラメタ)"と記述します。この関数はheroes.component.tsに記述します。

さらにheroes.component.tsには詳細表示用の変数として、selectedHeroを定義します。

コード全体は次のように変わります。

heroes.component.html

<h2>Heroes</h2>
<ul class="heroes">
  <li *ngFor="let h of heroes" (click)="onSelect(h)" >
    <span class="badge">{{h.id}}</span>{{h.name}}
  </li>
</ul>
<div *ngIf="selectedHero">
  <h2>{{selectedHero.name | uppercase}} Details</h2>
  <div><span>id: </span>{{selectedHero.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="selectedHero.name" placeholder="name"/>
    </label>
  </div>
</div>

heroes.component.ts

import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HEROES } from '../mock-heroes';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
  heroes: Hero[] = HEROES;
  selectedHero: Hero;
  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }
  constructor() { }

  ngOnInit(): void {
  }

}

動的なクラス付与

ある条件により、HTML要素に対してクラスを付与したり外したりする機能をクラスバインディングと呼びます。

コンポーネントのHTMLの要素の属性として、[class.付与したいクラス]="条件" と記述することで実現できます。

ここでは、li要素に対して、selectedというクラスを付与したり外すことで選択状況を可視化させます。

heroes.component.html

<h2>Heroes</h2>
<ul class="heroes">
  <li *ngFor="let h of heroes" (click)="onSelect(h)" [class.selected]="h===selectedHero" >
    <span class="badge">{{h.id}}</span>{{h.name}}
  </li>
</ul>
<div *ngIf="selectedHero">
  <h2>{{selectedHero.name | uppercase}} Details</h2>
  <div><span>id: </span>{{selectedHero.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="selectedHero.name" placeholder="name"/>
    </label>
  </div>
</div>

この時のCSSは次のようになっています。

heroes.component.css

.heroes {
  margin: 0 0 2em 0;
  list-style-type: none;
  padding: 0;
  width: 15em;
}
.heroes li {
  cursor: pointer;
  position: relative;
  left: 0;
  background-color: #EEE;
  margin: .5em;
  padding: .3em 0;
  height: 1.6em;
  border-radius: 4px;
}
.heroes li:hover {
  color: #607D8B;
  background-color: #DDD;
  left: .1em;
}
.heroes li.selected {
  background-color: #CFD8DC;
  color: white;
}
.heroes li.selected:hover {
  background-color: #BBD8DC;
  color: white;
}
.heroes .badge {
  display: inline-block;
  font-size: small;
  color: white;
  padding: 0.8em 0.7em 0 0.7em;
  background-color:#405061;
  line-height: 1em;
  position: relative;
  left: -1px;
  top: -4px;
  height: 1.8em;
  margin-right: .8em;
  border-radius: 4px 0 0 4px;
}

筆者紹介


自分の写真
がーふぁ、とか、ふぃんてっく、とか世の中すっかりハイテクになってしまいました。プログラムのコーディングに触れることもある筆者ですが、自分の作業は硯と筆で文字をかいているみたいな古臭いものだと思っています。 今やこんな風にブログを書くことすらAIにとって代わられそうなほど技術は進んでいます。 生活やビジネスでPCを活用しようとするとき、そんな第一線の技術と比べてしまうとやる気が失せてしまいがちですが、おいしいお惣菜をネットで注文できる時代でも、手作りの味はすたれていません。 提示されたもの(アプリ)に自分を合わせるのでなく、自分の活動にあったアプリを作る。それがPC活用の基本なんじゃなかと思います。 そんな意見に同調していただける方向けにLinuxのDebianOSをはじめとした基本無料のアプリの使い方を紹介できたらなと考えています。

広告