使用 $.formDialog 开发 AJAX 表单（含附件上传）?
李小翔
2015-05-22 11:02

内容列表

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(’&nbsp;<br/><div class=”progressbar”><div class=”progress-label” style=”float:right; margin-top:5px”>Uploading...</div></div><br/>&nbsp;’);
                    $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 方式提交表单。