English
Smart Form
About 2533 wordsAbout 8 min
2026-06-29
When the default display, interaction, or submission flow of a smart form is not enough for a business scenario, you can use JS scripts to add field handling, interaction control, business checks, and submission logic on top of the existing form capabilities.
Typical scenarios include:
- Dynamically adjusting the text, style, or visibility of other fields based on field values
- Listening to input, click, and selection events to add page interactions
- Adding business validation or adjusting submitted data before submission
- Running notifications or cleanup logic after submission results
Applicable Scenarios
This is suitable when the smart form can already handle basic data collection, but the default field behavior, page interaction, or submission flow is not enough and needs to be enhanced with JS scripts.
When to Use a Smart Form JS Script
If you run into the following requirements, smart form JS scripts are usually a good fit:
- You want to modify existing field values, text, styles, or visibility rules
- You want to control page behavior based on other field values
- You want to listen to interactions from buttons, inputs, and other page elements
- You want to add synchronous business validation or data processing after system validation passes and before the submit request is sent
- You want to run extra logic after submission succeeds, fails, or the page is destroyed
Development Approach
Smart form enhancement can usually be understood in three steps:
- Identify whether the enhancement targets a field, button, page view, or submission flow
- Choose standard DOM APIs or smart form lifecycle hooks as the extension method
- Write the script in the target form and verify that the extension does not break the original form flow
Development Workflow
Entry Steps
Go to the admin console and search for "Smart Form" in the left panel.
Click "Smart Form" in the search results to open the smart form list.
In the list, click "Edit" for an existing form, or click "New" in the upper-right corner to create one.
After entering the smart form editor, open "Global Settings" on the right.
In the "JS Script" section, click "Edit Script".
In the "JS Script" dialog, enter or paste the script content.
Click "OK" in the dialog to write the script back to the form config.
Go back to the form editor and click "Save" at the top of the page to save the current smart form.
Notes:
- After saving the script, verify the behavior in preview or in a real form page.
- If the script uses field selectors, prefer the field API Name mapped to
data-key. - If the script uses lifecycle hooks, make sure the current runtime already includes
window.smartForm.register. - Clicking "OK" in the dialog only writes the script into the current draft; the top-page "Save" is what persists it.
Clarify the Enhancement Goal
Before you start, confirm the following:
- Are you changing a field, a button, the page view, or the submission flow?
- Is the logic tied to the page DOM, field values, submission data, or API responses?
- Should the logic run after render, before submission, after submission, or when the page is destroyed?
Write the Enhancement Logic
During development, focus on the following:
- Use stable field API Names to locate elements instead of brittle DOM hierarchies
- Choose the correct execution timing and lifecycle hooks for the target behavior
- Keep conditions and business rules clear so the system validation and submission flow are not affected
- Handle asynchronous rendering, empty values, and script exceptions properly
Debug and Verify
- Validate page load, field interactions, and the main submission flow in a test form.
- Cover system validation failures, submission success, submission failure, and page destroy scenarios.
- DOM changes may happen after a page upgrade, so re-verify the dependent elements and events before going live.
- Script errors do not block the basic form display, but the faulty script will stop working.
- Do not store accounts, passwords, or keys in the script, and do not send customer-entered data to unapproved third-party addresses.
Smart Form Focus Areas
Field and Data Enhancement
Suitable for:
- Modifying field values, text, styles, or visibility
- Listening to field input, click, and selection events
- Handling simple linkage based on other field values
- Validating or adjusting submitted data before submission
Key points:
- Prefer
data-keyto locate elements - Field values on the page and values in the submitted payload are modified in different ways
- Check whether the target element is rendered only after asynchronous interaction
Button and Interaction Enhancement
The submit button can be found with name="button_submit":
var submitButton = document.querySelector('[name="button_submit"]');The reset button can be found with name="button_reset":
var resetButton = document.querySelector('[name="button_reset"]');Listen to submit button clicks:
var submitButton = document.querySelector('[name="button_submit"]');
if (submitButton) {
submitButton.addEventListener('click', function () {
console.log('The user clicked the submit button');
});
}The current filling page is not a standard native <form> submission. If you need to do lightweight checks before submission, prefer listening to the submit button click event.
If you only need logging or hints, do not call preventDefault() or stopPropagation(), otherwise the system validation and submission flow may be affected.
Example of a pre-submit hint:
var submitButton = document.querySelector('[name="button_submit"]');
if (submitButton) {
submitButton.addEventListener('click', function () {
var telInput = document.querySelector('[data-key="tel"] input');
if (telInput && telInput.value) {
console.log('About to submit, mobile number:', telInput.value);
}
});
}Key points:
- Check whether button behavior will affect the system validation and submission flow
- A button click and a successful submission are two different states
- Make sure user feedback is clear after the interaction happens
Page Behavior Enhancement
Suitable for:
- Running initialization logic after the basic form DOM is rendered
- Running notification logic after submission succeeds or fails
- Cleaning up script-bound events or timers when the page is destroyed
Key points:
- Make sure the extension logic is triggered at the correct time
- Make sure page behavior does not hurt the stability of the original form
- Handle asynchronous rendering, empty values, and exceptions properly
Appendix
Part 1: Extension Capability Details
Execution Timing
The script runs after the basic form DOM is rendered.
If the target element is rendered asynchronously, such as an address, location, attachment, or popup component, you can use a wait helper:
(function () {
function waitFor(selector, callback, timeout) {
var start = Date.now();
var timer = setInterval(function () {
var el = document.querySelector(selector);
if (el) {
clearInterval(timer);
callback(el);
} else if (Date.now() - start > (timeout || 5000)) {
clearInterval(timer);
}
}, 100);
}
waitFor('[data-key="tel"] input', function (input) {
input.placeholder = 'Please enter a mobile number';
});
})();Lifecycle Hook API
The smart form filling page exposes a global window.smartForm object. You can register form lifecycle hooks through register:
window.smartForm.register('my-hook', {
beforeSubmit: function (ctx) {},
submitSuccess: function (ctx) {},
submitError: function (ctx) {},
destroy: function (ctx) {}
});Rules for register(id, hooks):
idmust be a non-empty string.- If the same
idis registered more than once, the later one overrides the earlier one to avoid duplicate bindings. hooksonly recognizesbeforeSubmit,submitSuccess,submitError, anddestroy.registerreturns an unregister function.- Errors inside hook functions are isolated and do not block the basic form display, system validation, submission, payment, or error prompts.
Unregister example:
var unregister = window.smartForm.register('my-hook', {
submitSuccess: function () {
console.log('Submission succeeded');
}
});
unregister();No Ready Hook
The script already runs after the form body DOM is rendered, so there is no separate ready lifecycle.
If you only need to initialize DOM nodes, update helper text, or bind input events, you can write the logic directly in the top-level script or inside an IIFE:
(function () {
var nameField = document.querySelector('[data-key="name"]');
var nameInput = nameField && nameField.querySelector('input');
if (nameInput) {
nameInput.placeholder = 'Please enter the main attribute';
}
})();If the target element is a popup, attachment preview, location map, or another node that appears after interaction or asynchronously, still use waitFor.
Lifecycle Trigger Timing
| Lifecycle | Trigger timing | Can be blocked |
|---|---|---|
beforeSubmit | Triggered after system validation passes and before the submit request is sent | Yes |
submitSuccess | Triggered after the submit API returns code === 0 | No |
submitError | Triggered when the submit API returns a non-0 code or the request fails | No |
destroy | Triggered when the form page is unloaded or reset and destroyed | No |
Notes:
beforeSubmitruns after required-field and format validation passes. If system validation fails, for example because a required field is empty,beforeSubmitwill not run.submitSuccessandsubmitErrorare notification hooks. They do not change the original success page, payment redirect, error prompt, or captcha refresh behavior.destroyis good for cleaning up events, timers, or external state that the script binds towindowordocument.
ctx Context
Each lifecycle function receives a ctx object. ctx is a stable script context. It does not expose the React component instance or the full rc-form object.
Common fields:
| Field | Description |
|---|---|
ctx.cardId | Current form card ID |
ctx.root | Root DOM node of the current form |
ctx.describe | Current form description object |
ctx.fields | Field metadata map |
ctx.components | List of currently rendered fields |
ctx.buttons | Current button list |
ctx.data | Lifecycle-related data; in beforeSubmit, this is the payload to submit |
ctx.response | API response in submitSuccess / submitError |
Common methods:
| Method | Description |
|---|---|
ctx.getValue(apiName) | Read the current value of a field |
ctx.setValue(apiName, value) | Set the current value of a field |
ctx.getValues() | Read all current field values |
ctx.getField(apiName) | Get field metadata |
ctx.getFieldElement(apiName) | Get the outer DOM node by data-key |
Top-level script initialization does not receive ctx. If you need to work with the DOM, use standard DOM APIs directly.
beforeSubmit
beforeSubmit is used for synchronous checks, submission blocking, and modifying the payload before submission.
Blocking submission supports two return formats:
return false;or:
return {
cancel: true,
message: 'Please fill in the main attribute first'
};If message is provided, the page shows it.
The first version of beforeSubmit only supports synchronous returns. It does not wait for Promise, setTimeout, or async API results. If you need remote validation, do not write the API request so that the decision to submit depends on an async return. That kind of capability needs a separate design for waiting, loading, timeout, and duplicate submission handling.
Example of validating and modifying submitted data:
window.smartForm.register('before-submit-demo', {
beforeSubmit: function (ctx) {
if (!ctx.data.name) {
return {
cancel: true,
message: 'Please fill in the main attribute first'
};
}
ctx.data.name = String(ctx.data.name).trim() + '-hook';
}
});If you only want to change the field value on the page, use ctx.setValue(apiName, value). If you want to modify the data submitted to the API, update ctx.data directly.
submitSuccess, submitError, and destroy
Example for success, failure, and cleanup:
window.smartForm.register('submit-result-demo', {
submitSuccess: function (ctx) {
console.log('Submission succeeded:', ctx.response);
},
submitError: function (ctx) {
console.log('Submission failed:', ctx.response);
},
destroy: function () {
console.log('Form destroyed, clean up script events or timers');
}
});submitError covers both business errors and request failures. For business errors, you can usually get the API response. For request failures, ctx.response may be empty or only include low-level error information, so the script should handle null values on its own.
Full Verification Script
The following script can be used to verify registration, data modification before submission, submission success, submission failure, and destroy callbacks. The example field API Name uses name; replace it with the actual field data-key in your form.
(function () {
var HOOK_ID = 'verify-smart-form-hooks';
function log() {
var args = Array.prototype.slice.call(arguments);
console.log.apply(console, ['[smartForm hooks]'].concat(args));
}
var field = document.querySelector('[data-key="name"]');
log('top-level DOM check [data-key="name"]:', field);
window.smartForm.register(HOOK_ID, {
beforeSubmit: function (ctx) {
log('beforeSubmit data before:', JSON.stringify(ctx.data));
if (!ctx.data.name) {
return {
cancel: true,
message: 'Verification script: main attribute is empty, submission blocked'
};
}
ctx.data.name = String(ctx.data.name).trim() + '-hook';
log('beforeSubmit data after:', JSON.stringify(ctx.data));
},
submitSuccess: function (ctx) {
log('submitSuccess response:', ctx.response);
},
submitError: function (ctx) {
log('submitError response:', ctx.response);
},
destroy: function () {
log('destroy called');
}
});
})();Expected results:
- After the page loads, the DOM node for
[data-key="name"]should be logged, which means the script runs after the form body DOM is rendered. - If the required field is empty, the system required-field check runs first and
beforeSubmitdoes not run. - After the required field is filled and the form is submitted,
beforeSubmitruns and appends-hookto the submitted data. - When the submit API returns
code === 0,submitSuccessruns. - When the submit API returns a non-
0code or the request fails,submitErrorruns.
Field Selectors
Each field outer container provides the following data-* attributes:
<div
data-key="Field API Name"
data-label="Field display name"
data-type="Field type"
data-required="true/false"
data-readonly="true/false"
>
</div>Recommended priority:
- Recommended:
[data-key="tel"] - Available:
[data-type="text"],[data-required="true"] - Use with caution:
[data-label="Name"], because field renaming or multilingual settings may affect it - Not recommended: relying on complex DOM hierarchy, for example
div > div > input
Example:
var telField = document.querySelector('[data-key="tel"]');
var telInput = telField && telField.querySelector('input');Common Field Operations
Hide a field:
var company = document.querySelector('[data-key="company"]');
if (company) {
company.style.display = 'none';
}Modify the field title style:
var nameField = document.querySelector('[data-key="name"]');
if (nameField) {
var label = nameField.querySelector('.input-label');
if (label) {
label.style.color = '#d93026';
}
}Listen to input:
var telInput = document.querySelector('[data-key="tel"] input');
if (telInput) {
telInput.addEventListener('input', function () {
console.log('Current mobile number:', telInput.value);
});
}Set an input value:
function setInputValue(input, value) {
var descriptor = Object.getOwnPropertyDescriptor(input.__proto__, 'value');
descriptor.set.call(input, value);
input.dispatchEvent(new Event('input', { bubbles: true }));
input.dispatchEvent(new Event('change', { bubbles: true }));
}
var nameInput = document.querySelector('[data-key="name"] input');
if (nameInput) {
setInputValue(nameInput, 'John Smith');
}Field Linkage Example
Control whether the company field is shown based on whether the phone field is filled:
(function () {
var telInput = document.querySelector('[data-key="tel"] input');
var companyField = document.querySelector('[data-key="company"]');
if (!telInput || !companyField) {
return;
}
function updateCompanyVisible() {
companyField.style.display = telInput.value ? '' : 'none';
}
telInput.addEventListener('input', updateCompanyVisible);
updateCompanyVisible();
})();When the source field changes, update the sales lead detail prompt:
(function () {
var sourceField = document.querySelector('[data-key="source"]');
var remarkTextarea = document.querySelector('[data-key="remark"] textarea');
if (!sourceField || !remarkTextarea) {
return;
}
sourceField.addEventListener('click', function () {
remarkTextarea.placeholder = 'Please add sales lead details';
});
})();Part 2: CSP Security Policy
The smart form filling page configures the Content Security Policy through a meta tag:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-eval' https://webapi.amap.com; connect-src 'self' https://webapi.amap.com; img-src 'self' data: https:; style-src 'self' 'unsafe-inline';">This policy mainly restricts the following:
- Default resources can only be loaded from the current site:
default-src 'self' - Scripts can only be loaded from the current site and Amap scripts:
script-src 'self' 'unsafe-eval' https://webapi.amap.com - Network requests can only be sent to the current site and Amap APIs:
connect-src 'self' https://webapi.amap.com - Images can use the current site,
data:images, and HTTPS images:img-src 'self' data: https: - Styles can use current-site styles and inline styles:
style-src 'self' 'unsafe-inline'
Impact on user scripts:
- You can operate the current page DOM.
- You cannot use
fetch,XMLHttpRequest, or similar methods to request unauthorized third-party APIs. - You cannot load unauthorized third-party JS files.
- You can set inline styles, for example
element.style.display = 'none'. - You can use HTTPS images or
data:images. - If the script triggers a CSP restriction, the browser blocks the corresponding behavior.
