| name | ewa-form |
| description | Use when: 编写 EWA 表单前端 JS 代码、表单提交与验证、表单与列表联动、对话框中表单操作、动态字段控制、合并单元格、分组向导。按任务组织,含完整代码示例。 |
| trigger | ewa-form, EWA form, 表单提交, DoPostBefore, doPostAfter, setMust, CheckValid, DoAction, RecordNew, RecordModify, EWA.OW, 表单验证, 表单联动, 对话框表单, EWA_FrameClass |
EWA Form 操作指南
面向前端 JS 开发者的 EWA 表单操作参考。按任务组织,每个场景给完整可用的代码。
ewa 变量 = EWA.F.FOS['@SYS_FRAME_UNID'] — 当前帧实例。@SYS_FRAME_UNID 是服务端替换的占位符,运行时为实际帧 ID 字符串。
参考示例
示例配置在缓存目录 /Users/admin/java/ewa_page_cached_pf2023/scripts_cached/examples/:
index.xml # 首页列表
member_card.xml # 会员卡(Frame 表单)
product_cat.xml # 产品分类(Tree + Form)
sysatts.xml # 文件附件
自动触发:当用户要求编写 Form 表单相关代码时,先读取示例参考实际用法:
read_file /Users/admin/java/ewa_page_cached_pf2023/scripts_cached/examples/member_card.xml
框架文档参考
遇到 Frame 表单配置、Action/SqlSet 执行流程等概念不确定时,读取框架文档获取权威解释:
| 文档 | 说明 |
|---|
framework/emp-script/docs/zhcn/FRAME_EXECUTION.md | Frame 表单执行流程(新增/修改/复制/按钮渲染) |
framework/emp-script/docs/zhcn/FRAME_CALLS.md | Frame 各类型调用方式详解 |
framework/emp-script/docs/zhcn/EWA_TEMPLATE_REFERENCE.md | XML 模板属性完整参考(Frame/Set) |
自动触发:当对 Frame 属性、Action 类型、表单提交流程等概念不确定时,先 read_file 对应框架文档再操作。
速查表
| 任务 | 方法 | 优先级 |
|---|
| 🔥 表单提交前验证 | ewa.DoPostBefore | 高频 |
| 🔥 表单提交后回调 | ewa.doPostAfter | 高频 |
| 🔥 调用后端 Action | ewa.DoAction() | 高频 |
| 🔥 打开新建对话框 | ewa.RecordNew() | 高频 |
| 🔥 打开修改对话框 | ewa.RecordModify() | 高频 |
| 🔥 刷新父列表 | EWA.OW.Frame.Reload() | 高频 |
| 📋 动态设置必填 | ewa.setMust() / ewa.setUnMust() | 中频 |
| 📋 合并单元格 | ewa.Merge() / ewa.MergeExp() | 中频 |
| 📋 分组 Tab 切换 | ewa.GroupShow() | 中频 |
| 📋 下拉框刷新 | ewa.itemReload() | 中频 |
| 🔧 向导分步表单 | ewa.GuideShowCreate() | 低频 |
| 🔧 开关按钮回调 | ewa.extSwitchCallBack | 低频 |
1. 表单生命周期
完整提交链路
用户点击提交
→ ewa.DoPostBefore() ← 返回 false 阻止提交
→ 内置验证 (CheckValidAll)
→ 触发验证 (滑块/验证码)
→ DoPostStart(ajax) ← Ajax 发出前
→ Ajax POST
→ DoPostEnd(ajax, status, responseText)
→ ewa.doPostAfter(ret) ← 返回 true 阻止默认 eval(ret)
→ EWA_PostBehavior 执行 ← RELOAD_PARENT / CLOSE_SELF 等
DoPostBefore — 提交前验证
(function(){
var ewa = EWA.F.FOS['@SYS_FRAME_UNID'];
ewa.DoPostBefore = function(){
if (ewa._submitting) {
$Tip("提交中...");
return false;
}
var money = getObj('#MONEY input').val();
if (parseFloat(money) > 100000) {
$Confirm("金额超过 10 万,确认提交?", "确认", function(){
ewa._submitting = true;
ewa.DoPost();
});
return false;
}
return true;
};
})();
GOTCHA — 异步预检查模式: DoPostBefore 可返回数组 [result, tipMsg, useConfirm],框架会以 232ms 轮询直到 result 非 null:
ewa.DoPostBefore = function(){
if (!window._uploadDone) {
return [null, "文件上传中...", false];
}
if (window._uploadError) {
return [false, "上传失败", false];
}
return [true];
};
DoPostStart — Ajax 发出前
ewa.DoPostStart = function(ajax){
ajax.AddParameter("customFlag", "1");
};
DoPostEnd — Ajax 响应返回后(行为执行前)
ewa.DoPostEnd = function(ajax, status, responseText, statusText){
if (status === 200) {
$Tip("服务器响应成功");
}
};
doPostAfter — 提交后回调(替代已废弃的 ReloadAfter)
ewa.doPostAfter = function(ret){
if (ret.indexOf("success") > -1) {
$Tip("操作成功");
if (EWA.OW && EWA.OW.Close) {
EWA.OW.Close();
}
if (EWA.OW && EWA.OW.Frame) {
EWA.OW.Frame.Reload();
}
return true;
}
return false;
};
doPostAfter vs ReloadAfter:doPostAfter 是当前推荐名称。ReloadAfter 是旧名称,框架仍兼容但不再推荐。
ret 参数内容:后端 SQL 返回 EWA_ERR_OUT 时,框架生成 EWA.UI.Msg.ShowError("错误信息", "标题"); 作为 ret 的内容。常见错误做法是不检查 ret 直接刷新父帧,导致报错后父列表仍然刷新。
ewa.doPostAfter = function(ret) {
if (ret && ret.indexOf && (ret.indexOf("ShowError") >= 0 || ret.indexOf("EWA_ERR") >= 0)) {
return;
}
if ("@from_pid" && EWA.F.FOS["@from_pid"]) {
EWA.F.FOS["@from_pid"].Reload();
}
};
2. 表单字段操作
取值与赋值
function getObj(exp){
return exp ? $('#EWA_FRAME_@SYS_FRAME_UNID').find(exp) : $('#EWA_FRAME_@SYS_FRAME_UNID');
}
var name = getObj('#FIELD_NAME input').val();
getObj('#FIELD_NAME input').val("新值");
var selected = getObj('#FIELD_ID option:selected').val();
注意:如果是在 ListFrame 中操作,选择器前缀应改为 #EWA_LF_@SYS_FRAME_UNID。@SYS_FRAME_UNID 是服务端替换的占位符,运行时为实际帧 ID 字符串。
动态设置必填 / 非必填
ewa.setMust("FIELD_NAME");
ewa.setUnMust("FIELD_NAME");
启用 / 禁用所有控件
ewa.setDisable();
ewa.setEnable();
刷新下拉框选项
ewa.itemReload("DROP_LIST_ID", "default_value", function(){
});
ewa.itemReload("DROP_LIST_ID", "", "afterChangeEvent()");
创建 A-Z 字母筛选下拉
ewa.convertFilterCheckbox(
"checkbox_container_id",
"filter_container_id",
"PY",
true,
function(){ },
function(){ }
);
ewa.createFilterCheckbox(
"checkbox_target_id",
"filter_target_id",
"val1,val2",
"/ewa?XMLNAME=xxx&ITEMNAME=yyy&EWA_AJAX=JSON",
"id", "name", "py"
);
3. 表单 + 列表联动
打开新建记录对话框
ewa.RecordNew("@xmlName", "ITEM.F.N", "extra_param1=v1&extra_param2=v2");
打开修改选中记录对话框
ewa.RecordModify("@xmlName", "ITEM.F.M", "extra_param1=v1");
对话框内表单 — 关闭并刷新父列表
EWA.OW.Load();
EWA.OW.Close();
EWA.OW.Load();
EWA.OW.PWin.EWA.F.FOS['parent_frame_unid'].Reload();
EWA.OW.Close();
GOTCHA:必须先在对话框内的 JS 中调用 EWA.OW.Load(),否则 EWA.OW.Frame 等为 null。
行为链(Behavior Chain)
提交后自动执行一系列操作,通过 URL 参数 EWA_P_BEHAVIOR 设置:
EWA_P_BEHAVIOR=RELOAD_PARENT,CLOSE_SELF
EWA_P_BEHAVIOR=RELOAD_PARENT,CLEAR_SELF
EWA_P_BEHAVIOR=CLOSE_SELF
var u = ewa.getUrlClass();
u.AddParameter("EWA_P_BEHAVIOR", "RELOAD_PARENT,CLOSE_SELF");
u.AddParameter("EWA_PARENT_FRAME", "@SYS_FRAME_UNID");
ewa.Reload(u.GetUrl());
4. 表单验证
内置验证类型
在 XML <XItem> 的 <DataItem> 中配置:
<DataItem><Set DataField="EMAIL" DataType="String" Valid="Email"/></DataItem>
<DataItem><Set DataField="AGE" DataType="Int" Valid="Number"/></DataItem>
<DataItem><Set DataField="CODE" DataType="String" Valid="required"/></DataItem>
<DataItem><Set DataField="PHONE" DataType="String" Valid="^1[3-9]\d{9}$"/></DataItem>
| Valid 值 | 含义 |
|---|
required | 必填 |
Email | 邮箱格式 |
Number | 数字 |
| 正则表达式 | 自定义正则(如 ^1[3-9]\d{9}$) |
全部字段验证
if (!ewa.CheckValidAll()) {
$Tip("请检查必填字段");
return;
}
单个字段验证
var field = getObj('#FIELD_NAME input')[0];
if (!ewa.CheckValid(field)) {
}
滑块验证(Captcha)
XML 中配置 TriggerValid 的字段会触发滑块验证:
ewa.callTriggerValid(getObj('#VALID_CODE input')[0]);
扩展验证(服务端验证)
ewa.DoValidEx(
getObj('#FIELD_NAME input')[0],
"action",
"checkNameExists",
"CheckNameAction",
"名称可用",
"名称已存在"
);
5. 合并单元格
简单合并
ewa.Merge("FROM_FIELD_ID", "TO_FIELD_ID");
表达式合并
var exp = "@@DEPT x @PERSON = @@RESULT (@DATE)";
ewa.MergeExp("RESULT_FIELD_ID", exp);
ewa.merges("RESULT_FIELD_ID", ["FIELD_A", "FIELD_B", "FIELD_C"], true);
表达式中:
@@FIELD_ID — 匹配字段值
@FIELD_ID — 同上(单 @ 也行)
- 其他文本原样输出
6. 分组与向导
分组 Tab 切换
将表单字段按 groupIndex 分成多组,点击切换显示:
ewa.GroupShowBefore = function(obj, grpIdx){
};
ewa.GroupShowAfter = function(obj, grpIdx){
$Tip("已切换到第 " + (grpIdx + 1) + " 组");
};
XML 中通过 <GroupIndex> 元素设置字段所属组。
向导式分步表单
ewa.GuideShowCreate([
{ DES: "第一步:填写基本信息" },
{ DES: "第二步:填写详细信息" },
{ DES: "第三步:确认提交" }
]);
ewa.GuideShowCheck = function(idx){
return ewa.CheckValidAll();
};
7. 对话框中的表单
EWA.OW 完整用法
(function(){
EWA.OW.Load();
var parentFrame = EWA.OW.Frame;
var parentWin = EWA.OW.PWin;
var dialog = EWA.OW.Dia;
ewa.doPostAfter = function(ret){
if (ret.indexOf("success") > -1) {
parentFrame.Reload();
EWA.OW.Close();
return true;
}
return false;
};
})();
对话框内获取父帧数据
EWA.OW.Load();
var parentEwa = EWA.OW.Frame;
var parentUrl = parentEwa.getUrlClass();
var mtype = parentUrl.GetParameter("EWA_MTYPE");
var outParams = parentEwa.outParams;
关闭对话框
EWA.OW.Load();
EWA.OW.Close();
if (window._EWA_DialogWnd) {
window._EWA_DialogWnd.CloseWindow();
}
8. DoAction — 调用后端 Action
简单调用
ewa.DoAction(this, "OnFrameDelete");
带确认消息和回调
ewa.DoAction(
this,
"UAct0",
"DeleteConfirm",
"操作成功",
[
{ Name: "targetId", Value: "123" }
],
function(){
$Tip("删除完成");
ewa.Reload();
}
);
JSON 返回方式(不刷新页面)
ewa.DoActionJSON(
"SAct0",
"resultJson",
[
{ Name: "id", Value: "456" }
],
function(json){
$Tip("查询到 " + json.count + " 条记录");
}
);
简单 JSON 加载
ewa.LoadJson("GetStats", function(json){
getObj('#TOTAL_COUNT').text(json.total);
});
9. 开关按钮(Switch Button)
XML 中 <Tag Tag="switch"/> 的控件:
ewa.extSwitchCallBack = function(source, rst){
if (rst.indexOf("true") > -1) {
$Tip("状态切换成功");
} else {
$Tip("切换失败");
source.checked = !source.checked;
}
};
10. 隐藏无内容行
ewa.hiddenNoContentRow();
11. Memo 合并
ewa.MergeMemo();
12. 重写 Info/Memo 行
var data = [
{ id: "1", info: "审批通过", memo: "同意" },
{ id: "2", info: "驳回", memo: "需要修改" }
];
var trs = ewa.RewriteInfo(
JSON.stringify(data),
"id",
"info",
"memo",
function(tr, entry, index){
tr.style.color = entry.info === "驳回" ? "red" : "";
}
);
常见陷阱
| 陷阱 | 解决 |
|---|
@SYS_FRAME_UNID 在 JS 中是什么 | 是服务端替换的占位符,运行时是具体帧 ID 字符串(如 ewa_frame_abc123) |
doPostAfter 返回什么阻止默认行为 | 返回 true 会阻止后续的 eval(ret) |
ReloadAfter 和 doPostAfter 用哪个 | 用 doPostAfter。ReloadAfter 是旧名,仅作为兼容回退 |
| 表单提交无响应 | 检查 DoPostBefore 是否返回了 false |
对话框内 EWA.OW.Frame 为 null | 必须先调用 EWA.OW.Load() 初始化 |
setMust 无效 | 字段名不区分大小写,但必须匹配 XML 中定义的 XItem Name |
| 重复提交 | 框架有 ewa.posting 防重标记,但自定义 AJAX 需自行处理 |
Mearge 拼写 | 源码中 Mearge 是 Merge 的废弃别名,会打印警告,勿用 |
| 对话框传参带入了错误的 XMLNAME/ITEMNAME | 调用 getUrlClass() 获取 URL 后,先 u1.RemoveEwa() 清除 EWA 框架参数(XMLNAME、ITEMNAME 等),再 AddParameter() 添加新参数 |
13. EWA_ URL 参数速查
高频实用
| 参数 | 说明 | 示例 |
|---|
EWA_IN_DIALOG | 1 = 固定高度窗口打开,内容自适应滚动 | u1.AddParameter("EWA_IN_DIALOG", "1") |
EWA_P_BEHAVIOR | 行为链:RELOAD_PARENT,CLOSE_SELF | EWA_P_BEHAVIOR=RELOAD_PARENT,CLOSE_SELF |
EWA_PARENT_FRAME | 父帧 UNID,配合行为链使用 | EWA_PARENT_FRAME=@SYS_FRAME_UNID |
EWA_NO_CONTENT | 1 = 仅执行不输出内容 | 用于纯后端操作 |
EWA_LANG | 语言切换:zhcn/enus,会保留到 session | EWA_LANG=enus |
少用但好用
| 参数 | 说明 | 示例 |
|---|
EWA_HIDDEN_FIELDS | 按条件隐藏字段,在 <LogicShow> 中配置 | <Set HiddenFields="FIELD_A" Name="rule" ParaExp="'@MODE'='VIEW'"/> |
EWA_FRAME_UNID_PREFIX | 更改帧 UNID 前缀,避免同页面多个帧冲突 | EWA_FRAME_UNID_PREFIX=my_prefix_ |
EWA_FRAMESET_NO | 1 = 不显示 frame 框架 | EWA_FRAMESET_NO=1 |
EWA_WIDTH / EWA_HEIGHT | 覆盖帧尺寸 | EWA_WIDTH=900&EWA_HEIGHT=600 |