【问题标题】:How to prevent an angular-bootstrap dropdown from closing (Unbind Event which was bound by a directive)如何防止 angular-bootstrap 下拉菜单关闭(解除绑定事件,由指令绑定)
【发布时间】:2014-05-16 14:50:34
【问题描述】:

我正在使用 Angular-Bootstrap 下拉菜单。我想阻止它在点击时关闭,直到用户故意关闭它。

默认状态是:单击文档中的某处时下拉菜单关闭。

我确定了相关的代码行:(第 12 行,dropdown.js)

this.open = function( dropdownScope ) {
   if ( !openScope ) {
     $document.bind('click', closeDropdown); // line to unbind
     $document.bind('keydown', escapeKeyBind);
   }
}

你可以在这里找到完整的代码:Link to Github

我不想更改 angular-bootstrap 的原始来源以保持我的项目开放以供更新。

我的问题:

如何将指令绑定的事件与 Angular 控制器中的文档解除绑定?

【问题讨论】:

    标签: angularjs angular-ui-bootstrap


    【解决方案1】:

    我通过将以下内容添加到下拉菜单中解决了这个问题。这可以防止下拉菜单关闭,除非您单击打开它的标签

    <ul class="dropdown-menu" ng-click="$event.stopPropagation()">
    

    【讨论】:

    • 谢谢!你让我今天一整天都感觉很好!我想了解这种行为是否是设计使然,这遵循什么逻辑......
    • 这会阻止任何 ajax 请求,如果里面有一个触发 ajax 事件的按钮 ..
    • 谢谢你,很好的解决方案,快速简单:)
    • 我从未感到如此激动。
    • 如何手动关闭下拉菜单?我尝试了相反的 $event.startPropagation() 但不起作用
    【解决方案2】:

    对于使用 Angular UI-Bootstrap 0.13.0 或更高版本的用户,这里是 UI-Bootstrap 文档中所述的更简洁的方式。

    默认情况下,如果单击其中的任何元素,下拉菜单将自动关闭,您可以通过设置自动关闭选项来更改此行为,如下所示:

    • always - (默认) 元素被点击。

    • outsideClick - 仅当用户 点击下拉菜单之外的任何元素。

    • disabled - 禁用自动关闭。然后你可以控制 使用 is-open 手动打开/关闭下拉菜单的状态。请 请注意,如果单击切换,下拉菜单仍将关闭, 按下 esc 键或打开另一个下拉菜单。下拉菜单将 不再关闭 $locationChangeSuccess 事件。

    这里是文档的链接: https://angular-ui.github.io/bootstrap/#/dropdown

    【讨论】:

    • 这很好,但我究竟把outsideClick放在哪里?
    • 我想我有 0.2.8 是不是比 0.13 旧?
    • 对于 Angular 2,'outsideClick' 的用法是:&lt;span dropdown [autoClose]="'outsideClick'"&gt; &lt;a href id="simple-dropdown" dropdownToggle&gt; &lt;span&gt;Open Dropdown&lt;/span&gt; &lt;/a&gt; &lt;ul dropdownMenu role="menu" aria-labelledby="single-button" class="simple-dropdown"&gt; &lt;li role="menuitem" *ngFor="let item of items"&gt; &lt;a&gt;{{item}}&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; &lt;/span&gt;
    • 这个问题是警告“...如果单击切换,按下 esc 键或打开另一个下拉菜单,下拉菜单仍将关闭。”在大多数情况下,切换部分很容易(不要添加切换),但其他 2 个可能不是,具体取决于项目。
    【解决方案3】:

    您可以通过添加事件传播来阻止事件在 Angular 2 及以上的 DOM 树中冒泡。 例如:(click)="$event.stopPropagation()"

    【讨论】:

      【解决方案4】:

      这是另一个技巧,但您可以添加一个指令来阻止切换事件传播。例如,这样的事情适用于我的特定用例:

      <div>
      <div class="btn-group" dropdown is-open="status.isopen" ng-controller="DropDownCtrl">
        <button type="button" class="btn btn-primary dropdown-toggle" ng-disabled="disabled">
          Button dropdown <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu">
          <li ng-click="goToPage('Action')">Action</li>
          <li disable-auto-close>Don't Dismiss</li>
          <li ng-click="goToPage('SomethingElse')">Something else here</li>
        </ul>
      </div>
      

      将此指令添加到元素应禁用自动关闭行为:

      angular.module('plunker', ['ui.bootstrap'])
      .controller('DropDownCtrl', ['$scope', '$location',
      function($scope, $location) {
        // Controller logic here
        $scope.goToPage = function(page) {
          console.log("Going to " + page + ". Dropdown should close");
          $location.path(page);
        };
      }])
      .directive('disableAutoClose', function() {
        // directive for disabling the default
        // close on 'click' behavior
        return {
              link: function($scope, $element) {
                  $element.on('click', function($event) {
                      console.log("Dropdown should not close");
                      $event.stopPropagation();
                  });
              }
          };
      });
      

      Plunker Example Here

      【讨论】:

      • 不幸的是,我认为这是一个错误的解决方案,朋友。您的“不要自动关闭”
      • 没有关闭下拉列表的原因应该是它没有codehref="#"code 属性,而其余的都有。
    • 好消息@adam_0628。我在错误的位置添加了 event.stopPropagation。但基本的想法应该有效。您想禁用元素的单击事件。您可以通过使用 '$event.stopPropagation();' 阻止事件向上传播链来做到这一点我更新了上面的代码以及 plunkr。希望此解决方案适合您
    • 【解决方案5】:

      这是一种覆盖它的粗略方式。需要手动控制is-open属性并劫持on-toggle事件,例如:

      <div class="btn-group" dropdown is-open="ctrl.isOpen" on-toggle="toggled(open)">
          <button type="button" class="btn btn-primary dropdown-toggle">
              Button dropdown <span class="caret"></span>
          </button>
          <ul class="dropdown-menu" role="menu">
              <li><a href="#">Action</a></li>
              <li><a href="#">Another action</a></li>
              <li><a href="#">Something else here</a></li>
              <li class="divider"></li>
              <li><a href="#">Separated link</a></li>
          </ul>
      </div>
      

      控制器:

          $scope.toggled = function (open) {
              $timeout(function () {
                  $scope.ctrl.isOpen = true;
              });
          };
      

      我会要求 dropdownConfig 常量(类似于 autoClose)的属性作为永久解决方案。

      【讨论】:

      • 嗨,谢谢您的回答 - 这基本上可以,但它会导致难看的闪烁 - 下拉菜单已关闭并再次打开。没有其他方法可以覆盖 JavaScript 中绑定到事件的函数吗?
      • 我按照你的建议打开了一个 github 问题:github.com/angular-ui/bootstrap/issues/2218
      • 要将特定处理程序取消绑定到事件,您需要对该处理程序的引用并执行 $(document).unbind('click', closeDropdown);或者您可以像这样取消绑定事件的所有处理程序: $(document).unbind('click');您可以使用 jQuery _data 对象来获取附加到元素事件的处理程序,但这是供内部使用的,请参阅这篇文章:stackoverflow.com/questions/2518421/…
      【解决方案6】:

      这是一种基于 Rob Jacobs 回答的更粗略的覆盖方法,除了它可以防止丑陋的闪烁 ulilcht 评论:

          $scope.toggled = function (open) {
              $scope.open = true;
              var child = $scope.$$childHead;
              while (child) {
                  if (child.focusToggleElement) {
                      child.isOpen = true;
                      break;
                  }
                  child = child.$$nextSibling;
              }
          };
      

      【讨论】:

        【解决方案7】:

        您也可以使用此解决方案:https://gist.github.com/Xspirits/684beb66e2499c3ff0e5 如果需要,您可以更好地控制下拉菜单。

        【讨论】:

          【解决方案8】:

          你可以装饰指令。

          通过这种方式,您不必接触原始代码,并且可以保持原始行为。

          您可以在下拉菜单中放置一个关闭按钮

          HTML

          <div class="dropdown-menu keep-dropdown-open-on-click" role="menu">
              <i class="icon-close close-dropdown-on-click"></i>
          </div>
          

          JS

          angular.module('app').config(uiDropdownMenuDecorate);
          uiDropdownMenuDecorate.$inject = ['$provide'];
          function uiDropdownMenuDecorate($provide) {
          
              $provide.decorator('dropdownMenuDirective', uiDropdownMenuDecorator);
          
              uiDropdownMenuDecorator.$inject = ['$delegate'];
          
              function uiDropdownMenuDecorator($delegate) {
          
                  var directive = $delegate[0];
                  var link = directive.link;
          
                  directive.compile = function () {
                      return function (scope, elem, attrs, ctrl) {
                          link.apply(this, [scope, elem, attrs, ctrl]);
                          elem.click(function (e) {
                              if (elem.hasClass('keep-dropdown-open-on-click') && !angular.element(e.target).hasClass('close-dropdown-on-click')) {
                                  e.stopPropagation();
                              }
                          });
                      };
                  };
          
                  return $delegate;
              }
          }
          

          【讨论】:

            【解决方案9】:

            这是使用经过批准的 angular-bootstrap 自动关闭方法的代码的样子。请注意,自动关闭属性位于顶部 &lt;div&gt;

            <div class="btn-group" uib-dropdown auto-close="disabled">
                <button id="single-button" type="button" class="btn btn-primary" uib-dropdown-toggle>
                    Button dropdown <span class="caret"></span>
                </button>
                <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button">
                    <textarea class="form-control" ng-model="description" rows="4" placeholder="Description"></textarea>
                </ul>
            </div>
            

            【讨论】:

              猜你喜欢
              相关资源
              最近更新 更多
              热门标签