Chuyển đến nội dung chính

Gửi một biểu mẫu với loại trường thực thể (trang, sản phẩm...)

Trong ví dụ này, chúng tôi sẽ trình bày cách gửi một biểu mẫu bao gồm loại trường thực thể, chẳng hạn như trang hoặc sản phẩm, sử dụng API OneEntry.

✅ Mục đích của kịch bản:

  • Lấy cấu hình biểu mẫu từ Nền tảng OneEntry
  • Người dùng chọn một trong các phần tử của thực thể
  • Gửi dữ liệu đã thu thập đến API OneEntry.

✅ Những gì bạn cần:

  • Một PROJECT_URL và APP_TOKEN hợp lệ để xác thực với API OneEntry.
  • Một biểu mẫu đã được cấu hình trước trong OneEntry với một dấu hiệu (ví dụ: thực thể) và các trường bao gồm một loại "thực thể".
  • Các trường biểu mẫu đã được cấu hình trước bao gồm một loại "thực thể".

📌 Quan trọng:

  • Những ví dụ này không bao gồm xử lý lỗi.
  • Bạn có thể quản lý lỗi bằng cách sử dụng khối try-catch hoặc bằng cách sử dụng một cấu trúc như await Promise.catch((error) => error).

📚 Xem trong tài liệu:

📦 Tham khảo SDK:

Thử nghiệm trực tiếp

Chạy phương pháp này một cách tương tác trong JS SDK sandbox — kết nối URL Dự án và Mã thông báo Ứng dụng của bạn khi truy cập lần đầu, sau đó mở:

Kịch bản

1. Nhập defineOneEntry từ SDK và định nghĩa PROJECT_URL và APP_TOKEN

Ví dụ:

import { defineOneEntry } from 'oneentry';

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

2. Tạo một khách hàng API với defineOneEntry()

Ví dụ:

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

3. Lấy biểu mẫu với Forms.getFormByMarker()

Ví dụ:

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. Lấy các cài đặt bổ sung cho việc gửi biểu mẫu

Ví dụ:

const moduleFormConfig = form.moduleFormConfigs?.[0];
if (!moduleFormConfig) {
setErrorMsg('Form has no moduleFormConfigs');
setStatus('error');
return;
}
Kết quả:
{
"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. Lấy dữ liệu trường từ biểu mẫu frontend — chọn một tùy chọn thực thể cho mỗi trường kiểu thực thể (lựa chọn của người dùng từ danh sách chọn đã hiển thị)

Ví dụ:

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] || ''),
}));
Kết quả:
[
{
"marker": "entity",
"type": "entity",
"value": [
"p-2-7"
]
}
]

6. Đăng FormsData với FormData.postFormsData()

Ví dụ:

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);
Kết quả:
{
"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": ""
}

Ví dụ cuối cùng

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;