Documentation

カスタムフォームフィールドタイプの書き方

Forms アプリケーションには、高度に設定可能な フィールドタイプが多く含まれており、すぐに利用することができます。. ほとんどのユースケースは、既存のフィールドタイプの一つで対応できる。 デフォルトのフィールドタイプでユースケースを満たせない場合、独自のフィールドタイプを作成することができます。

多くの便利なフォーム要素があります。

注釈

  • ドキュメントとメディア(メタデータセット)、Webコンテンツ(構造体)、およびFormsアプリケーションで作成されたフォームは、すべて同じフォームフィールドを消費することができます。 デフォルトでは、カスタムフォームフィールドは、Formsアプリケーションでのみ使用されます。 どのアプリケーションがフォームフィールドタイプを有効にするかを明示的に指定するために、コンポーネントプロパティを追加します。

    "ddm.form.field.type.scope=document-library,forms,journal""
    
  • プロジェクトの互換性 サンプルプロジェクトはLiferay 7.4で動作しています。 Liferay 7.3 を実行している場合、ソースコードは互換性がありますが、 Workspace プロジェクト を Liferay 7.3 用に再設定する必要があります。 そのための手順が、以下のインストラクションに記載されています。

    Liferay 7.2 をお使いの場合、サポートされるフロントエンドフレームワークの違いにより、このソースコードは動作しません。 C2P9 Sliderのコードサンプルを7.2用に適合させる方法については、 Developing a Custom Form Field for Liferay 7.2 を参照してください。

Liferay のカスタムフォームフィールドを検証する

カスタムフォームフィールドがどのように機能するかを見るために、例をデプロイし、新しいフィールドを使っていくつかのフォームデータを追加してみましょう。

例をデプロイする

新しいLiferay インスタンスを起動し、以下を実行します。

docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.29-ga29。

http://localhost:8080でLiferayへのサインインします。 メールアドレス_test@liferay.com_とパスワード_test_を使用してください。 プロンプトが表示されたら、パスワードを _learn_に変更します。

次に、以下の手順を実行します。

  1. Custom Form Field Type プロジェクト をダウンロードし、解凍してください。

    curl https://learn.liferay.com/dxp/latest/ja/process-automation/forms/developer-guide/liferay-c2p9.zip -O
    
    unzip liferay-c2p9.zip
    
  2. モジュールのルートから、ビルドおよびデプロイします。

    ./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    

    ちなみに

    このコマンドは、デプロイされたjarをDockerコンテナの/opt/liferay/osgi/modulesにコピーするのと同じです。

    注釈

    Liferay 7.3 の場合、デプロイする前にプロジェクトに以下の調整を加えてください。

    • c2p9-impl/package.json で、devDependencies の参照を @liferay/portal-7.4 から @liferay/portal-7.3 に変更します。

    • gradle.propertiesliferay.workspace.product の値を portal-7.3-ga8 に変更します (GA8 より新しい Liferay 7.3 バージョンがある場合は、代わりにここを参照してみてください)。

  3. Liferay Dockerコンテナコンソールでデプロイを確認します。

    STARTED com.acme.c2p9.impl_1.0.0 [1009]
    

デプロイされたスライダーフィールドを使用する

  1. ブラウザでhttp://localhost:8080を開きます。

  2. サイトメニューコンテンツ & データフォーム のフォームアプリケーションに移動します。

  3. 追加 ボタン(Add)をクリックして、フォームビルダーを開きます。

  4. フォームに C2P9 Slider フィールドを追加します。

  5. ラベル、定義済み値、ヘルプテキストを記入し、フィールドを必須とすることもできます。 これらの設定は、多くの アウトオブボックスフィールド が基本設定として提供するものと一致します。

  6. フォームを公開し、スライダーフィールドを使用してレコードを送信してください。

スライダーで0〜100の値を設定します。

フォームフィールドのコードを理解する

基本的なフォームフィールドは、JavaクラスとJavaScriptファイルから構成されています。 C2P9 Sliderフィールドでは、 C2P9DDMFormFieldType.java が、 DDMFormFieldType の実装を、抽象クラス BaseDDMFormFieldType を拡張してOSGiコンポーネントでそのメタデータを定義して提供します。

@Component(
	property = {
		"ddm.form.field.type.description=c2p9-description",
		"ddm.form.field.type.display.order:Integer=10",
		"ddm.form.field.type.group=customized", "ddm.form.field.type.icon=text",
		"ddm.form.field.type.label=c2p9-label",
		"ddm.form.field.type.name=c2p9-slider"
	},
	service = DDMFormFieldType.class
)
public class C2P9DDMFormFieldType extends BaseDDMFormFieldType {

ddm.form.field.type.description: 説明テキストに言語キーを指定します。 翻訳された値が Language.properties ファイルに定義されていることを確認してください。

ddm.form.field.type.display.order: フォームビルダーのサイドバーのどこにフィールドが表示されるかを、整数値または浮動小数点数で設定します。 同じ値を持つフィールドはランダムに並べられる。

ddm.form.field.type.icon: フィールドに使用するアイコンタイプを決定します。 Clay Icon いずれかを選択。

ddm.form.field.type.label: ラベルテキストに言語キーを指定します。 翻訳された値が Language.properties ファイルに定義されていることを確認してください。

ddm.form.field.type.name: フィールドタイプの識別子を指定します。 これは内部および他のコンポーネントでフィールドを識別するために使用される。

getModuleName メソッドは、 Slider.es.js ファイルのパスを NPMResolver サービスに渡します。

@Override
public String getModuleName() {
	return _npmResolver.resolveModuleName(
		"dynamic-data-mapping-form-field-type-c2p9-slider/C2P9/Slider.es");
}
@Reference
private NPMResolver _npmResolver;

パス定義の一部は package.json ファイルで実現されています ( name declaration と source-maps defined in scripts section をご覧ください)。

getName メソッドは、フォームフィールドの識別子を返します。 これは、コンポーネントプロパティ ddm.form.field.type.nameの値と一致しなければなりません。

@Override
public String getName() {
	return "c2p9-slider";
}

isCustomDDMFormFieldType は内部で使用される。 true を返す NPMResolver.resolveModuleName() の結果を getModuleName メソッドで返す場合は、 true を返す。

@Override
public boolean isCustomDDMFormFieldType() {
	return true;
}

Slider.es.js フィールドのJavaScriptロジックを提供します。 MainSliderの2つのコンポーネントがファイルに定義されています。

インポート文は、Liferayの基本フォームフィールドである dynamic-data-mapping-form-field-typeの機能を取り込んでいます。 これらは、後で宣言された変数 FieldBaseuseSyncValueを使って呼び出されます。

import {FieldBase} from 'dynamic-data-mapping-form-field-type/FieldBase/ReactFieldBase.es';
import {useSyncValue} from 'dynamic-data-mapping-form-field-type/hooks/useSyncValue.es';

const Slider = ブロックはフィールドを定義します: それはパラメータ name, onChange, predefinedValue, readOnly, and valueでインスタンス化されています。

const Slider = ({name, onChange, predefinedValue, readOnly, value}) => (
	<input
		className="ddm-field-slider form-control slider"
		disabled={readOnly}
		id="myRange"
		max={100}
		min={1}
		name={name}
		onInput={onChange}
		type="range"
		value={value ? value : predefinedValue}
	/>
);

これらのパラメータの値と、その他のいくつかのパラメータによって、フォームフィールドのHTML <input> タグが定義されます。 重要なのは、ユーザーが選択できる maxmin の値は、現在ハードコードされていることです。 後で変更します . フィールドの値は三項演算子を用いて定義される。値が入力されていれば、それを使用する。 それ以外の場合は、あらかじめ設定されている値を使用します。

Main コンポーネントはファイルの最後にエクスポートされ、インポートされた FieldBaseの子要素として Slider を含んでいます。 onChange 関数は、イベントが検出されるたびに(スライダーが新しい値までドラッグされるたびに)スライダーの位置/値を取得します。

const Main = ({
	label,
	name,
	onChange,
	predefinedValue,
	readOnly,
	value,
	...otherProps
}) => {
	const [currentValue, setCurrentValue] = useSyncValue(
		value ? value : predefinedValue
	);

	return (
		<FieldBase
			label={label}
			name={name}
			predefinedValue={predefinedValue}
			{...otherProps}
		>
			<Slider
				name={name}
				onChange={(event) => {
					setCurrentValue(event.target.value);
					onChange(event);
				}}
				predefinedValue={predefinedValue}
				readOnly={readOnly}
				value={currentValue}
			/>
		</FieldBase>
	);
};

Main.displayName = 'Slider';

export default Main;

フォームフィールドにカスタム設定を追加する

現在、スライダーフィールドの最大値と最小値の設定はハードコーディングされていますが、設定可能であればよりよいでしょう。 フォームのフィールドにカスタム設定を追加する場合。

  • DDMFormFieldTypeSettings クラスを追加し、 DDMFormFieldTypeにメソッドを追加して、バックエンドを調整します。

  • DDMFormFieldTemplateContextContributor を追加し、 Slider.es.jsで定義されている設定方法を更新して、新しい設定をレンダリングするためにフロントエンドを適応させます。

バックエンドのカスタム設定に対応

フォームフィールドの設定は DDMTypeSettings クラスで定義されます。また、 @DDMForm アノテーションを使ってフィールドのサイドバーに表示されるフォームも定義されます。 それから、 DDMFormFieldType 自身が新しい設定定義について知っている必要があるので、デフォルトのフィールド設定フォームを表示しないようにします。 DDMFormFieldContextContributor クラスが新しい設定を React コンポーネントに送信し、エンドユーザーに表示します。

  1. C2P9DDMFormFieldTypeSettings Java クラスを com.acme.c2p9.internal.dynamic.data.mapping.form.field.type パッケージに追加してください。

    package com.acme.c2p9.internal.dynamic.data.mapping.form.field.type;
    
    import com.liferay.dynamic.data.mapping.annotations.DDMForm;
    import com.liferay.dynamic.data.mapping.annotations.DDMFormField;
    import com.liferay.dynamic.data.mapping.annotations.DDMFormLayout;
    import com.liferay.dynamic.data.mapping.annotations.DDMFormLayoutColumn;
    import com.liferay.dynamic.data.mapping.annotations.DDMFormLayoutPage;
    import com.liferay.dynamic.data.mapping.annotations.DDMFormLayoutRow;
    import com.liferay.dynamic.data.mapping.form.field.type.DefaultDDMFormFieldTypeSettings;
    
    @DDMForm
    @DDMFormLayout(
       paginationMode = com.liferay.dynamic.data.mapping.model.DDMFormLayout.TABBED_MODE,
       value = {
          @DDMFormLayoutPage(
             title = "%basic",
             value = {
                @DDMFormLayoutRow(
                   {
                      @DDMFormLayoutColumn(
                         size = 12,
                         value = {
                            "label", "predefinedValue", "required", "tip"
                         }
                      )
                   }
                )
             }
          ),
          @DDMFormLayoutPage(
             title = "%advanced",
             value = {
                @DDMFormLayoutRow(
                   {
                      @DDMFormLayoutColumn(
                         size = 12,
                         value = {
                            "dataType", "min", "max", "name", "showLabel",
                            "repeatable", "type", "validation",
                            "visibilityExpression"
                         }
                      )
                   }
                )
             }
          )
       }
    )
    public interface C2P9DDMFormFieldTypeSettings
       extends DefaultDDMFormFieldTypeSettings {
    
       @DDMFormField(
          label = "%max-value",
          properties = "placeholder=%enter-the-top-limit-of-the-range",
          type = "numeric"
       )
       public String max();
    
       @DDMFormField(
          label = "%min-value",
          properties = "placeholder=%enter-the-bottom-limit-of-the-range",
          type = "numeric"
       )
       public String min();
    
    }
    
  2. 各設定には、 ラベルプレースホルダーの2つの言語キーがあります。 c2p9-impl/src/main/resources/content/Language.properties を開き、以下の行を追加してください。

    max-value=Maximum Value
    min-value=Minimum Value
    enter-the-bottom-limit-of-the-range=Enter the bottom limit of the range.
    enter-the-top-limit-of-the-range=Enter the top limit of the range.
    
  3. DDMFormFieldType クラスに getDDMFormFieldTypeSettings メソッドを追加/オーバーライドして更新します。

    @Override
    public Class<? extends DDMFormFieldTypeSettings>
       getDDMFormFieldTypeSettings() {
    
       return C2P9DDMFormFieldTypeSettings.class;
    }
    

フロントエンドでのカスタム設定に対応

フロントエンドでは、ユーザーが入力する min と max の値をサポートするために Slider.es.js を更新し、フロントエンドがバックエンドから設定値を受け取れるように DDMTemplateContextContributor を追加する必要があります。

  1. C2P9DDMFormFieldTemplateContextContributor クラスを com.acme.c2p9.internal.dynamic.data.mapping.form.field.type パッケージに作成する。

    package com.acme.c2p9.internal.dynamic.data.mapping.form.field.type;
    
    import com.liferay.dynamic.data.mapping.form.field.type.DDMFormFieldTemplateContextContributor;
    import com.liferay.dynamic.data.mapping.model.DDMFormField;
    import com.liferay.dynamic.data.mapping.render.DDMFormFieldRenderingContext;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.osgi.service.component.annotations.Component;
    
    @Component(
      property = "ddm.form.field.type.name=c2p9-slider",
      service = DDMFormFieldTemplateContextContributor.class
    )
    public class C2P9DDMFormFieldTemplateContextContributor
      implements DDMFormFieldTemplateContextContributor {
    
      @Override
      public Map<String, Object> getParameters(
         DDMFormField ddmFormField,
         DDMFormFieldRenderingContext ddmFormFieldRenderingContext) {
    
         Map<String, Object> parameters = new HashMap<>();
    
         parameters.put("max", (String)ddmFormField.getProperty("max"));
         parameters.put("min", (String)ddmFormField.getProperty("min"));
    
         return parameters;
      }
    
    }
    
  2. Slider.es.jsの JavaScript コンポーネントを更新し、ハードコードされた最小値と最大値を削除し、代わりにユーザーが値を入力できるようにしました。 ファイルの全内容は以下の通りです。

    import {FieldBase} from 'dynamic-data-mapping-form-field-type/FieldBase/ReactFieldBase.es';
    import {useSyncValue} from 'dynamic-data-mapping-form-field-type/hooks/useSyncValue.es';
    import React from 'react';
    
    const Slider = ({max, min, name, onChange, predefinedValue, readOnly, value}) => (
       <input
          className="ddm-field-slider form-control slider"
          disabled={readOnly}
          id="myRange"
          max={max}
          min={min}
          name={name}
          onInput={onChange}
          type="range"
          value={value ? value : predefinedValue}
       />
    );
    
    const Main = ({
       label,
       max,
       min,
       name,
       onChange,
       predefinedValue,
       readOnly,
       value,
       ...otherProps
    }) => {
       const [currentValue, setCurrentValue] = useSyncValue(
          value ? value : predefinedValue
       );
    
       return (
          <FieldBase
             label={label}
             name={name}
             predefinedValue={predefinedValue}
             {...otherProps}
          >
             <Slider
                max={max}
                min={min}
                name={name}
                onChange={(event) => {
                   setCurrentValue(event.target.value);
                   onChange(event);
                }}
                predefinedValue={predefinedValue}
                readOnly={readOnly}
                value={currentValue}
             />
          </FieldBase>
       );
    };
    
    Main.displayName = 'Slider';
    
    export default Main;
    
  3. フォームフィールドモジュールを再展開します。 処理されたら(コンソールでSTOPPED → STARTED)、Liferayを再起動します。

    ./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    
    docker container restart $(docker ps -lq)
    
  4. フォームのスライダーフィールドを再度テストします。 今回は、フィールドのサイドバー設定の「詳細設定」タブで、最小値と最大値の設定を変えて試してみてください。

    MinとMaxの設定ができるようになりました。