カスタムフォーム項目タイプの書き込み
フォームアプリケーションには、高度に設定可能な フィールドタイプが標準で多く含まれています。 既存のフィールドタイプのいずれかを使えば、ほとんどのユースケースに対応できます。 デフォルトのフィールドタイプでユースケースに対応できない場合、独自のフィールドタイプを作成することができます。
-
その他のアプリケーションにおけるフォームフィールドタイプ: ドキュメントとメディア(メタデータセット)、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 。
http://localhost:8080でLiferayへのサインインします。 メールアドレス test@liferay.com とパスワード test を使用してください。 プロンプトが表示されたら、パスワードを learn に変更します。
次に、以下の手順に従います。
-
カスタムフォームフィールドタイプのプロジェクトをダウンロードし、解凍します。
curl https://resources.learn.liferay.com/dxp/latest/en/process-automation/forms/developer-guide/liferay-c2p9.zip -O
unzip liferay-c2p9.zip
-
モジュールのルートから、ビルドおよびデプロイします。
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
tipこのコマンドは、デプロイされたjarをDockerコンテナの/opt/liferay/osgi/modulesにコピーするのと同じです。
noteLiferay 7.3 の場合、デプロイする前にプロジェクトに以下の調整を加えてください。
- c2p9-impl/package.json
で、
devDependenciesの参照を
@liferay/portal-7.4から
@liferay/portal-7.3` に変更します。 gradle.properties
でliferay.workspace.product
の値をportal-7.3-ga8
に変更します (GA8 より新しい Liferay 7.3 バージョンがある場合は、代わりにここを参照してみてください)。
- c2p9-impl/package.json
-
Liferay Dockerコンテナコンソールでデプロイを確認します。
STARTED com.acme.c2p9.impl_1.0.0 [1009]
デプロイされたスライダーフィールドを使用する
-
ブラウザでhttp://localhost:8080を開きます。
-
[サイトメニュー] → [コンテンツ & データ] → [フォーム] のフォームアプリケーションに移動します。
-
追加 ボタン()をクリックして、フォームビルダーを開きます。
-
フォームに C2P9 Slider フィールドを追加します。
-
ラベル、初期値、ヘルプテキストを記入し、フィールドを必須とすることもできます。 これらの設定は、多くの デフォルトのフィールド が基本設定として提供するものと一致します。
-
フォームを公開し、スライダーフィールドを使用してレコードを送信します。
フォームフィールドのコードを理解する
基本的なフォームフィールドは、JavaクラスとJavaScriptファイルから構成されています。 C2P9スライダーフィールドでは、抽象クラス BaseDDMFormFieldType
を拡張してOSGiコンポーネントでそのメタデータを定義することで、C2P9DDMFormFieldType.java
がDDMFormFieldType
の実装を提供します。
@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ロジックを指定します。 Main
とSlider
の2つのコンポーネントがファイルに定義されています。
インポートステートメントは、Liferayの基本フォームフィールドであるdynamic-data-mapping-form-field-type
の機能を取り込みます。 これらは、宣言された変数 FieldBase
とuseSyncValue
を使って後で呼び出されます。
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
および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>
タグを定義します。 重要なのは、ユーザーが選択できるmax
とmin
の値は、現在ハードコードされていることです。 これは、 後ほど変更します 。 フィールドの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コンポーネントに送信し、エンドユーザーに表示します。
-
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(); }
-
各設定には、
label
とplaceholder
の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.
-
getDDMFormFieldTypeSettings
メソッドを追加/オーバーライドすることにより、DDMFormFieldType
クラスを更新します。@Override public Class<? extends DDMFormFieldTypeSettings> getDDMFormFieldTypeSettings() { return C2P9DDMFormFieldTypeSettings.class; }
フロントエンドでのカスタム設定に対応
フロントエンドでは、ユーザーが入力する min と max の値に対応するためにSlider.es.js
を更新し、フロントエンドがバックエンドから設定値を受け取れるように DDMTemplateContextContributor
を追加する必要があります。
-
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; } }
-
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;
-
フォームフィールドモジュールを再デプロイします。 処理が完了したら(コンソールでSTOPPED → STARTED)、Liferayを再起動します。
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
docker container restart $(docker ps -lq)
-
フォームのスライダーフィールドを再度テストします。 今回は、フィールドのサイドバー設定の[詳細設定]タブで、最小値と最大値の設定を変えて試してみてください。