BroFramework 中集成了 JQuery UI,因此,我们通常采用其 dialog 组件来开发 AJAX 表单。
对于多数 AJAX 表单来说,基本流程如下:
- 创建一个 dialog,并初始化大小、按钮等属性,多数情况下,仅包含“确定”、“关闭”两个按钮
- 加载一个 AJAX 表单,加载完成后显示 dialog
- 触发确定按钮后,执行 ajax 提交并回显
如下面的两个例子所示:
/**
* 示例1:AJAX 表单提交
*/
function createFolder(url) {
var id = "dlgCmsCreateFolder";
var dlg = $j("#"+id);
if ( dlg.length == 0 ) {
$j("<div id='"+id+"' class='body'></div>").appendTo("body");
dlg = $j("#"+id);
dlg.dialog({
autoOpen:false, modal:true, title:"创建文件夹", width:420, resizable:false,
buttons: {
"提交": function() {
var fm = $j("#fmCreateFolder");
showProcessingDlg();
$j.post(fm[0].action, fm.serialize(), function(msg){
hideProcessingDlg();
showAjaxMsg(msg, function(){
dlg.dialog("close");
try { parent.reloadNode($j("#folderId")[0].value); }catch(e){}
location.reload();
})
})
},
"关闭": function() { $j(this).dialog("close"); }
} // end of buttons
}) // end of dlg.dialog
}
dlg.load( url, function(msg){
if (/{"error"/.test(msg)) return;
dlg.dialog('open');
$j("#fmCreateFolder #name").focus()
});
}
/**
* 示例2:AJAX 附件上传
*/
function createFile(url) {
var id = "dlgCmsCreateFile";
var dlg = $j("#"+id);
if ( dlg.length == 0 ) {
$j("<div id='"+id+"' class='body'></div>").appendTo("body");
dlg = $j("#"+id);
dlg.dialog({
autoOpen:false, modal:true, title:"上传附件", width:450, resizable:false,
buttons: {
"上传": function() {
if ( $j("#fmCreateFile").find(":file").val() ) {
if ( $j.browser.fileApiSupported ) {
$j("#fmCreateFile").submit();
} else {
showProcessingDlg(function(){
$j("#fmCreateFile").submit();
return false;
});
$j(this).dialog("close");
}
}
},
"关闭": function() { $j(this).dialog("close"); }
} // end of buttons
}) // end of dlg.dialog
}
dlg.load( url, function(msg){
if (/{"error"/.test(msg)) return;
dlg.dialog('open');
// AJAX 上载,如果支持XMLHttpRequest Level 2,则显示上传进度
$j("#fmCreateFile").ajaxForm({
dataType: 'json',
beforeSend : function() {
if ( $j.browser.fileApiSupported ) {
dlg.closest("div.ui-dialog").find(".ui-dialog-titlebar, .ui-dialog-buttonpane, .ui-dialog-titlebar-close, .ui-resizable-handle").hide();
$j("#fmCreateFile").html(' <br/><div class="progressbar"><div class="progress-label" style="float:right; margin-top:5px">Uploading...</div></div><br/> ');
$j("#fmCreateFile .progressbar").progressbar({value: 0});
}
},
uploadProgress: function(event, position, total, percentComplete) {
$j("#fmCreateFile .progressbar").progressbar( "value", percentComplete );
$j("#fmCreateFile .progress-label").text( percentComplete + '%' );
},
complete: function(xhr) {
if ( $j.browser.fileApiSupported ) {
dlg.closest("div.ui-dialog").find(".ui-dialog-titlebar, .ui-dialog-buttonpane, .ui-dialog-titlebar-close, .ui-resizable-handle").show();
dlg.dialog("close");
}
}
})
});
}
上面的代码乍一看,麻烦得很,尤其是每次写AJAX表单时,总是要拷贝粘贴大量代码,因此,BroFWK提供了一个简化的API:$.formDialog,简化后的代码如下所示:
/**
* 示例1:AJAX 表单提交
*/
function createFolder(url) {
$j.formDialog({
modal:true, title:"创建文件夹", width:420, resizable:false,
id: "dlgCmsCreateFolder", url: url,
"submit.close": true, "submit.reload": true,
"submit.after": function() {
try {
parent.reloadNode($j("#folderId").val());
} catch(e) {}
}
})
}
/**
* 示例2:AJAX 附件上传
*/
function createFile(url) {
$j.formDialog({
modal:true, title:"上传附件", width:450, resizable:false,
id: "dlgCmsCreateFile", url: url, cache: false,
"submit.close": true, "submit.reload": true,
"submit.before": function() {
return $j("#fmCreateFile").find(":file").val();
}
})
}
和简化前的代码示例相比,代码量整整减少了2/3。
下面对 $.formDialog 做个简单的介绍:
- 封装了jquery ui的dialog组件,仅接收一个 options 参数,参数中的内容除了下面的注释所写的内容外,全部和 jqui 的 dialog 兼容
- 参数 options 说明:
@param options.id HTML容器的ID,如果不存在,则会创建一个DIV
@param options.html 表单的HTML文本内容,当容器不存在、并创建容器时将本参数的值放到 DIV 中
@param options.url 表单的URL,通过AJAX加载
@param options.cache 是否保存表单URL的Cache,默认为true
@param options.progressbar 如果有附件域、且浏览器支持XMLHttpRequest Level 2,是否显示上传进度条,默认为真
@param options.'buttons.default' 是否生成默认的确定(提交)、关闭(取消)按钮,默认为 true,即如果没有按钮Ok、Close按钮,则自动生成
@param options.'buttons.OK' 默认确定按钮的名称,默认取i18n配置 jqui.dalog.button.OK,即“确定”,如果为 false 则不显示
@param options.'buttons.CLOSE' 默认关闭按钮的名称,默认取i18n配置 jqui.dalog.button.CLOSE,即“关闭”,如果为 false 则不显示
@param options.'submit.ajax' 是否采用ajax的方式提交,默认为true。
如果提交后,需要根据上传的数据渲染或者重定向到其他页面(表单的 target 属性设为 _blank),则应设为false,此时ProcessingDlg显示3秒后自动关闭。
@param options.'submit.close' 提交成功后是否自动关闭
@param options.'submit.reload' 提交成功后是否自动刷新当前页面
@param options.'submit.before' 点击“确定”前的事件,接收参数 form,如果返回 false 则中断提交
@param options.'submit.after' 点击“确定”并且ajax提交成功后的事件,接收参数 message(服务器返回的对象)
@params options.buttons jqui dialog 的按钮参数,用法不变,但其回调函数中可以调用 this.submit()、this.close()、this.form() 来直接提交、关闭、获取表单对象 - 需要注意的是,附件上传使用的是 jqeury 插件 ajaxForm,由于浏览器的支持程度不同,因此在控制器中需要采用下面的写法来接收附件、返回结果:
def importExcel() {
// 解析 Excel 文件
Map result = bropen.toolkit.utils.office.MSExcelUtils.readAll(request)
// 处理数据
if ( !result.error ) {
....
}
// 渲染结果
if ( isAjax() ) {
render(result as JSON)
} else {
render(text:"<textarea>${result?.encodeAsJSON()}</textarea>", contentType:"text/html", encoding:"UTF-8")
}
}
控制器中,还可以通过 request.getFileMap() 来获得所有上传的附件,或者使用默认的 attachmentService.save 将附件保存到 Domain 实体中。
此外,提交过程默认为ajax的,如果上传附件后需要渲染一个预览界面,则应该设置 ‘submit.ajax’ 参数为 false,即禁用 ajax 方式提交表单。