Lewati ke konten utama

Mengirimkan formulir dengan tipe field entitas (halaman, produk...)

Dalam contoh ini, kami menunjukkan cara mengirimkan formulir yang mencakup tipe field entitas, seperti halaman atau produk, menggunakan API OneEntry.

✅ Tujuan skenario:

  • Mendapatkan konfigurasi formulir dari Platform OneEntry
  • Pengguna memilih salah satu elemen dari entitas
  • Mengirimkan data yang dikumpulkan ke API OneEntry.

✅ Apa yang Anda butuhkan:

  • PROJECT_URL dan APP_TOKEN yang valid untuk otentikasi dengan API OneEntry.
  • Formulir yang telah dikonfigurasi sebelumnya di OneEntry dengan penanda (misalnya, entitas) dan field termasuk salah satu dari tipe "entitas".
  • Field formulir yang telah dikonfigurasi sebelumnya termasuk salah satu dari tipe "entitas".

📌 Penting:

  • Contoh-contoh ini tidak mencakup penanganan kesalahan.
  • Anda dapat mengelola kesalahan menggunakan blok try-catch atau dengan menggunakan konstruksi seperti await Promise.catch((error) => error).

📚 Lihat di dokumentasi:

📦 Referensi SDK:

Coba secara langsung

Jalankan metode ini secara interaktif di JS SDK sandbox — sambungkan Project URL dan App Token Anda pada kunjungan pertama, lalu buka:

Skenario

1. Impor defineOneEntry dari SDK dan definisikan PROJECT_URL dan APP_TOKEN

Contoh:

import { defineOneEntry } from 'oneentry';

const PROJECT_URL = 'your-project-url';
const APP_TOKEN = 'your-app-token';

2. Membuat klien API dengan defineOneEntry()

Contoh:

const { Forms, FormData } = defineOneEntry(PROJECT_URL, {
token: APP_TOKEN,
});

3. Mendapatkan formulir dengan Forms.getFormByMarker()

Contoh:

useEffect(() => {
Forms.getFormByMarker('entity').then((data: any) => {
setForm(data);
const initial: Record<string, string> = {};
data?.attributes?.forEach((a: any) => { initial[a.marker] = ''; });
setValues(initial);

console.log('Form Entity ', data);
}).catch(console.error);
}, []);

if (!form) return <div>Loading...</div>;

const sortedFields = [...(form.attributes || [])].sort(
(a: any, b: any) => a.position - b.position,
);

const handleSubmit = async (e: any) => {
e.preventDefault();
if (!form) return;
setStatus('loading');

4. Mendapatkan pengaturan tambahan untuk pengiriman formulir

Contoh:

const moduleFormConfig = form.moduleFormConfigs?.[0];
if (!moduleFormConfig) {
setErrorMsg('Form has no moduleFormConfigs');
setStatus('error');
return;
}
Hasil:
{
"id": 1,
"moduleIdentifier": "content",
"isGlobal": false,
"isClosed": false,
"viewOnlyUserData": false,
"commentOnlyUserData": false,
"entityIdentifiers": [
{
"id": "services",
"isNested": false
}
],
"ratingCalculation": "average",
"allowHalfRatings": null,
"maxRatingScale": null,
"isAnonymous": null,
"allowRerating": null,
"isRating": null
}

5. Mendapatkan data field dari formulir frontend — pilih satu opsi entitas per field bertipe entitas (pilihan pengguna dari select yang dirender)

Contoh:

const fieldsData = sortedFields
.filter((f: any) => values[f.marker])
.map((f: any) => ({
marker: f.marker,
type: f.type,
value: prepareValue(f.type, values[f.marker] || ''),
}));
Hasil:
[
{
"marker": "entity",
"type": "entity",
"value": [
"p-2-7"
]
}
]

6. kirim FormsData dengan FormData.postFormsData()

Contoh:

const response = await FormData.postFormsData({
formIdentifier: 'entity',
formData: fieldsData,
formModuleConfigId: moduleFormConfig.id,
moduleEntityIdentifier: moduleFormConfig.entityIdentifiers?.[0]?.id || '',
replayTo: null,
status: 'sent',
}).catch((e: any) => e);
Hasil:
{
"formData": {
"formIdentifier": "entity",
"time": "2026-06-06T10:21:42.166Z",
"formData": [
{
"marker": "entity",
"type": "entity",
"value": [
"p-2-7"
]
}
],
"entityIdentifier": "services",
"fingerprint": "UQ_zhfcsr_mpdtr691jq7d",
"isUserAdmin": false,
"formModuleId": 1,
"userIdentifier": null,
"parentId": null,
"id": 174
},
"actionMessage": ""
}

Contoh akhir

import React from 'react';

// Note: React is a sandbox global — in your project use named imports from 'react'
const { useState, useEffect } = React;

// 1. Import defineOneEntry from SDK and define PROJECT_URL and APP_TOKEN
import { defineOneEntry } from 'oneentry';

const PROJECT_URL = 'your-project-url';
const APP_TOKEN = 'your-app-token';

// 2. Creating an API client with [defineOneEntry()](/docs/index/#Installation)
const { Forms, FormData } = defineOneEntry(PROJECT_URL, {
token: APP_TOKEN,
});

// Prepare value for API submission by field type.
function prepareValue(type: string, value: string) {
if (type === 'text') return [{ plainValue: value }];
if (type === 'list' || type === 'radioButton') return [value];
if (type === 'entity') return [/^\d+$/.test(value) ? Number(value) : value];
return value;
}

const EntityForm = () => {
const [form, setForm] = useState<any>(null);
const [values, setValues] = useState<Record<string, string>>({});
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
const [errorMsg, setErrorMsg] = useState('');

// 3. Get form with [Forms.getFormByMarker()](/docs/forms/getFormByMarker)
useEffect(() => {
Forms.getFormByMarker('entity').then((data: any) => {
setForm(data);
const initial: Record<string, string> = {};
data?.attributes?.forEach((a: any) => { initial[a.marker] = ''; });
setValues(initial);

console.log('Form Entity ', data);
}).catch(console.error);
}, []);

if (!form) return <div>Loading...</div>;

const sortedFields = [...(form.attributes || [])].sort(
(a: any, b: any) => a.position - b.position,
);

const handleSubmit = async (e: any) => {
e.preventDefault();
if (!form) return;
setStatus('loading');

// 4. Get additional settings for the form submission
const moduleFormConfig = form.moduleFormConfigs?.[0];
if (!moduleFormConfig) {
setErrorMsg('Form has no moduleFormConfigs');
setStatus('error');
return;
}

// 5. Get fields data from the frontend form — pick one entity option per entity-typed field (the user's selection from the rendered select)
const fieldsData = sortedFields
.filter((f: any) => values[f.marker])
.map((f: any) => ({
marker: f.marker,
type: f.type,
value: prepareValue(f.type, values[f.marker] || ''),
}));

// 6. post FormsData with [FormData.postFormsData()](/docs/forms-data/postFormsData)
const response = await FormData.postFormsData({
formIdentifier: 'entity',
formData: fieldsData,
formModuleConfigId: moduleFormConfig.id,
moduleEntityIdentifier: moduleFormConfig.entityIdentifiers?.[0]?.id || '',
replayTo: null,
status: 'sent',
}).catch((e: any) => e);

if (response?.statusCode >= 400) {
setErrorMsg(response.message || 'Submission failed');
setStatus('error');
} else {
setStatus('success');
console.log('Submit response: ', response);
}
};

return (
<form onSubmit={handleSubmit}>
<h2>{form.localizeInfos?.title || 'Entity Form'}</h2>

{sortedFields.map((field: any) => {
const label = field.localizeInfos?.title || field.marker;
const value = values[field.marker] || '';
const required = !!field.validators?.requiredValidator?.strict;
const placeholder = field.additionalFields?.placeholder?.value || '';
const onChange = (val: string) =>
setValues((prev) => ({ ...prev, [field.marker]: val }));

if (field.type === 'entity') {
const options = field.listTitles || [];
if (options.length > 0) {
return (
<div key={field.marker}>
<label htmlFor={field.marker}>{label}</label>
<select
id={field.marker}
value={value}
required={required}
onChange={(e: { target: { value: string; }; }) => onChange(e.target.value)}
>
<option value="">— Select —</option>
{options.map((opt: any) => {
// For entity fields, listTitles[].value is an object ({ id, depth, ... }),
// so use its primitive `id` for the key/value (a page id like 25 or product like "p-1-123").
const optValue = opt.value && typeof opt.value === 'object' ? opt.value.id : opt.value;
return (
<option key={optValue} value={optValue}>{opt.title}</option>
);
})}
</select>
</div>
);
}
return (
<div key={field.marker}>
<label htmlFor={field.marker}>{label}</label>
<input
id={field.marker}
type="text"
value={value}
placeholder={placeholder || 'Page id (e.g. 25) or product (e.g. p-1-123)'}
required={required}
onChange={(e: { target: { value: string; }; }) => onChange(e.target.value)}
/>
</div>
);
}

return (
<div key={field.marker}>
<label htmlFor={field.marker}>{label}</label>
<input
id={field.marker}
type="text"
value={value}
placeholder={placeholder}
required={required}
onChange={(e: { target: { value: string; }; }) => onChange(e.target.value)}
/>
</div>
);
})}

{status === 'error' && <p role="alert">{errorMsg}</p>}
{status === 'success' && <p role="status">Form submitted successfully!</p>}

<button type="submit" disabled={status === 'loading'}>
{status === 'loading' ? 'Submitting...' : 'Submit'}
</button>
</form>
);
};

export default EntityForm;