3
3

Angularを使ってみよう

Posted at

:point_up: はじめに

フロントのみをチュートリアルを参考にサクッと落とし込みます。
なぜAngularなのか?となりますが、癖があるので慣れると作れちゃいます。
ただ保守性が如何せん大変だということでReactのシェアが多いのだと思います。

以下の記事はよく調べられており、Angular経験者なら頷く内容でした。
それでも Angular を選ぶ理由

3年ほどまえにAngulerでag-gridを採用したことがあり、久しぶりにAngularを触ってみようと思った次第です。

:thinking: 構成

Angular(^18.1.4) + TypeScript(~5.5.2) + Tailwindcss(^3.4.11)
Angularとは?
AngularでTailwind CSSをインストールする

:point_right: 1.Angular CLIをインストールする

参考

$ npm install @angular/cli --no-save 
$ ng version 

image.png

:point_right: 2.プロジェクト作成

私はSCSSを採用しています(お好みでよき)

$ ng new angular-app --directory=./

image.png

:point_right: 3.Angular Material インストール

参考
選択肢が分からなければデフォルトで選択すればよいです
image.png

:point_right: 4.tailwindcss インストール

ここまでインストールしたら下地はできました
参考

$ npm install -D tailwindcss postcss autoprefixer 
$ npx tailwindcss init 

参考にあるテンプレートパスを構成してください
image.png

参考にある Tailwind ディレクティブを CSS に追加してください
image.png

:point_right: コンポーネントを追加する

よくあるヘッダ、ボディ、フッタのイメージで用意します

$ ng generate component header 
$ ng generate component grid 
$ ng generate component footer 

指定したフォルダ配下にファイルが作成されます
image.png

:point_right: ヘッダ・フッタを定義する

テンプレート集があるのでイメージにあるものをチョイスする。
私はTailblocksからヘッダとフッタをチョイスしました。

:point_right: ボディを定義する(テーブルを配置します)

CdkTable
grid.component.html に以下を配置して grid.component.ts から Map を渡します。

<table cdk-table [dataSource]="dataSource" class="table-body">
  <ng-container cdkColumnDef="position">
    <th cdk-header-cell *cdkHeaderCellDef class="table-th">No</th>
    <td cdk-cell *cdkCellDef="let element" class="table-td"> {{element.position}} </td>
  </ng-container>
  <ng-container cdkColumnDef="name">
    <th cdk-header-cell *cdkHeaderCellDef class="table-th">名称</th>
    <td cdk-cell *cdkCellDef="let element" class="table-td underline underline-offset-4"> {{element.name}} </td>
  </ng-container>
  <ng-container cdkColumnDef="address">
    <th cdk-header-cell *cdkHeaderCellDef class="table-th">住所</th>
    <td cdk-cell *cdkCellDef="let element" class="table-td"> {{element.address}} </td>
  </ng-container>
  <tr cdk-header-row *cdkHeaderRowDef="displayedColumns"></tr>
  <tr cdk-row *cdkRowDef="let row; columns: displayedColumns;" (click)="onClickRow(row)" [style.background-color]="rowBackColor(row)"></tr>
</table>

Paginator
grid.component.html に以下を配置して

<mat-paginator #paginator
 class="demo-paginator"
 (page)="handlePageEvent($event)"
 [length]="length"
 [pageSize]="pageSize"
 [disabled]="disabled"
 [showFirstLastButtons]="showFirstLastButtons"
 [pageSizeOptions]="showPageSizeOptions ? pageSizeOptions : []"
 [hidePageSize]="hidePageSize"
 [pageIndex]="pageIndex"
 aria-label="Select page">
</mat-paginator>

grid.component.ts からページ情報を渡す

import { DataSource } from '@angular/cdk/collections';
import { BehaviorSubject, Observable } from 'rxjs';

(省略)

export interface MapsData {
  position: number;
  name: string;
  address: string;
}

(省略)

  length = 50;
  pageSize = 10;
  pageIndex = 0;
  pageSizeOptions = [5, 10, 25];

  hidePageSize = false;
  showPageSizeOptions = true;
  showFirstLastButtons = true;
  disabled = false;

  pageEvent: PageEvent | null = null;

  displayedColumns: string[] = ['position', 'name', 'address'];
  exampleDatabase = new ExampleDatabase(this.pageSize, this.pageIndex);
  dataSource: ExampleDataSource = new ExampleDataSource(this.exampleDatabase);

  ngOnInit() {
    this.dataSource = new ExampleDataSource(this.exampleDatabase);
  }
  handlePageEvent(e: PageEvent) {
    this.pageEvent = e;
    this.length = e.length;
    this.pageSize = e.pageSize;
    this.pageIndex = e.pageIndex;
    this.exampleDatabase = new ExampleDatabase(this.pageSize, this.pageIndex);
    this.dataSource = new ExampleDataSource(this.exampleDatabase);
  }
  setPageSizeOptions(setPageSizeOptionsInput: string) {
    if (setPageSizeOptionsInput) {
      this.pageSizeOptions = setPageSizeOptionsInput.split(',').map(str => +str);
    }
  }

(省略)

// Create Data
export class ExampleDatabase {
  dataChange: BehaviorSubject<MapsData[]> = new BehaviorSubject<MapsData[]>([]);
  get data(): MapsData[] { return this.dataChange.value; }

  constructor(pageSize: any, pageIndex: any) {
    for (let i = (pageIndex * 10); i < (pageSize * (pageIndex + 1)); i++) { this.addMaps(i + 1); }
  }

  addMaps(dataIndex: any) {
    const copiedData = this.data.slice();
    copiedData.push(this.createNewMaps(dataIndex));
    this.dataChange.next(copiedData);
  }

  private createNewMaps(dataIndex: any) {
    return {
      position: dataIndex,
      name: '東京駅',
      address: '東京都千代田区丸'
    };
  }
}

export class ExampleDataSource extends DataSource<any> {
  constructor(private _exampleDatabase: ExampleDatabase) {
    super();
  }
  connect(): Observable<MapsData[]> {
    return this._exampleDatabase.dataChange;
  }
  disconnect() {}
}

Row Event
行選択時のイベントは以下のイメージです。

import { PageEvent, MatPaginatorModule } from '@angular/material/paginator';

(省略)

  private selectItem: any;
  onClickRow(item: any) {
    this.selectItem = item;
  }
  rowBackColor(item: any): string {
    if (this.selectItem === undefined) return 'white';
    if (this.selectItem.position === item.position) return 'lightcyan';
    return 'white';
  }

:point_right: 動作確認

app.component.html にヘッダ、ボディ、フッタのコンポーネントを追加する
image.png

$ ng serve --open

デザインが表示されれば完成です:clap:
image.png

Angularを試す際の参考になればと思います:writing_hand:

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