1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【kintone】銀行名と支店名から、金融機関コードと店番を検索

1
Last updated at Posted at 2025-07-17

Animation.gif

銀行くんのAPIを使用。銀行名と支店名の入力をサジェストで補助し
選択された銀行や支店に応じて、自動的に金融機関コードと店番を設定する。


フィールドを以下の通り配置する。
スペースの要素IDは、左から space1 space2 とする。

er.png

PC用のJavaScript / CSSファイル を下図のように設定。

ライブラリは以下のページにある。

タイトルなし.png

sample.js は下記のように書く。

sample.js
(() => {
  'use strict';

  let selectedBankCode = null;
  let bankText = null;
  let branchText = null;
  let bankAutocompleteInit = false;
  let branchAutocompleteInit = false;

  // オートコンプリート設定関数
  const createAutocompleteForInput = (inputEl, type, getSource, onSelect) => {
    if (!inputEl) return;

    // jQuery UI のオートコンプリートを設定
    $(inputEl).autocomplete({
      // 候補を取得して表示する処理
      source: async (request, response) => {
        const q = request.term.trim(); // 入力された文字列を取得してトリミング
        if (!q) {
          response([]); // 空なら候補を返さず終了
          return;
        }
        try {
          // 非同期でデータ取得し、上位10件のみ整形して返す
          const data = await getSource(q);
          response(
            data.slice(0, 10).map((item) => ({
              label: `${item.name}(${item.code})`,
              value: item.name,
              code: item.code
            }))
          );
        } catch (err) {
          // 通信やAPIのエラーが出たら、ログ出力し、候補は空で返す
          console.error(`${type} 検索エラー:`, err);
          response([]);
        }
      },
      // 選択された候補をTextコンポーネントを入力
      select: (ev, ui) => {
        onSelect(ui.item);
        return false; // デフォルト動作を抑制
      },
      minLength: 1, // 最低1文字入力で候補検索を実行
      delay: 300 // 過剰通信防止のため入力後300msの待機を設定
    });
  };

  // 追加作成か編集画面が表示されたときに実行
  kintone.events.on(['app.record.create.show', 'app.record.edit.show'], (event) => {
    // 初回のみスペースの位置調整用CSSを挿入
    if (!document.getElementById('kuc-custom-styles')) {
      const style = document.createElement('style');
      style.id = 'kuc-custom-styles';
      style.textContent = `
        .bank-space { margin-left: 8px; display: inline-block; }
        .branch-space { margin-left: 8px; display: inline-block; }
      `;
      document.head.appendChild(style);
    }

    const record = event.record;

    // ユーザーが手動でコードを入力できないようにフィールドを非活性化
    record.金融機関コード.disabled = true;
    record.店番.disabled = true;

    // [銀行名][支店名]フィールドを非表示にする
    kintone.app.record.setFieldShown('銀行名', false);
    kintone.app.record.setFieldShown('支店名', false);

    // kintone UI Component の Textコンポーネント を配置するスペースを取得
    const space1 = kintone.app.record.getSpaceElement('space1');
    const space2 = kintone.app.record.getSpaceElement('space2');
    if (!space1 || !space2) {
      console.error('スペースフィールドが見つかりません');
      return event;
    }

    // 銀行名の入力コンポーネントを生成
    bankText = new Kuc.Text({
      label: '銀行名',
      requiredIcon: false,
      value: record.銀行名.value || '',
      error: '',
      className: 'bank-text'
    });

    // 支店名の入力コンポーネントを生成
    branchText = new Kuc.Text({
      label: '支店名',
      requiredIcon: false,
      value: record.支店名.value || '',
      error: '',
      className: 'branch-text'
    });

    // スペースに生成したコンポーネントを追加
    space1.classList.add('bank-space');
    space2.classList.add('branch-space');
    space1.appendChild(bankText);
    space2.appendChild(branchText);

    // 既存データに銀行コードがあれば状態を保持
    if (record.銀行名.value && record.金融機関コード.value) {
      selectedBankCode = record.金融機関コード.value;
    }

    // 銀行名コンポーネントの値が変更されたときの処理
    bankText.addEventListener('change', (e) => {
      const newVal = e?.detail?.value ?? '';
      record.銀行名.value = newVal;

      // 値がクリアされたらフィールドの値もクリア
      if (!newVal) {
        record.金融機関コード.value = '';
        record.支店名.value = '';
        record.店番.value = '';
        if (branchText) branchText.value = '';
        selectedBankCode = null;
      }

      // フィールドの値クリアをレコードに反映
      kintone.app.record.set({ record });
    });

    // 支店名コンポーネントの値が変更されたときの処理
    branchText.addEventListener('change', (e) => {
      const newVal = e?.detail?.value ?? '';
      record.支店名.value = newVal;
      // 値が空になったら店番も消す
      if (!newVal) record.店番.value = '';
      kintone.app.record.set({ record });
    });

    // 銀行名が初めてフォーカスされたときにオートコンプリートを設定
    bankText.addEventListener('focus', () => {
      if (bankAutocompleteInit) return; // 初期化済みなら再設定しない
      const input = bankText.querySelector?.('input');
      if (!input) return;

      // 銀行くんを利用して候補を取得
      createAutocompleteForInput(
        input,
        '銀行',
        async (q) => {
          const res = await fetch(`https://bank.teraren.com/banks/search.json?name=${encodeURIComponent(q)}`);
          return await res.json();
        },
        // 候補選択時に値を反映
        (item) => {
          bankText.value = item.value;
          record.銀行名.value = item.value;
          record.金融機関コード.value = item.code;
          selectedBankCode = item.code;
          // 銀行が変わったら支店情報はリセット
          branchText.value = '';
          record.支店名.value = '';
          record.店番.value = '';
          kintone.app.record.set({ record });
        }
      );

      // 一度設定したら再実行しないようフラグを立てる
      bankAutocompleteInit = true;
    });

    // 支店名が初めてフォーカスされたとき
    branchText.addEventListener('focus', () => {
      if (branchAutocompleteInit) return; // 初期化済みなら終了
      const input = branchText.querySelector?.('input');
      if (!input) return;

      // 銀行コードが選択されてない場合は検索しない
      createAutocompleteForInput(
        input,
        '支店',
        async (q) => {
          if (!selectedBankCode) return [];
          const res = await fetch(`https://bank.teraren.com/banks/${selectedBankCode}/branches/search.json?name=${encodeURIComponent(q)}`);
          return await res.json();
        },
        // 候補が選択されたら値を反映
        (item) => {
          branchText.value = item.value;
          record.支店名.value = item.value;
          record.店番.value = item.code;
          kintone.app.record.set({ record });
        }
      );

      // 初期化済みフラグをセット
      branchAutocompleteInit = true;
    });

    return event;
  });

  // 表示崩れ防止のため詳細画面でスペースを隠す
  kintone.events.on('app.record.detail.show', (event) => {
    requestAnimationFrame(() => {
      const spaceCodes = ['space1', 'space2'];
      for (const code of spaceCodes) {
        const el = kintone.app.record.getSpaceElement(code);
        if (!el) continue;

        // 親要素を探索して表示中のブロックを非表示にする
        let p = el.parentElement;
        while (p && p !== document.body) {
          if (p.getBoundingClientRect().height > 1) {
            p.style.display = 'none';
            break;
          }
          p = p.parentElement;
        }

        // スペース自体も非表示にする
        el.style.display = 'none';
      }
    });
    return event;
  });

  // [銀行名][支店名]フィールドの値変更に連動して他フィールドを更新
  kintone.events.on(
    [
      'app.record.create.change.銀行名',
      'app.record.edit.change.銀行名',
      'app.record.create.change.支店名',
      'app.record.edit.change.支店名'
    ],
    (event) => {
      const record = event.record;

      // 銀行名が空欄になったら、関連する全フィールドをクリア
      if (!record.銀行名.value) {
        record.金融機関コード.value = '';
        record.支店名.value = '';
        record.店番.value = '';
        selectedBankCode = null;
        if (branchText) branchText.value = '';
      }

      // 支店名が空欄になった場合は店番のみクリア
      if (!record.支店名.value) {
        record.店番.value = '';
      }

      return event;
    }
  );
})();
1
1
6

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?