【问题标题】:Using Angular Bootstrap datepicker inside of ui-grid (unstable 3.0.0)在 ui-grid 中使用 Angular Bootstrap 日期选择器(不稳定的 3.0.0)
【发布时间】:2016-12-21 10:57:36
【问题描述】:

我在 ui-grid 中使用 AngularJS Bootstrap 日期选择器(3.0.0 - 不稳定)

我已经通过自定义 cellTemplate (ui-grid) 实现了日期选择器:

{
      field: 'Wiedervorl',
      displayName: 'Wiedervorl.',
      enableCellEdit: true,
      enableCellEditOnFocus: true,
      enableHiding: false,
      cellTemplate: '<div><input ng-model="row.entity.Wiedervorl" ng-change="grid.appScope.addModifyFlag(row.entity)" ng-click="opened = true;" datepicker-popup="dd.MM.yyyy" is-open="opened" datepicker-options="grid.appScope.dateOptions" datepicker-append-to-body="true" type="text" /></div>',
      cellFilter: 'date',
      cellClass: function () {
        return 'text-left';
      },
      filter: {
        placeholder: 'date',
        condition: uiGridConstants.filter.CONTAINS
      },
      width: '7%'
    },

日期选择器输入内部有一个“已打开”标志,该标志完全针对该输入元素的一个实例(日期选择器实例)隔离。

问题是,在另一行中再打开一个日期选择器后,前一个不会关闭,并且可以同时打开多个日期选择器。

我尝试在输入中添加“ng-blur”,但它在日期选择器打开时执行。

任何想法,如何在 UI-Grid 中完成关闭以前的 datepicker 实例?一次只激活一个。

谢谢

【问题讨论】:

    标签: angularjs angular-ui-bootstrap


    【解决方案1】:

    也许它会对某人有所帮助。我对如何将 Bootstrap detepicker 集成到 UI Grid 进行了详细调查。

    首先,您需要使用自定义的editableCellTemplate 和正确处理END_EDITCANCEL_EDIT 事件的自定义指令。

    您可以在下面找到我的指令的代码:

    var app = angular.module('ui.grid.edit');
    
    app.directive('uiGridEditDatepicker', ['$timeout', '$document', 'uiGridConstants', 'uiGridEditConstants', function($timeout, $document, uiGridConstants, uiGridEditConstants) {
        return {
            template: function(element, attrs) {
                var html = '<div class="datepicker-wrapper" ><input uib-datepicker-popup is-open="isOpen" ng-model="' + attrs.rowField + '" ng-change="changeDate($event)" on-open-focus="false" disabled/></div>';
                return html;
            },
            require: ['?^uiGrid', '?^uiGridRenderContainer'],
            scope: true,
            compile: function() {
                return {
                    pre: function($scope, $elm, $attrs) {
    
                    },
                    post: function($scope, $elm, $attrs, controllers) {
                        var setCorrectPosition = function() {
                            var gridElement = $('.ui-grid-viewport');
                            var gridPosition = {
                                width: gridElement.outerWidth(),
                                height: gridElement.outerHeight(),
                                offset: gridElement.offset()
                            };
    
                            var cellElement = $($elm);
                            var cellPosition = {
                                width: cellElement.outerWidth(),
                                height: cellElement.outerHeight(),
                                offset: cellElement.offset()
                            };
    
                            var datepickerElement = $('ul', cellElement);
                            var datepickerPosition = {
                                width: datepickerElement.outerWidth(),
                                height: datepickerElement.outerHeight()
                            };
                            var newOffsetValues = {};
    
                            var isFreeOnRight = (gridPosition.width - (cellPosition.offset.left - gridPosition.offset.left) - cellPosition.width) > datepickerPosition.width;
                            if (isFreeOnRight) {
                                newOffsetValues.left = cellPosition.offset.left + cellPosition.width;
                            } else {
                                newOffsetValues.left = cellPosition.offset.left - datepickerPosition.width;
                            }
    
                            var freePixelsOnBottom = gridPosition.height - (cellPosition.offset.top - gridPosition.offset.top) - cellPosition.height;
                            var freePixelsOnTop = gridPosition.height - freePixelsOnBottom - cellPosition.height;
                            var requiredPixels = (datepickerPosition.height - cellPosition.height) / 2;
                            if (freePixelsOnBottom >= requiredPixels && freePixelsOnTop >= requiredPixels) {
                                newOffsetValues.top = cellPosition.offset.top - requiredPixels + 10;
                            } else if (freePixelsOnBottom >= requiredPixels && freePixelsOnTop < requiredPixels) {
                                newOffsetValues.top = cellPosition.offset.top - freePixelsOnTop + 10;
                            } else {
                                newOffsetValues.top = gridPosition.height - datepickerPosition.height + gridPosition.offset.top - 20;
                            }
    
                            datepickerElement.offset(newOffsetValues);
                            datepickerElement.css("visibility", "visible");
                        };
    
                        $timeout(function() {
                            setCorrectPosition();
                        }, 0);
    
                        $scope.isOpen = true;
    
                        var uiGridCtrl = controllers[0];
                        var renderContainerCtrl = controllers[1];
    
                        var onWindowClick = function (evt) {
                            var classNamed = angular.element(evt.target).attr('class');
                            var inDatepicker = (classNamed.indexOf('datepicker-calendar') > -1);
                            if (!inDatepicker && evt.target.nodeName !== "INPUT") {
                                $scope.stopEdit(evt);
                            }
                        };
    
                        var onCellClick = function (evt) {
                            console.log('click')
                            angular.element(document.querySelectorAll('.ui-grid-cell-contents')).off('click', onCellClick);
                            $scope.stopEdit(evt);
                        };
    
                        $scope.changeDate = function (evt) {
                            $scope.stopEdit(evt);
                        };
    
                        $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
                            if (uiGridCtrl.grid.api.cellNav) {
                                uiGridCtrl.grid.api.cellNav.on.navigate($scope, function (newRowCol, oldRowCol) {
                                    $scope.stopEdit();
                                });
                            } else {
                                angular.element(document.querySelectorAll('.ui-grid-cell-contents')).on('click', onCellClick);
                            }
                            angular.element(window).on('click', onWindowClick);
                        });
    
                        $scope.$on('$destroy', function () {
                            angular.element(window).off('click', onWindowClick);
                        });
    
                        $scope.stopEdit = function(evt) {
                            $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
                        };
    
                        $elm.on('keydown', function(evt) {
                            switch (evt.keyCode) {
                                case uiGridConstants.keymap.ESC:
                                    evt.stopPropagation();
                                    $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
                                    break;
                            }
                            if (uiGridCtrl && uiGridCtrl.grid.api.cellNav) {
                                evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
                                if (uiGridCtrl.cellNav.handleKeyDown(evt) !== null) {
                                    $scope.stopEdit(evt);
                                }
                            } else {
                                switch (evt.keyCode) {
                                    case uiGridConstants.keymap.ENTER:
                                    case uiGridConstants.keymap.TAB:
                                        evt.stopPropagation();
                                        evt.preventDefault();
                                        $scope.stopEdit(evt);
                                        break;
                                }
                            }
                            return true;
                        });
                    }
                };
            }
        };
    }]);
    

    注意! 我的指令需要 jQuery 来设置网格内日期选择器的正确位置。如果你不使用 jQuery,你应该在指令中调用setCorrectPosition() 进行注释。在这种情况下,日期选择器将根据标准行为放置在网格中。

    您可以在 Github 上找到有关如何使用它的一些额外信息和示例代码:https://github.com/Joiler/ui-grid-edit-datepicker

    Plunker:http://plnkr.co/edit/4mNr86cN6wFOLYQ02QND

    【讨论】:

    • 这非常非常有用。如果屏幕上有多个网格,则需要进行一些修改。我必须提交带有调整的 PR。
    • @RichardTurner,我只将它与不提供时间支持的 Angular Bootstrap Datepicker 集成。
    • 谢谢@JoilerWhite - 我已经根据github.com/adamalbrecht/ngQuickDate 和您的示例代码制定了一个新指令。它有一个日期和时间选项:-)
    • 我正在关注这个答案以及下面给出的 plunker。我在我的模块中完全复制了这个指令。我也有 jQuery。我使用了类似的列定义。我也在我的模块中做了一个相同的过滤器。我仍然看不到任何日期选择器工作。任何建议..我可能会错过什么
    • 我看到你使用的模块名称是ui.grid.edit。已经有一个同名的指令,它是库本身的一部分。我很困惑这两者之间是否有联系??如何命名两个模块相同?
    【解决方案2】:

    以防万一有人像我一样遇到,ui-grid 也已经有它自己的内置日期选择器选项。

     $scope.gridOptions.columnDefs = [
        { name: 'registered', 
          displayName: 'Registered', 
          type: 'date', 
          cellFilter:'date:"yyyy-MM-dd"'}
    ];
    

    除非需要像 OP 这样的特定类型的外部日期选择器,否则这似乎非常方便且易于使用。

    【讨论】:

    • 其中一个主要问题是它只是将input 类型设置为date,这是许多常见浏览器(最重要的是Firefox)没有实现的HTML5 功能。
    【解决方案3】:

    您需要实现一个带有日期选择器的指令,并且该指令需要向网格提供 END_EDIT 和 CANCEL_EDIT 事件。请参阅编辑教程:http://ui-grid.info/docs/#/tutorial/201_editable(在 ColumnDef 选项上方)。

    您可以在https://github.com/angular-ui/ng-grid/blob/master/src/features/edit/js/gridEdit.js 中看到与下拉指令关联的代码,倒数第二个块

    【讨论】:

    • 好的,我考虑了您的建议并尝试创建指令。我创造了它。它似乎工作但并不顺利。我看到你对 ui-grid 非常熟悉......你能帮我解决一个问题吗?这是我的代码:note.io/1AxMc54 我把有问题的列表放在那里。我在以下链接上表现出不良行为:screencast.com/t/meAwibtT
    • gitter 频道gitter.im/angular-ui/ng-grid(查找@joanne16)基于@c0bra 的博客帖子:brianhann.com/ui-grid-and-dropdowns 进行了类似的讨论。一般来说,您需要收听 cellNav 并执行 end_cell_edit,我认为这将处理您正在寻找的大部分内容。
    【解决方案4】:
    app.directive('uiGridEditDatepicker', ['$timeout', '$document', 'uiGridConstants', 'uiGridEditConstants', function($timeout, $document, uiGridConstants, uiGridEditConstants) {
    return {
        template: function(element, attrs) {    
            var html = '<div class="datepicker-wrapper" ><input type="text" uib-datepicker-popup datepicker-append-to-body="true" is-open="isOpen" ng-model="datePickerValue" ng-change="changeDate($event)" popup-placement="auto top"/></div>';
            return html;
        },
        require: ['?^uiGrid', '?^uiGridRenderContainer'],
        scope: true,
        compile: function() {
            return {
                pre: function($scope, $elm, $attrs) {
    
                },
                post: function($scope, $elm, $attrs, controllers) {
    
                    $scope.datePickerValue = new Date($scope.row.entity[$scope.col.field]);
                    $scope.isOpen = true;
                    var uiGridCtrl = controllers[0];
                    var renderContainerCtrl = controllers[1];
    
                    var onWindowClick = function (evt) {
                        var classNamed = angular.element(evt.target).attr('class');
                        if (classNamed) {
                            var inDatepicker = (classNamed.indexOf('datepicker-calendar') > -1);
                            if (!inDatepicker && evt.target.nodeName !== "INPUT") {
                                $scope.stopEdit(evt);
                            }
                        }
                        else {
                            $scope.stopEdit(evt);
                        }
                    };
    
                    var onCellClick = function (evt) {
                        angular.element(document.querySelectorAll('.ui-grid-cell-contents')).off('click', onCellClick);
                        $scope.stopEdit(evt);
                    };
    
                    $scope.changeDate = function (evt) {
                        $scope.row.entity[$scope.col.field] = $scope.datePickerValue;
                        $scope.stopEdit(evt);
                    };
    
                    $scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
                        if (uiGridCtrl.grid.api.cellNav) {
                            uiGridCtrl.grid.api.cellNav.on.navigate($scope, function (newRowCol, oldRowCol) {
                                $scope.stopEdit();
                            });
                        } else {
                            angular.element(document.querySelectorAll('.ui-grid-cell-contents')).on('click', onCellClick);
                        }
                        angular.element(window).on('click', onWindowClick);
                    });
    
                    $scope.$on('$destroy', function () {
                        angular.element(window).off('click', onWindowClick);
                        //$('body > .dropdown-menu, body > div > .dropdown-menu').remove();
                    });
    
                    $scope.stopEdit = function(evt) {
                        $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
                    };
    
                    $elm.on('keydown', function(evt) {
                        switch (evt.keyCode) {
                            case uiGridConstants.keymap.ESC:
                                evt.stopPropagation();
                                $scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
                                break;
                        }
                        if (uiGridCtrl && uiGridCtrl.grid.api.cellNav) {
                            evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
                            if (uiGridCtrl.cellNav.handleKeyDown(evt) !== null) {
                                $scope.stopEdit(evt);
                            }
                        } else {
                            switch (evt.keyCode) {
                                case uiGridConstants.keymap.ENTER:
                                case uiGridConstants.keymap.TAB:
                                    evt.stopPropagation();
                                    evt.preventDefault();
                                    $scope.stopEdit(evt);
                                    break;
                            }
                        }
                        return true;
                    });
                }
            };
        }
    };
    }]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-28
      • 2015-04-19
      • 1970-01-01
      • 2013-10-06
      • 1970-01-01
      • 1970-01-01
      • 2014-04-07
      • 2013-08-14
      相关资源
      最近更新 更多