在JQuery UI的Dialog、Tabs界面中实现combobox?
李小翔
2013-11-26 10:32

内容列表
问题描述 	 # 
原因分析 	 # 
解决方案 	 # 
适用于 	 # 
参考资料 	 # 

问题描述
    bro-framework中，基于jquery ui以及第三方代码，实现了一个combobox组件。
    通常情况下，jqui的dialog内容会采用ajax的方式（load）加载html文本、或者提前加载但是隐藏到页面上，当需要的时候再调用api将其显示出来；如果dialog页面上需要combobox之类的控件，若生成combobox的时机不正确时，会发现输入框和右侧的下拉箭头的位置严重偏离，或者根本就不显示为combobox，还是默认的下拉框形式。
    下面是导致出现该问题的几段问题代码。
示例代码1
var dlg = $j(”#foobar”).dialog({ 
    autoOpen:false, ......
} );
dlg.load( ”http://xxxx/yyyy/zzzz”, function(){ 
    dlg.dialog(’open’);
    $j(”select[name=’foobar’]”).combobox({ minLength:1, delay:300} );
} );
示例代码2
var dlg = $j(”#foobar”).dialog({ 
    autoOpen:false, .....
    , open: function() { 
        $j(”select[name=’foobar’]”).combobox({ minLength:1, delay:300} );
    } 
} );
dlg.load( ”http://xxxx/yyyy/zzzz”, function(){ 
    dlg.dialog(’open’);
} );
示例代码3
<html>
<head>
   <script>
   // 页面加载完成后就提前设置combobox！！！
    $j(function(){ 
        $j(”#foobar”).combobox({ minLength:1, delay:300} );
    } )
   
   // 显示dialog
    function showDialog() { 
        $j(”#dialog”).dialog({ ....} )
    } 
   </script>
</head>
<body>
   <div id=”dialog” style=”display:none”>
       <select id=”foobar”>...</select>
   </div>
   <button onclick=”showDialog()”>
        show dialog
   </button>
</body>
示例代码4
<html>
<head>
   <script>
    $j(function(){ 
        $j(”#tabs”).tabs();    // 生成tab页签
        $j(”#foobar”).combobox({ minLength:1, delay:300} );
    } )
   
   function showDialog() { 
        $j(”#dialog”).dialog({ ....} )
    } 
   </script>
</head>
<body>
   <div id=”tabs”>
       <ul>
           <li><a href=”#tabs-1”>tab1</li>
           <li><a href=”#tabs-2”>tab2-combobox</li>
       </ul>
       <div id=”tabs-1”>....</div>
       <div id=”tabs-2”>
            <select id=”foobar”>...</select>
       </div>
   </div>
   <button onclick=”showDialog()”>
        show dialog
   </button>
</body>

原因分析
    示例代码1和2中，虽然都在相关的事件中渲染combobox，但实际上偶尔会出现不生成combobox的问题。原因是jquery的ajax方法load显然做了延迟渲染的处理，在load成功的回调方法里调用dialog方法来显示窗口时，HTML内容并未真正渲染到页面上。
    示例代码3中，虽然html内容已渲染，但是select此时并不可见，导致渲染出来的combobox输入框和右侧的下拉箭头的位置严重偏离。
    实例代码4中，由于有tab页签，并且默认显示tab1，而下拉框在tab2中，此时也是不可见的，因此切换到页签tab2时，combobox的显示效果仍然错位。

解决方案
    对于示例代码1和2，由于jquery目前没有提供渲染完成的事件，因此只好写点看比较罗嗦的异步代码，如下所示：
var dlg = $j(”#foobar”).dialog({ 
    autoOpen:false, .....
    , open: function() { 
       // 异步渲染combobox
        function setCombobox() { 
            $j.doTimeout(50, function() { 
               if ( $j(”select[name=’foobar’]:visible”).length == 0 ) return setCombobox();
                $j(”select[name=’foobar’]”).combobox({ minLength:1, delay:300} );
            } )
        } ;
        setCombobox();
    } 
} );
dlg.load( ”http://xxxx/yyyy/zzzz”, function(){ 
    dlg.dialog(’open’);
} );
    对于示例代码3，将对combobox的调用改到dialog的open事件（见上面的open事件）中即可，代码略。
    对于示例代码4，将对combobox的调用改到对应页签激活的事件中即可，如下所示：
$j(”#tabs”).tabs({ 
    activate: function(event, ui) { 
       if ( ui.newPanel.attr(”id”) == ”tabs-2” ) { 
            $j(”select[name=’foobar’]”).combobox({ minLength:1, delay:300} );
        } 
    } 
} );

适用于
    BroFramework 2.8+

参考资料
  http://api.jqueryui.com/dialog/
   http://api.jqueryui.com/tabs/