twitter-bootstrap 如何使用 angularJS 将可拖动指令应用于引导模式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27942209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 22:09:07  来源:igfitidea点击:

How can i apply a draggable directive to bootstrap modal using angularJS?

javascriptangularjshtmltwitter-bootstrap

提问by Sajeetharan

I am using bootstrap modal in my Angular Application, it works fine. I need to make it draggable and resizeable, so i have defined a directive. The issue now is it getting applied to the content inside the modal window, hence the modal window becomes transparent.

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

how can i assign the draggable directive to the modal window when opening the window? Here is the code,

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

HTML:

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:

应用程序.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;
              }
            }
          });
        };
    }
    ])

Chart Settings is another HTML page. Here is my Draggable directive.

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

UPDATE:

更新:

I have update the issue with Plunker

我已经更新了问题 Plunker

Issue:enter image description here

问题:在此处输入图片说明

回答by Naeem Shaikh

I couldn't find a way to add the directive to the modal opened by ui-bootstrap, as it wraps the template with a modal-dialog..

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

So what i did is setting the events for drag to the modal-dialog itself(not the directive) using the following code.

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

I know it is not the best practice to add events to another element inside a directive but not a bad practice as well in cases like these, where you cant set a directive directly to the element.

我知道将事件添加到指令中的另一个元素不是最佳实践,但在此类情况下也不是坏习惯,在这种情况下,您无法直接为元素设置指令。

the reason doing this is because ui-bootstrapdoesnt provide a way to add a directive to the modal-dialogon modal.openfunction

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

here is the code to be put at the start of the directive:

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

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

and the plunkr

plunkr

回答by Steve Cohen

I upvoted @Naeem_Shaikh's answer which is basically an improvement on the standard angular directive.

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

However, there is another problem with the standard angular draggable directive that I have been able to fix.

但是,我已经能够修复标准角度可拖动指令的另一个问题。

The standard directive imposes draggability on the whole dialog. On the one hand, this is what we want. We want to drag the whole dialog. But this has unfortunate side effect that clicks in various edit fields in the dialog do not work: the default behavior is prevented! Somehow buttons have been coded in bootstrap to overcome this but not text edit fields. I'm guessing that the authors weren't considering my use case. But dialogs are more than just buttons!

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

It's tricky since it is the whole dialog that needs to be dragged, but you only want drags initiated by clicks in the header "hotspot". In other words, the hotspot to initiate dragging is a subset of the area to be dragged.

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

Naeem's fix enabled me to get it to work so that only clicks in the header initiated drags. Without his fix, the coordinate conversion was getting confused.

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();
        ...

Note that the clickedWithinHeader() logic only works with Naeem's improvement.There may be a better way to do it, but this works. Only clicks in the header initiate dragging and clicks elsewhere do what they're supposed to do.

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

However, that wasn't the whole answer since the standard directive also imposed the move cursor over the whole dialog which is very disconcerting, even if, or especially if you can't drag where it appears.

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

Removing that from the element.css in the directive:

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

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

and tying the move cursor only to the modal header using CSS

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

.modal-header 
{
    cursor: move;
}

provides a complete solution.

提供完整的解决方案。

回答by Dan Morphis

I incorporated the various code fragments here and came up with a simpler solution. This one doesn't rely on detecting if the click event happened in the modal-header, because the mousedownevent is bound to the header specifically.

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

This solution also doesn't rely on searching the entire DOM for the modal-dialogclass, as it searches the parents for the modal-dialogelement. This will allow you to have multiple dialogs on screen and only one be draggable.

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

I also created a gistthat has checking to prevent the dialog from being moved outside the visible bounds.

我还创建了一个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));

回答by Fabricio Miranda

I change an existing solution to more than one modal on screen.

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

Html: ....

html: ....

OR

或者

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

JS call modal: var modalInstance = $uibModal.open({ animation: true, controller: 'ModalAndamentoController', controllerAs: 'vm', windowClass: 'center-modal', size: 'lg', templateUrl: 'modalAndamento.html'
});

JS调用modal:var modalInstance = $uibModal.open({ animation: true, controller: 'ModalAndamentoController', controllerAs: 'vm', windowClass: 'center-modal', size: 'lg', templateUrl: 'modalAndamento.html'
});

Directive JS: (function () { 'use strict';

指令 JS: (function () { 'use strict';

angular .module('app') .directive('draggable', draggableDirective);

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

/** @ngInject */ function draggableDirective($document) {

/** @ngInject */ function 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);
      }
  };

} })();

} })();