【问题标题】:Bootstrap popover directive and nested element with Angularjs使用 Angularjs 引导弹出框指令和嵌套元素
【发布时间】:2014-01-15 10:34:03
【问题描述】:

我一直在尝试创建一个指令,我可以将它任意添加到现有表单(作为属性)中,这会使表单在单击附近的触发链接时成为弹出框。我已经让指令工作了一次,但是一旦我再次单击链接,基础数据不会改变并且按钮(例如“关闭”)停止工作。

可以在这里找到一个 plunker:http://plnkr.co/edit/2Zyg1bLearELpofeoj2T?p=preview

重现步骤: 1. 单击链接,2. 更改文本(注意链接文本也会更改),3. 单击关闭(确定当前没有做正确的事情),4. 再次单击链接, 5. 尝试更改文字/点击关闭,但没有任何效果...

我读到一个问题是引导程序中的弹出框被分离/附加到 DOM,但我不知道如何解决这个问题。我还想避免使用第三方库(例如 angular-ui),因为我想避免开销。

非常感谢任何帮助。

更新 多亏了瓦萨卡的提示,我才得以进步一点。问题略有改变,现在嵌套指令似乎没有从$compile 中受益,即我不相信它附加到范围。

要重现该行为,请单击日期(下面的 plunker 链接),单击弹出窗口中的日期(日期应递增)并关闭弹出窗口。再次重复这些步骤,您会注意到增加日期不再起作用。我尝试添加$compile(element.contents())(scope) 以尝试同时编译嵌套指令simple-date-picker,但这并没有解决问题。

这是更新的 plunker:http://plnkr.co/edit/2Zyg1bLearELpofeoj2T?p=preview

以及更新后的代码:

<!DOCTYPE html>
<html>

  <head>
    <link data-require="bootstrap-css@*" data-semver="3.0.3" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" />
    <script data-require="jquery@1.9.1" data-semver="1.9.1" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script data-require="bootstrap@2.3.2" data-semver="2.3.2" src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
    <script data-require="angular.js@1.2.5" data-semver="1.2.5" src="http://code.angularjs.org/1.2.5/angular.js"></script>

    <style>
    body {margin-top:40px; margin-left:40px;}
    </style>
    <script>
      var module = angular.module('module', []);

      module.directive('simpleDatePicker', function($compile) {
        return {
          restrict: 'E',
          scope: {
            date: '='
          },
          replace: true,
          template: '<div ng-click="date.setDate(date.getDate()+5)"> {{ date }} </div>',
        }
      });

      module.directive('myForm', function() {
        return {
          restrict: 'E',
          scope: {
            popover: '=?',
            value: '='
          },
          transclude: true,
          replace: true,
          template:
            '<div>' +
              '<a href="" ng-transclude></a>' +
              '<form ng-submit="submit($event)" ng-hide="popover && !formVisible" ng-attr-popover="{{ popover }}" class="form-inline">' +
                '<simple-date-picker date="value"></simple-date-picker>' +
                '<div ng-hide="!popover">' +
                  '<button type="submit" class="btn btn-primary">OK</button>' +
                  '<button type="button" class="btn" ng-click="formVisible=false">close</button>' +
                '</div>' +
                '<div class="editable-error help-block" ng-show="error">{{ error }}</div>' +
              '</form>' +
            '</div>',
          controller: function($scope, $element, $attrs) {
            $scope.formVisible = false;
            $scope.submit = function(evt) {
              $scope.formVisible = false;
            }
          }
      }});

      module.directive('popover', function($compile) {
        return {
          restrict: 'A',
          scope: false,
          compile: function compile(tElement, tAttrs, transclude) {
            return {
              pre: function preLink(scope, iElement, iAttrs, controller) {
              },
              post: function postLink(scope, iElement, iAttrs, controller) {
                var attrs = iAttrs;
                var element = iElement;

                // We assume that the trigger (i.e. the element the popover will be
                // positioned at is the previous child.
                var trigger = element.prev();
                var popup = element;

                // Connect scope to popover.
                trigger.on('shown', function() {
                  var tip = trigger.data('popover').tip();
                  $compile(tip)(scope);
                  scope.$digest();
                });

                trigger.popover({
                  html: true,
                  content: function() {
                    scope.$apply(function() {
                      scope.formVisible = true;
                    });
                    return popup;
                  },
                  container: 'body'
                });
                scope.$watch('formVisible', function(formVisible) {
                  if (!formVisible) {
                    trigger.popover('hide');
                  }
                });
                if (trigger.data('popover')) {
                  trigger.data('popover').tip().css('width', '500px');
                }
              }
            }
          }
        };
      });

      function MyCtrl($scope) {
          $scope.value = new Date(0);
      }

      angular.element(document).ready(function() {
        angular.bootstrap(document, ['module']);
    });

      </script>
  </head>

  <body ng-controller="MyCtrl">
    <my-form popover="true" value="value">
    {{ value }}
  </my-form>
  </body>

</html>

【问题讨论】:

  • angular-ui 已经有一个popover了,看看那个,我不知道你说的overhead是什么意思,但是这些组件是原生用angular编写的。
  • 我想避免一个额外的库(angular-ui),我称之为开销。
  • 您可能想查看this popover 实现。这里的关键是通过覆盖原生引导函数,根据 popover 的显示范围编译 popover 的内容。
  • @Vasaka 谢谢,我会看看他们的实现。

标签: javascript jquery angularjs twitter-bootstrap angularjs-directive


【解决方案1】:

我想我解决了这两个问题。如果有人感兴趣,我会快速总结一下我的发现:

1) 根据 Vasaka 的建议,popover 的tip 需要绑定到作用域($compile(tip)(scope))。

2) 第二个问题是嵌套指令不是由 (1) 中的 $compile() 调用编译的。这是由于在simple-date-picker 的(嵌套)指令定义对象中设置了replace: true。由于最初的指令标签最初被替换,任何后续的 $compile 运行将不再将简单的日期选择器识别为 Angular 指令。

最终的plunker(唯一的区别是replace: false)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-28
    相关资源
    最近更新 更多