浏览代码

fix datatable style issue when display none at init

wangweimin 2 年之前
父节点
当前提交
4777b5ff3e
共有 2 个文件被更改,包括 41 次插入26 次删除
  1. 8 16
      pywebio/output.py
  2. 33 10
      webiojs/src/models/datatable.ts

+ 8 - 16
pywebio/output.py

@@ -1393,7 +1393,7 @@ def put_grid(content: List[List[Union[Output, None]]], cell_width: str = 'auto',
     The format of width/height value in ``cell_width``,``cell_height``,``cell_widths``,``cell_heights``
     can refer to the ``size`` parameter of the `put_row()` function.
 
-    :Example:
+    Example:
 
     .. exportable-codeblock::
         :name: put_grid
@@ -1515,6 +1515,7 @@ def put_datatable(
         When not provide, the datatable will use the index in ``records`` to assign row ID.
     :param int/str height: widget height. When pass ``int`` type, the unit is pixel,
         when pass ``str`` type, you can specify any valid CSS height value.
+        In particular, you can use ``'auto'`` to make the widget auto-size it's height to fit the content.
     :param str theme: datatable theme.
         Available themes are: 'balham' (default), 'alpine', 'alpine-dark', 'balham-dark', 'material'.
     :param bool cell_content_bar: whether to add a text bar to datatable to show the content of current focused cell.
@@ -1529,7 +1530,8 @@ def put_datatable(
     :param str enterprise_key: `ag-grid enterprise  <https://www.ag-grid.com/javascript-data-grid/licensing/>`_ license key.
         When not provided, will use the ag-grid community version.
 
-    To pass JS function as value of ``column_args`` or ``grid_args``, you can use ``JSFunction`` object:
+    The ag-grid library is so powerful, and you can use the ``column_args`` and ``grid_args`` parameters to achieve
+    high customization. To pass JS functions as value of ``column_args`` or ``grid_args``, you can use ``JSFunction`` object:
 
         .. py:function:: JSFunction([param1], [param2], ... , [param n], body)
 
@@ -1565,6 +1567,10 @@ def put_datatable(
 
     if isinstance(height, int):
         height = f"{height}px"
+    if height == 'auto' and len(records) > 1000:
+        height = '600px'
+        logger.warning("put_datatable: numbers of rows are too large to use auto height, use fix height instead")
+
     if isinstance(id_field, str):
         id_field = [id_field]
 
@@ -1938,20 +1944,6 @@ def popup(title: str, content: Union[str, Output, List[Union[str, Output]]] = No
     After the context manager exits, the popup window will not be closed.
     You can still use the ``scope`` parameter of the output function to output to the popup.
 
-    * decorator:
-
-    .. exportable-codeblock::
-        :name: popup-decorator
-        :summary: `popup()` as decorator
-
-        @popup('Popup title')
-        def show_popup():
-            put_html('<h3>Popup Content</h3>')
-            put_text("I'm in a popup!")
-            ...
-
-        show_popup()
-
     """
     if content is None:
         content = []

+ 33 - 10
webiojs/src/models/datatable.ts

@@ -1,7 +1,9 @@
 import {pushData} from "../session";
 
 const tpl = `<div>
-<div class="ag-theme-{{theme}} ag-grid" style="width: 100%; height: {{height}}"></div>
+<div class="ag-theme-{{theme}} ag-grid" style="width: 100%; height: {{height}}">
+    <div class="grid-loading">⌛️ Loading Datatable...</div>
+</div>
 <div class="ag-grid-cell-bar"></div>
 <div class="ag-grid-tools">
     <div class="grid-status">
@@ -239,6 +241,7 @@ export let Datatable = {
         spec.field_args = parse_js_func(spec.field_args, spec.js_func_key);
         spec.path_args = parse_js_func(spec.path_args, spec.js_func_key);
         spec.grid_args = parse_js_func(spec.grid_args, spec.js_func_key);
+        let auto_height = spec.height == 'auto';
 
         let options = row_data_and_column_def(spec.records, spec.field_args, spec.path_args);
 
@@ -294,17 +297,36 @@ export let Datatable = {
             },
             onGridReady: (param: any) => {
                 grid_resolve(gridOptions);
+                if (auto_height) {
+                    gridOptions.api.setDomLayout('autoHeight');
+                }
 
-                gridOptions.columnApi.autoSizeAllColumns();
-                let content_width = 0;
-                gridOptions.columnApi.getColumns().forEach((column:any) => {
-                    if(!column.getColDef().hide)
-                        content_width += column.getActualWidth();
-                });
-                if (content_width < elem.find(".ag-grid")[0].clientWidth) {
-                    // the content is smaller than the grid, so we set columns to adjust in size to fit the grid horizontally
-                    gridOptions.api.sizeColumnsToFit();
+                let grid_elem = elem.find(".ag-grid")[0];
+                let on_grid_show = Promise.resolve();
+                if (grid_elem.clientWidth === 0) {  // the grid is hidden via `display: none`, wait for it to show
+                    on_grid_show = new Promise((resolve) => {
+                        // @ts-ignore
+                        let observer = new ResizeObserver((entries, observer) => {
+                            if (grid_elem.clientWidth > 0) {
+                                observer.disconnect();
+                                resolve();
+                            }
+                        });
+                        observer.observe(grid_elem);
+                    });
                 }
+                on_grid_show.then(() => {
+                    gridOptions.columnApi.autoSizeAllColumns();
+                    let content_width = 0;
+                    gridOptions.columnApi.getColumns().forEach((column: any) => {
+                        if (!column.getColDef().hide)
+                            content_width += column.getActualWidth();
+                    });
+                    if (content_width < grid_elem.clientWidth) {
+                        // the content is smaller than the grid, so we set columns to adjust in size to fit the grid horizontally
+                        gridOptions.api.sizeColumnsToFit();
+                    }
+                })
 
                 if (spec.actions.length > 0) {
                     elem.find('.ag-grid-tools').css('opacity', 1);
@@ -367,6 +389,7 @@ export let Datatable = {
         let ag_version = spec.enterprise_key ? 'ag-grid-enterprise' : 'ag-grid';
         // @ts-ignore
         requirejs([ag_version], function (agGrid) {
+            elem.find('.grid-loading').remove();
             new agGrid.Grid(elem.find(".ag-grid")[0], gridOptions);
             if (spec.instance_id) {
                 // @ts-ignore