コース内容
トピック0:イントロダクション
なぜAIを学ぶ必要があるのか?全社員がAIを使うことを常識化することで、売上や給与の向上がどのくらい見込めるか?を説明します。
0/61
(※準備中)トピック2:効果的な質問の仕方とは?〜AIを活かすプロンプトの作り方〜
AIを活用する上で最も重要なのがプロンプトの作り方です。プロンプト次第でAIは嘘をつく(ハルシネーション)ことも、思い通りの出力をしないことも多々あります。現在AIを上手に仕事に活用している人たちは、ずばりプロンプトの作り方が上手な人たちです。AIを活かすプロンプトの作り方をこのトピックで徹底的に学びましょう。
東光ブロズAI活用レクチャー

 

L43:JavaScript基礎(DOM・イベント・状態管理)+UI状態(loading/error/empty)最小実装(TRAINING ONLY/流用禁止)

【重要:本レッスンは訓練専用】

  • このレッスンで作る「サンプルHTML/CSS/JS」「状態遷移の実装」「例外処理」「A11y対応(フォーカス/キーボード)」「デバッグ手順」等は訓練専用です。通常業務でそのまま使用することは禁止します(コピペ流用禁止)。
  • 実サイト更新・実公開・実リポジトリ反映は禁止:本番環境/実CMS/実タグ/実URLには触れません(ローカルファイル・ダミーのみ)。
  • 実データ・個人情報・未公開情報は禁止(実案件名、実ページID、実在のSKU/取引先/条件などは書かない)。
  • 本番で必要になった場合は、訓練成果物を流用せず、情報を取り直し、別途レビュー/承認を経て新規作成してください。

本レッスンでは、JavaScriptを「コードを書く」よりも先に、UI要件(状態/例外/A11y)を“実装に落ちる粒度”にする練習をします。
L42で作ったUI要件(State表・例外表・A11y要件)を前提に、状態管理(state)→描画(render)→イベント(event)→例外(error)の最小構造を体験します。

このページの使い方

1レッスン=1LP(1ページ)です。上から順に当日の時間割に沿って進めてください。
各項目の冒頭に EC事業部文房具カフェ事業部・準備室 の実施時間を併記しています。
※本レッスンはダミーのみで行います(実データ・個人情報・未公開情報は入力しない)。


このレッスンの狙い(到達状態)

  • DOM/イベントの基本(querySelector/addEventListener)を説明できる
  • UIを「画面の雰囲気」ではなく、状態(state)として扱える
  • loading/error/emptyなどの状態を、UI要件→実装で一貫させられる
  • 例外(未入力/通信失敗/二重送信)を実装側で止められる
  • アクセシビリティ(キーボード/フォーカス/通知)を“要件として”入れられる

受講ルール(共通)

  • 実データ禁止:実URL、実ページID、実アカウント、実顧客情報、未公開企画などは禁止
  • 訓練成果物の流用禁止:訓練で作ったコード/要件/テンプレを通常業務へコピペしない
  • 通常業務をしない:訓練日は講義・演習・レビュー・理解度確認に専念する
  • 命令系統の具体化をしない:役割は「作成担当」「レビュー担当」「承認担当」など抽象ロール
  • 相互レビュー2件以上:前日までの他者成果物に2件以上コメント(本ページの観点を使用)

今日の目標(できた範囲でOK)

受講者のレベル差があるため、強制の提出物は設けません。今日の目標を選び、できた範囲を「今日進めたこと」に記録してください。

  1. (A)TRN-JS43 Specヘッダ(v0.1):UI対象/状態/例外/完了条件を固定(L42を参照してOK)
  2. (B)state+render(最小):UI状態を1つのオブジェクトで持ち、renderで表示を揃える
  3. (C)例外処理(最低3つ):未入力/二重送信/擬似通信失敗 を止める
  4. (D)A11y最小対応:キーボード操作、フォーカス移動、通知(aria-live想定)
  5. (E)デバッグ手順(v0.1):再現条件→原因仮説→修正→再確認の型を作る

結論:JSは「イベント」より先に「状態(state)」を決める

ありがちな失敗(JSがごちゃつく理由)

  • クリックのたびにDOMを直接いじってしまい、状態が破綻する
  • loading/error/emptyが実装されず、連打・二重送信・迷子が起きる
  • 例外(未入力/失敗)を想定せず、復帰導線がなくなる
  • キーボード操作・フォーカスが抜けて、検収で差戻しになる

今日の最小アーキテクチャ(これだけで崩れにくい)

  1. state:今の状態を1箇所に集約(例:modalOpen, status, errorMessage)
  2. render():stateからUIを再描画(表示/非表示、disabled、メッセージ)
  3. event:イベントでstateを更新し、renderを呼ぶ
  4. guard:例外(未入力/二重送信/失敗)をifで止める

標準テンプレ(TRAINING ONLY)

A) TRN-JS43 Specヘッダ(v0.1)

【TRN-JS43 Specヘッダ(v0.1:訓練専用・流用禁止)】
Spec-ID:TRN-JS43
版:v0.1
状態:DRAFT / REVIEW / FINAL(訓練内)

UI対象(ダミー):

* 例:モーダル+フォーム送信 / タブ切替 / リストフィルタ
  目的(1行):
* 例:state+renderで、loading/error/emptyを破綻なく実装する練習をする

範囲(やる/やらない):

* やる:DOM/イベント/state/render/例外処理/A11y最小対応(ダミー)
* やらない:実サイト更新、実公開、実運用データ反映、実承認

状態(最低8つのうち使うもの):

* default / focus / active / disabled / loading / success / error / empty / closed / open

例外(最低3つ):

* 未入力(validation error)
* 二重送信(loading中の連打)
* 擬似通信失敗(ダミー条件でerror)

A11y(最低ライン):

* キーボード(Enter/Space/Esc)
* フォーカス(開いたら中へ、閉じたら戻す)
* 通知(処理中/完了/エラーを伝える想定)
* 動き抑制(動きがなくても理解できる)

完了条件(採点可能):

* stateとrenderが分離され、イベントでstate更新→renderになっている
* loading中は操作が抑止され、二重送信ができない
* error/emptyが表示され、復帰導線がある
* 実データ混入がない(訓練専用の明記あり)

B) ダミー課題(1つ選べばOK)

JS-43A(易):タブ切替(矢印キー対応)+empty状態

状況(ダミー):
- 3タブで表示内容を切り替える
- タブの内容は配列(ダミー)から表示
- 該当データがない場合は empty を表示する

要求:

* state(activeTab, status)を持つ
* クリックとキーボード(左右矢印)で切替できる
* empty時の復帰(別タブへ切替)が明確

JS-43B(中):モーダル+フォーム送信(loading/success/error)

状況(ダミー):
- ボタンでモーダルを開く
- 必須入力が空ならエラー
- 送信でloading → success / error に遷移
- error時は再試行導線がある
- Escで閉じる、閉じたらフォーカスを元ボタンへ戻す

要求:

* 二重送信防止(loading中は送信不可)
* aria-live等で状態通知の想定
* 実データ/実URLは使わない

JS-43C(中):リスト取得(擬似API)+error/empty復帰

状況(ダミー):
- 「読み込み」クリックで擬似データを表示(setTimeout)
- 擬似失敗条件がある(例:チェックボックスONで失敗)
- emptyの場合は「条件を変える」導線で復帰

要求:

* status: idle/loading/success/error/empty をstateで管理
* render()で表示を揃える

サンプル(訓練用:JS-43B モーダル+フォーム送信)

※このサンプルは訓練用の型です。実務に流用しないでください。

1) HTML(index.html想定:抜粋)

<!-- TRAINING ONLY: TRN-JS43 -->
<div class="trn">
  <h2>TRN-JS43:モーダル+フォーム送信(ダミー)</h2>



 

 

2) JS(script.js想定:抜粋)

/* TRAINING ONLY: TRN-JS43(流用禁止) */

const $ = (sel) => document.querySelector(sel);

const els = {
openBtn: $("#openBtn"),
closeBtn: $("#closeBtn"),
submitBtn: $("#submitBtn"),
modal: $("#modal"),
msg: $("#msg"),
errorBox: $("#errorBox"),
resultBox: $("#resultBox"),
statusLive: $("#statusLive"),
};

const state = {
modalOpen: false,
status: "idle", // idle | loading | success | error
errorMessage: "",
resultMessage: "",
lastFocusEl: null,
};

function setLive(text) {
// 訓練:状態通知の想定(実装方針は本番で別途設計)
els.statusLive.textContent = text;
}

function render() {
// モーダル表示
els.modal.hidden = !state.modalOpen;

// ボタン操作抑止(loading中)
const isLoading = state.status === "loading";
els.submitBtn.disabled = isLoading;
els.closeBtn.disabled = isLoading;

// エラー表示
if (state.status === "error") {
els.errorBox.hidden = false;
els.errorBox.textContent = state.errorMessage || "エラー(ダミー)";
setLive("エラーが発生しました(ダミー)");
} else {
els.errorBox.hidden = true;
els.errorBox.textContent = "";
}

// 結果表示
if (state.status === "success") {
els.resultBox.hidden = false;
els.resultBox.textContent = state.resultMessage || "完了(ダミー)";
setLive("送信が完了しました(ダミー)");
} else {
els.resultBox.hidden = true;
els.resultBox.textContent = "";
}

// loading通知
if (state.status === "loading") {
setLive("処理中です(ダミー)");
}
}

function openModal() {
state.lastFocusEl = document.activeElement;
state.modalOpen = true;
state.status = "idle";
state.errorMessage = "";
state.resultMessage = "";
render();

// フォーカス(最小対応)
els.msg.focus();
}

function closeModal() {
if (state.status === "loading") return; // 二重操作防止
state.modalOpen = false;
render();

// フォーカスを戻す(最小対応)
if (state.lastFocusEl && state.lastFocusEl.focus) {
state.lastFocusEl.focus();
} else {
els.openBtn.focus();
}
}

function validate() {
const v = (els.msg.value || "").trim();
if (!v) {
return { ok: false, message: "必須入力が空です(ダミー)" };
}
return { ok: true, message: "" };
}

function fakeRequest(payload) {
// 擬似通信:入力に「error」が含まれると失敗(再現可能)
return new Promise((resolve, reject) => {
setTimeout(() => {
if ((payload.message || "").includes("error")) {
reject(new Error("擬似通信失敗(ダミー条件:'error'を含む)"));
} else {
resolve({ ok: true });
}
}, 800);
});
}

async function onSubmit() {
if (state.status === "loading") return; // 二重送信防止(ガード)
const check = validate();
if (!check.ok) {
state.status = "error";
state.errorMessage = check.message;
state.resultMessage = "";
render();
els.msg.focus();
return;
}

state.status = "loading";
state.errorMessage = "";
state.resultMessage = "";
render();

try {
await fakeRequest({ message: els.msg.value.trim() });
state.status = "success";
state.resultMessage = "送信完了(ダミー)";
render();
} catch (e) {
state.status = "error";
state.errorMessage = e.message || "不明なエラー(ダミー)";
render();
// エラー時は入力に戻して復帰できるように
els.msg.focus();
}
}

els.openBtn.addEventListener("click", openModal);
els.closeBtn.addEventListener("click", closeModal);
els.submitBtn.addEventListener("click", onSubmit);

// Escで閉じる(最小)
document.addEventListener("keydown", (ev) => {
if (!state.modalOpen) return;
if (ev.key === "Escape") {
ev.preventDefault();
closeModal();
}
});

// 初期描画
render();

3) デバッグ観点(サンプルの確認ポイント)

  • 未入力で送信 → error表示+フォーカスが入力へ戻る
  • 入力に「error」を含めて送信 → 擬似失敗 → error表示+再入力できる
  • 送信中(loading)に連打 → 二重送信されない(ボタンdisabled)
  • Escで閉じる → 開いたボタンへフォーカスが戻る

品質ゲート(OK/差戻し/要相談:v1.0)

判定 基準 次アクション 記録
OK state+renderが分離され、loading/error/empty等の状態が再現でき、例外で止められる(二重送信/未入力) 次工程(L40の検収観点やL42のState表に接続)へ 結果=OK、根拠
差戻し 状態がDOM散在、loadingがなく二重送信可能、error/emptyの復帰がない、A11yが抜け(Esc/フォーカス) v+0.1で修正(不足を埋める) 差戻し理由(どこ/なぜ/完了条件)
要相談(停止) 実データ混入、実サイト更新・公開を誘導、権利/法務/安全に触れる断定、通常業務に流用する意図がある 作業停止→相談(抽象ルート) 停止理由、混入箇所、再開条件

ChatGPTに投げるプロンプト(コピペ用)

1) UI要件(L42)から「実装に落ちるstate設計」を作る

【L43 プロンプト①:state設計(訓練用)】

前提(安全):

* 教育訓練用ダミー。実データ・実URL・未公開情報は禁止。
* 訓練成果物は流用禁止。実サイト更新はしない。

入力:

* L42で作ったUI要件(State表+例外表+A11y要件)
* 選んだ課題(JS-43A/B/C)

出力形式(必須):

* state設計(キー一覧と意味)
* renderで更新するUI要素一覧
* イベント一覧(click/keydown/submit 等)とstate遷移
* ガード(未入力/二重送信/失敗)

2) 最小実装(state+render+event)を生成する

【L43 プロンプト②:最小実装(訓練用)】

前提:

* 外部通信はしない(fetchしない)。擬似通信はsetTimeout/Promiseで。
* 状態管理(state)と描画(render)を分ける。
* A11y:Esc、フォーカス戻し、通知(aria-live想定)を入れる。

入力:

* あなたのstate設計
* UI要件(抜粋)

出力形式:

* HTML(必要要素:ボタン/入力/メッセージ領域 等)
* JS(state/render/event/guard/擬似通信)
* コメントで「TRAINING ONLY/流用禁止」を明記

3) 自己レビュー(差戻し観点)

【L43 プロンプト③:自己レビュー(差戻し防止)】

入力:

* あなたのHTML/JS
* L43の品質ゲート

出力:

* 判定(OK/差戻し/要相談)
* 差戻し理由(どこ/なぜ/完了条件:最大5つ)
* v+0.1の改善案(差分)

相互レビュー観点(L43専用)

  • 訓練専用の担保:流用禁止が明記され、実在情報が混入していないか
  • state+render:状態が1箇所に集約され、renderで表示が揃っているか
  • 例外:未入力/二重送信/失敗がガードでき、復帰があるか
  • A11y:キーボード(Esc等)とフォーカスが最低限入っているか
  • 再現性:成功/失敗が再現できる条件があり、検収ができるか(ランダム禁止推奨)

レビューコメントテンプレ(コピペ用)

【L43 相互レビューコメント】
対象(TRN-JS43):
版:

1. 良い点(1つ):

*

2. state+renderは分離できてる?

* OK / 要改善
  改善案(1つ):
*

3. 例外(未入力/二重送信/失敗)は止められる?

* OK / 要改善
  不足(1つ):
*

4. A11y(Esc/フォーカス/通知想定)は最低限ある?

* OK / 要改善
  不足(1つ):
*

5. 次の一手(v+0.1で直すなら):

* 

本日の流れ(タイムライン)

目次(クリックで移動)

  1. 出席・当日選択カリキュラムの内容確認
  2. 時間差相互評価(2件以上コメント)
  3. 休憩
  4. 自分への受領レビュー確認・改善方針メモ
  5. L43 レクチャー本編(講師説明・質疑込み)
  6. 昼休憩
  7. 個人演習①:state設計→最小実装
  8. 休憩
  9. 個人演習②:例外/A11y/差戻し→v+0.1改善
  10. 休憩
  11. 復習:共有できる形に整形(できた範囲でOK)
  12. 質問・コメント・感想の提出(指定スレッド)

1) 出席・当日選択カリキュラムの内容確認

【実施時間】

対象 時間
EC事業部 08:30–09:10
文房具カフェ事業部/準備室 10:00–10:40

この時間にやること

  1. 今日の目標(A〜E)を選ぶ(できた範囲でOK)
  2. ダミー課題(JS-43A/B/C)を1つ選ぶ
  3. 注意点を1行で書く(例:stateとrenderを分ける/二重送信を止める/流用禁止)

セルフ棚卸し(コピペ用)

【L43 セルフ棚卸し】
1) 今日選ぶダミー課題:
- JS-43A / JS-43B / JS-43C

2. 自分が弱い点(1つ):

* (例:状態の洗い出し/例外処理/フォーカス設計/デバッグ)

3. 今日の目標(1行):

* 

2) 時間差相互評価(前日までの他者成果物に2件以上コメント)

【実施時間】

対象 時間
EC事業部 09:10–10:00
文房具カフェ事業部/準備室 10:40–11:30

この時間にやること

  • 前日までの他者成果物を2件選び、L43レビュー観点でコメントする
  • 「動いてる」より、状態/例外/復帰/A11yが揃っているかを見る

3) 休憩

【実施時間】

対象 時間
EC事業部 10:00–10:15
文房具カフェ事業部/準備室 11:30–11:45

休憩:学習作業なし


4) 自分への受領レビュー確認・改善方針メモ(講師レビュー含む)

【実施時間】

対象 時間
EC事業部 10:15–10:45
文房具カフェ事業部/準備室 11:45–12:15

改善方針メモ(コピペ用)

【L43 改善方針メモ】
受領した指摘の要点(最大3つ):
1)
2)
3)

## 直す理由(state散在/例外不足/復帰が曖昧/A11y不足 等):

直し方(どこを改善する?):

* state設計:
* render(表示/非表示/disabled):
* 例外(ガード):
* A11y(フォーカス/キー操作):
* 再現条件(成功/失敗):

今日の最優先ルール(1行):

* 

5) 当日選択カリキュラム実施:L43レクチャー本編(講師説明・質疑込み)

【実施時間】

対象 時間
EC事業部 10:45–12:00
文房具カフェ事業部/準備室 12:15–13:30

ここからが「読む/聞く」パート

JSは「正解コード」よりも、壊れない構造(state→render→event→guard)を先に作るのが重要です。
午後は、選んだダミー課題をstate設計から始め、例外/A11y/復帰まで揃えます。


6) 昼休憩

【実施時間】

対象 時間
EC事業部 12:00–13:00
文房具カフェ事業部/準備室 13:30–14:30

昼休憩:学習作業なし


7) 個人演習①:state設計→最小実装

【実施時間】

対象 時間
EC事業部 13:00–14:30
文房具カフェ事業部/準備室 14:30–16:00

演習①のやり方(必須)

  1. TRN-JS43 Specヘッダ(v0.1)を埋める(状態/例外/A11y/完了条件)
  2. state設計(キー一覧)を作る
  3. render()を作り、state→UIが揃うようにする
  4. イベント(click/keydown等)でstate更新→renderを徹底する

提出用フォーマット(演習①:コピペ用/できた範囲でOK)

【L43 演習① 提出(できた範囲でOK)】
Spec-ID:TRN-JS43
ダミー課題:

## (1) Specヘッダ(v0.1):

## (2) state設計(キー一覧):

(3) renderの方針(何をstateで制御する?):

* 

8) 休憩

【実施時間】

対象 時間
EC事業部 14:30–14:45
文房具カフェ事業部/準備室 16:00–16:15

休憩:学習作業なし


9) 個人演習②:例外/A11y/差戻し→v+0.1改善

【実施時間】

対象 時間
EC事業部 14:45–15:45
文房具カフェ事業部/準備室 16:15–17:15

演習②のやり方(必須)

  1. 例外(未入力/二重送信/失敗)をガードし、復帰導線を作る
  2. A11y最小(Esc/フォーカス戻し/通知想定)を入れる
  3. 品質ゲートで自己判定(OK/差戻し/要相談)し、差戻しならv+0.1で直す

提出用フォーマット(演習②:コピペ用/できた範囲でOK)

【L43 演習② 提出(できた範囲でOK)】
Spec-ID:TRN-JS43

## (1) 例外(ガード)と復帰:

## (2) A11y最小対応(Esc/フォーカス/通知想定):

(3) 品質ゲート判定:

* 判定(OK/差戻し/要相談):
* 根拠(1行):

(4) 任意:v+0.1の改善ログ(何を/なぜ/どう直す):

* 

10) 休憩

【実施時間】

対象 時間
EC事業部 15:45–16:00
文房具カフェ事業部/準備室 17:15–17:30

休憩:学習作業なし


11) 復習:共有できる形に整形(できた範囲でOK)

【実施時間】

対象 時間
EC事業部 16:00–16:30
文房具カフェ事業部/準備室 17:30–18:00

最終チェック(コピペ用)

【L43 最終チェック】
- 訓練専用(流用禁止)が明記されている
- 実データ/実URL/実案件が混入していない
- stateとrenderが分離されている(イベントでstate更新→render)
- loading中の二重送信が止められる
- error/emptyがあり、復帰導線がある
- A11y最小(Esc/フォーカス戻し/通知想定)がある

12) 講師への質問・コメント・感想の提出(指定スレッド)

【実施時間】

対象 時間
EC事業部 16:30–17:00
文房具カフェ事業部/準備室 18:00–18:30

提出先(参考)

EC事業部・文房具カフェ事業部:ChatWork の指定スレッド/準備室:Slack の指定スレッド

提出テンプレ(コピペ用)

【L43 提出(本人レポート)】

1. 今日の学習内容(要約:3行)

*
*
*

2. 今日進めたこと(TRAINING ONLY:流用禁止)

* 選んだ課題(JS-43A/B/C):
* Specヘッダ:
* state設計:
* render方針:
* 例外(ガード):
* A11y最小対応:
* 品質ゲート判定:

3. 一番工夫した点(1つ)
   -(例:state→renderに揃えた/二重送信を止めた/error復帰を作った 等)
   理由:

*

4. 次に改善したい点(1つ)

*

## 理由:

5. 質問(最低1つ)

* 

ページ先頭へ戻る

上部へスクロール