【问题标题】:How can i apply a draggable directive to bootstrap modal using angularJS?如何使用 angularJS 将可拖动指令应用于引导模式?
【发布时间】:2015-03-12 14:14:34
【问题描述】:

我在我的 Angular 应用程序中使用引导模式,它工作正常。我需要让它可拖动和调整大小,所以我定义了一个指令。现在的问题是它被应用于模态窗口内的内容,因此模态窗口变得透明。

如何在打开窗口时将可拖动指令分配给模态窗口? 这是代码,

HTML:

<div ng-controller="CustomWidgetCtrl">
    <div class="box-header-btns pull-right" style="top:10px" >
        <a title="settings" ng-click="openSettings(widget)"><i class="glyphicon glyphicon-cog"></i></a>
</div>
</div>

App.js:

var routerApp = angular.module('DiginRt',  ['ui.bootstrap','ngRoute']);
routerApp.controller('CustomWidgetCtrl', ['$scope', '$modal',
  function($scope, $modal) {

    $scope.openSettings = function(widget) {
          $modal.open({
            scope: $scope,
            templateUrl: 'chart_settings.html',
            controller: 'chartSettingsCtrl',        
            resolve: {
              widget: function() {
                return widget;
              }
            }
          });
        };
    }
    ])

图表设置是另一个 HTML 页面。这是我的 Draggable 指令。

更新:

我已经用Plunker更新了问题

问题:

【问题讨论】:

标签: javascript angularjs html twitter-bootstrap


【解决方案1】:

我找不到将指令添加到ui-bootstrap 打开的模态的方法,因为它用模态对话框包装了模板..

所以我所做的是使用以下代码将拖动事件设置到模态对话框本身(而不是指令)。

我知道将事件添加到指令内的另一个元素不是最佳做法,但在无法直接为元素设置指令的情况下也不是坏做法。

这样做的原因是因为ui-bootstrap 没有提供向modal.open 函数上的modal-dialog 添加指令的方法

这是要放在指令开头的代码:

element= angular.element(document.getElementsByClassName("modal-dialog"));

还有plunkr

【讨论】:

【解决方案2】:

我赞成@Naeem_Shaikh 的回答,这基本上是对标准角度指令的改进。

但是,我已经能够修复标准 angular draggable 指令的另一个问题。

标准指令对整个对话框施加了可拖动性。一方面,这是我们想要的。我们要拖动整个对话框。但这有一个不幸的副作用,即在对话框中的各种编辑字段中单击不起作用:默认行为被阻止!不知何故,按钮已经在引导程序中被编码来克服这个问题,但不是文本编辑字段。我猜作者没有考虑我的用例。但对话框不仅仅是按钮!

这很棘手,因为需要拖动整个对话框,但您只希望通过单击标题“热点”中的单击来启动拖动。也就是说,发起拖拽的热点是被拖拽区域的一个子集。

Naeem 的修复使我能够让它工作,这样只有在标题中单击才会启动拖动。如果没有他的修复,坐标转换就会变得混乱。

function clickedWithinHeader(event) {
    var target = event.currentTarget;
    var hotspot = null;
    var hotspots = target.getElementsByClassName("modal-header");
    if (hotspots.length > 0) {
        hotspot = hotspots.item(0);
    }
    if (hotspot !== null) {
        var eY = event.clientY;
        var tOT = target.offsetTop;
        var y = eY - tOT;
        var hH = hotspot.offsetHeight;
        // since the header occupies the full width across the top
        // no need to check X.  Note that this assumes the header
        // is on the top, which should be a safe assumption
        var within = (y <= hH);
        return within;
    } else {
        return true;
    }
}


// Draggable directive from: http://docs.angularjs.org/guide/compiler
// Modified so that only clicks in the dialog header trigger drag behavior.
// Otherwise clicking on dialog widgets did not give them focus.
angular.module('drag', []).directive('draggable', function($document) {
"use strict";
return function(scope, element) {
    var startX = 0, startY = 0, x = 0, y = 0;
    element= angular.element(document.getElementsByClassName("modal-dialog"));
    element.css({
        position : 'fixed',
        cursor : 'move',
    });
    element.on('mousedown', function(event) {
//      // OK, where did they touch?  Only want to do this
//      // when they clicked on the header.
        if (!clickedWithinHeader(event)) {
            return;
        }
        // Prevent default dragging of selected content
        event.preventDefault();
        ...

请注意,clickedWithinHeader() 逻辑仅适用于 Naeem 的改进。 可能有更好的方法来做到这一点,但这是可行的。只有在标题中点击才会开始拖动,而在其他地方点击会做他们应该做的事情。

但是,这并不是全部答案,因为标准指令还将移动光标强加在整个对话框上,这非常令人不安,即使,或者特别是如果您无法拖动它出现的位置。

从指令中的 element.css 中删除它:

element.css({
    position : 'fixed',
});

并使用 CSS 将移动光标仅绑定到模态标题

.modal-header 
{
    cursor: move;
}

提供完整的解决方案。

【讨论】:

    【解决方案3】:

    我在这里合并了各种代码片段,并提出了一个更简单的解决方案。这个不依赖于检测点击事件是否发生在 modal-header 中,因为 mousedown 事件是专门绑定到 header 的。

    此解决方案也不依赖于在整个 DOM 中搜索 modal-dialog 类,因为它在父级中搜索 modal-dialog 元素。这将允许您在屏幕上有多个对话框,并且只有一个是可拖动的。

    我还创建了一个gist,该gist 进行了检查以防止对话框被移出可见范围。

    (function (angular) {
        "use strict";
    
        angular.module('MyModule')
            .directive('modalDraggable', ['$document', modalDraggable]);
    
        function modalDraggable($document) {
            return function (scope, element) {
                var startX = 0,
                    startY = 0,
                    x = 0,
                    y = 0;
    
                var draggable = angular.element(element.parents('.modal-dialog')[0]);
    
                draggable.find('.modal-header')
                    .css('cursor', 'move')
                    .on('mousedown', function (event) {
                        // Prevent default dragging of selected content
                        event.preventDefault();
                        startX = event.screenX - x;
                        startY = event.screenY - y;
    
                        $document.on('mousemove', mousemove);
                        $document.on('mouseup', mouseup);
                    });
    
                function mousemove(event) {
                    y = event.screenY - startY;
                    x = event.screenX - startX;
    
                    draggable.css({
                        top: y + 'px',
                        left: x + 'px'
                    });
                }
    
                function mouseup() {
                    $document.unbind('mousemove', mousemove);
                    $document.unbind('mouseup', mouseup);
                }
            };
        }
    }(window.angular));
    

    【讨论】:

      【解决方案4】:

      我将现有解决方案更改为屏幕上的多个模式。

      HTML: ……

      ... // 模态页眉、正文、页脚。

      JS调用模态: var modalInstance = $uibModal.open({ 动画:真的, 控制器:'ModalAndamentoController', 控制器作为:'vm', windowClass: '中心模式', 尺寸:'lg', 模板网址:'modalAndamento.html'
      });

      指令JS: (功能 () { '使用严格';

      角度 .module('app') .directive('draggable', draggableDirective);

      /** @ngInject */ 函数 draggableDirective($document) {

        //busca pelo elemento 
        var serachElement = function (parentElement, element) {
            //se o elemento pai corrente é igual ao elemento, então este foi encontrado
            if (parentElement == element[0]) {
                return true;
            }
      
            //aprofunda mais um nível na árvore procurando pelo elemento
            var i = 0;
            for (i = 0; i < parentElement.childNodes.length; i++) {
                return serachElement(parentElement.childNodes[i], element);
            }
            return false;
        };
      
        //recupera o elemento referente ao dialog
        var getDialogFromElement = function (element) {
            //recupera todos os dialogs da tela
            var dialogs = document.getElementsByClassName("modal-dialog")
            //se tiver apenas um, então esse é o dialog procurado e o mesmo é retornado
            if (dialogs.length == 1) {
                return angular.element(dialogs[0]);
            }
            //senão, varre todos os dialogs, procurando por aquele que contém o elemento corrente na sua árvore de elementos
            var i = 0;
            for (i = 0; i < dialogs.length; i++) {
                //se encontrar o elemento correte, então esse é o dialog procurado
                if (serachElement(dialogs[i], element)) {
                    return angular.element(dialogs[i]);
                }              
            }
        };
      
        //movimenta o dialog correspondente ao elemento informado (element)
        //O elemento que chega aqui é aquele que contém o atributo draggable
        return function (scope, element) {          
            var startX = 0,
              startY = 0,
              x = 0,
              y = 0;
      
            //recupera o dialog correspondente ao element corrente
            element = getDialogFromElement(element);
      
            //coloca o cursor de movimento no header
            var header = angular.element(document.getElementsByClassName("modal-header"));
            header.css({              
                cursor: 'move'
            });          
      
            element.on('mousedown', function (event) {
                // Prevent default dragging of selected content
                //event.preventDefault();
                startX = event.screenX - x;
                startY = event.screenY - y;
                $document.on('mousemove', mousemove);
                $document.on('mouseup', mouseup);
            });
      
            function mousemove(event) {
                y = event.screenY - startY;
                x = event.screenX - startX;
                element.css({
                    top: y + 'px',
                    left: x + 'px'
                });
            }
      
            function mouseup() {
                $document.unbind('mousemove', mousemove);
                $document.unbind('mouseup', mouseup);
            }
        };
      

      } })();

      【讨论】:

        猜你喜欢
        • 2016-04-16
        • 1970-01-01
        • 2017-12-17
        • 2014-06-11
        • 1970-01-01
        • 2016-12-01
        • 2013-05-18
        • 2012-09-16
        • 1970-01-01
        相关资源
        最近更新 更多