oo

カスタムフォーム項目タイプの書き込み

フォームアプリケーションには、高度に設定可能な フィールドタイプが標準で多く含まれています。 既存のフィールドタイプのいずれかを使えば、ほとんどのユースケースに対応できます。 デフォルトのフィールドタイプでユースケースに対応できない場合、独自のフィールドタイプを作成することができます。

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

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

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

    Liferay 7.2をお使いの場合、サポートされるフロントエンドフレームワークの違いにより、このソースコードは実行されません。 C2P9スライダーのコードサンプルを7.2用に適合させる方法については、 Liferay 7.2のカスタムフォーム項目の開発を参照してください。

Liferay のカスタムフォームフィールドを調べる

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

例をデプロイする

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

docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.112-ga112。

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

次に、以下の手順に従います。

  1. カスタムフォームフィールドタイプのプロジェクトをダウンロードし、解凍します。

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

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

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

    note

    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スライダーフィールドでは、抽象クラス BaseDDMFormFieldTypeを拡張してOSGiコンポーネントでそのメタデータを定義することで、C2P9DDMFormFieldType.javaDDMFormFieldTypeの実装を提供します。

@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アイコン を選択します。

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宣言とscriptsセクションで定義されたsource-mapsをご覧ください)。

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

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

isCustomDDMFormFieldTypeは内部で使用されます。 getModuleNameメソッドでNPMResolver.resolveModuleName()の結果を返している場合は、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 =ブロックはフィールドを定義し、パラメーターnameonChangepredefinedValuereadOnlyおよび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の値は、現在ハードコードされていることです。 これは、 後ほど変更します 。 フィールドのvalueは三項演算子を用いて定義されており、値が入力されていれば、それを使用します。 それ以外の場合は、初期値を使用します。

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. 各設定には、labelplaceholderの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. getDDMFormFieldTypeSettingsメソッドを追加/オーバーライドすることにより、DDMFormFieldTypeクラスを更新します。

    @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の設定ができるようになりました。

Capability:
Feature: