はじめに
フロントのみをチュートリアルを参考にサクッと落とし込みます。
なぜAngularなのか?となりますが、癖があるので慣れると作れちゃいます。
ただ保守性が如何せん大変だということでReactのシェアが多いのだと思います。
以下の記事はよく調べられており、Angular経験者なら頷く内容でした。
それでも Angular を選ぶ理由
3年ほどまえにAngulerでag-gridを採用したことがあり、久しぶりにAngularを触ってみようと思った次第です。
構成
Angular(^18.1.4) + TypeScript(~5.5.2) + Tailwindcss(^3.4.11)
Angularとは?
AngularでTailwind CSSをインストールする
1.Angular CLIをインストールする
$ npm install @angular/cli --no-save
$ ng version
2.プロジェクト作成
私はSCSSを採用しています(お好みでよき)
$ ng new angular-app --directory=./
3.Angular Material インストール
参考
選択肢が分からなければデフォルトで選択すればよいです
4.tailwindcss インストール
ここまでインストールしたら下地はできました
参考
$ npm install -D tailwindcss postcss autoprefixer
$ npx tailwindcss init
参考にある Tailwind ディレクティブを CSS に追加してください
コンポーネントを追加する
よくあるヘッダ、ボディ、フッタのイメージで用意します
$ ng generate component header
$ ng generate component grid
$ ng generate component footer
ヘッダ・フッタを定義する
テンプレート集があるのでイメージにあるものをチョイスする。
私はTailblocksからヘッダとフッタをチョイスしました。
ボディを定義する(テーブルを配置します)
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';
}
動作確認
app.component.html にヘッダ、ボディ、フッタのコンポーネントを追加する
$ ng serve --open
Angularを試す際の参考になればと思います