Open7

Next.js上でformBuilderを使ってみる

hoshitahoshita

準備

パッケージをインストール

$ yarn add formBuilder

Homeコンポーネントの不要なものを削除

"use client"

export default function Home() {
  return (
    <main>
      <h1>formbuilder</h1>
    </main>
  );
}

必要最低限のものだけ削除

layout.tsxのglobals.cssの読み込みを削除しておいた方が見やすい

useRefを使用するので"use clientも一緒に記述

hoshitahoshita

必要なものをインポート

import $ from 'jquery';
import React, { useEffect, useRef } from 'react';

export default function Home() {
// 省略
}

公式のドキュメントでは一緒にNodeのrequireを使用してインポートしているが、タイミングの都合でうまく動かない。後ほどuseEffect内で記述する。

importとrequreiの違いについては

ロジック部分の記述

export default function Home() {
  const fbRef = useRef<HTMLDivElement | null>(null); // フォーム編集の中身を保持

  useEffect(() => {
    window.jQuery = $;
    window.$ = $;

    require('jquery-ui-sortable');
    require('formBuilder');

    // jQuery 関連のコードを実行
    ($ as any)(fbRef.current).formBuilder({});
  }, []); 
  return (
    // 省略
  );
}

中身を保持するrefとjQueryのインポートをここで行う。

useEffectを使用して初回のみ走らせるようにする。

hoshitahoshita

描画の記述

export default function Home() {
  const fbRef = useRef<HTMLDivElement | null>(null);
  const isInitializedForm = useRef(false);

  useEffect(() => {
    if (isInitializedForm.current) return;
  // 省略
  }, []);

  return (
    <main>
      <h1>formbuilder</h1>
      <div id="fb-editor" ref={fbRef} />
    </main>
  );
}

まずは1つ前で定義したfbRefを使用して<div id="fb-editor" ref={fbRef} />を追記

これで画面上にフォームビルダーを描画することができた。

しかし現状の実装だとfbRefに変更が入るたびにformBuilder({})が発火してフォームビルダーが増殖する。

それを防ぐために初期化フラグを持つ変数を用意して、if文の早期リターンで初期化時のみformBuilder({})が実行されるようにする。

hoshitahoshita

フォームデータの出力

既存で実装されているClear[{...}]は実際にクリアとjsonの中身を表示するよう動くがSaveだけは保存したり出力されりしない。

そのため個別で作る準備としてClearとSaveとDataを非表示にする

 ($ as any)(fbRef.current).formBuilder({disabledActionButtons: ['data', 'save']});
hoshitahoshita

プロパティ 'jQuery' は型 'Window & typeof globalThis' に存在しません。という指摘を解消する

方法1

global.d.ts
export {};

declare global {
  interface Window {
    jQuery: typeof import('jquery');
    $: typeof import('jquery');
  }
}

方法2

index.tsx
interface Window {
  jQuery: typeof import('jquery');
  $: typeof import('jquery');
}
declare var window: Window;

https://blog.tanebox.com/archives/1757/
https://dev.classmethod.jp/articles/typings-of-window-object/