d2-04-search-delete-page について
CRUD機能の選択に応じて操作を切り替える検索リストページを作るためのAngular開発スキルです。signalによる状態管理、データ取得、ルーティング、削除確認を扱います。
主な機能
- 01機能に応じた追加・削除ボタン
- 02signalによるリスト状態管理
- 03エンティティレコードの取得と表示
- 04編集・戻る・新規作成の画面遷移
- 05削除確認とリスト更新
活用シーン
- 01編集機能付きのエンティティ検索ページ作成
- 02プロジェクトで無効な操作の非表示
- 03削除確認後のリスト更新実装
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ softinter-chiangrai/ up-ai-skill-training --skill d2-04-search-delete-pageインストール後、Claude Code で/d2-04-search-delete-pageを入力して読み込まれたか確認します。
詳細
2 日目 · ステップ 4 — 機能に基づいた機能を備えた検索ページ
**注記:**このスキルは、d2-03-main-menu で選択した機能に応じて変わります。
searchが選択されている場合:編集ボタン付きの一覧を表示しますdeleteも選択されている場合:インライン確認ポップアップ付きの削除ボタンを追加しますsearchのみの場合:削除ボタンは表示されません
up-app/src/app/pages/<entity>-search/<entity>-search.component.ts(スタンドアロンコンポーネント):
signal<Entity[]>([])を使用して項目一覧を保存します。データを取得したら、.set()を呼び出して更新します。- 初期化時に
<entity>Service.getAll()を呼び出し、this.items.set(data)でシグナルを更新します。 create機能が有効な場合:追加ボタンを含むヘッダーバーを表示し、router.navigate(['/<entity>/new'])に移動します。- ホーム/メニューに移動する 戻る ボタンを追加し、
router.navigate(['/'])に移動します。 - 行ごと(
@forとtrack item.idを使用):- 編集ボタン →
router.navigate(['/<entity>', item.id, 'edit'])(常に含めます) - 削除ボタン(
delete機能が選択されている場合のみ)→ 確認ポップアップを表示します。確認されたら、<entity>Service.delete(id)を呼び出し、成功時に.set()でシグナルを更新します。
- 編集ボタン →
**ルート:**すでに d2-03-main-menu で定義済みです(完全な app.routes.ts)。このスキルでは、ナビゲーションにこれらのルートを使用します。
コンポーネントの TypeScript:
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { CommonModule } from '@angular/common';
import { signal } from '@angular/core';
import { <Entity>Service, <Entity> } from '../../services/<entity>.service';
@Component({
selector: 'app-<entity>-search',
standalone: true,
imports: [CommonModule],
templateUrl: './<entity>-search.component.html',
styleUrls: ['./<entity>-search.component.css']
})
export class <Entity>SearchComponent implements OnInit {
items = signal<<Entity>[]>([]);
// Capability flags (set based on selections from d2-03)
hasCreateCapability = true; // Set to false if 'create' not selected
hasDeleteCapability = true; // Set to false if 'delete' not selected
constructor(
private router: Router,
private <entity>Service: <Entity>Service
) {}
ngOnInit() {
this.<entity>Service.getAll().subscribe(data => {
this.items.set(data);
});
}
onBack() {
this.router.navigate(['/']); // Navigate back to menu/home
}
onAdd() {
this.router.navigate([`/<entity>/new`]);
}
onEdit(id: number | undefined) {
if (id) {
this.router.navigate(['/<entity>', id, 'edit']);
}
}
onDelete(item: <Entity>) {
if (confirm(`Delete "<property name from item>"?`)) {
if (item.id) {
this.<entity>Service.delete(item.id).subscribe(() => {
const current = this.items();
this.items.set(current.filter(i => i.id !== item.id));
});
}
}
}
}
テンプレート(柔軟な列、戻るボタン、機能に基づいた削除機能を含む):
<div class="min-h-screen bg-gray-50">
<div class="max-w-4xl mx-auto p-6">
<div class="flex justify-between items-center mb-6">
<div class="flex items-center gap-4">
<button
(click)="onBack()"
class="bg-gray-500 hover:bg-gray-600 text-white font-semibold px-4 py-2 rounded-lg transition"
>
← Back
</button>
<h1 class="text-4xl font-bold text-gray-900"><Entity> List</h1>
</div>
@if (hasCreateCapability) {
<button
(click)="onAdd()"
class="bg-green-500 hover:bg-green-600 text-white font-semibold px-6 py-3 rounded-lg transition shadow-md"
>
+ Add New
</button>
}
</div>
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<div class="overflow-x-auto">
<table class="min-w-full">
<thead>
<tr class="bg-gray-100 border-b border-gray-200">
<th class="px-6 py-3 text-left font-semibold text-gray-700">Code</th>
<th class="px-6 py-3 text-left font-semibold text-gray-700">Name</th>
<th class="px-6 py-3 text-left font-semibold text-gray-700">Address</th>
<th class="px-6 py-3 text-left font-semibold text-gray-700">Phone</th>
<th class="px-6 py-3 text-center font-semibold text-gray-700">Actions</th>
</tr>
</thead>
<tbody>
@for (item of items(); track item.id) {
<tr class="border-b border-gray-100 hover:bg-gray-50 transition">
<td class="px-6 py-3 text-gray-900 font-medium">{{ item.empCode }}</td>
<td class="px-6 py-3 text-gray-900">{{ item.empName }}</td>
<td class="px-6 py-3 text-gray-700">{{ item.address || "-" }}</td>
<td class="px-6 py-3 text-gray-700">{{ item.phoneNo || "-" }}</td>
<td class="px-6 py-3 text-center">
<button
(click)="onEdit(item.id)"
class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg mr-2 transition text-sm font-semibold"
>
Edit
</button>
@if (hasDeleteCapability) {
<button
(click)="onDelete(item)"
class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg transition text-sm font-semibold"
>
Delete
</button>
}
</td>
</tr>
}
</tbody>
</table>
</div>
@if (items().length === 0) {
<div class="text-center py-8 text-gray-600">
<p class="text-lg">No <entity> found.
@if (hasCreateCapability) {
<a href="javascript:" (click)="onAdd()" class="text-blue-500 hover:underline">Create one</a>.
} @else {
Contact your administrator to create records.
}
</p>
</div>
}
</div>
</div>
</div>
列のカスタマイズ:
empCode、empName、address、phoneNoを、エンティティの実際のプロパティ名に置き換えます- テーブルのヘッダー
<th>とデータ<td>の列を追加/削除して、エンティティの構成に合わせます - 空または null のオプション項目には
|| "-"を使用してダッシュを表示します
機能フラグ:
- d2-03 での選択内容に基づいて
hasCreateCapabilityとhasDeleteCapabilityを設定します falseの場合、追加ボタンと削除ボタンは表示されません- CRUD 要件に応じてボタンを動的に調整します
コメント
Markdown 対応