Bootstrap popover指令和Angularjs的嵌套元素

时间:2014-01-14 04:17:55

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

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

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

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

我读过一个问题是bootstrap中的popovers分离/附加到DOM,但我不知道如何解决这个问题。我也想避免第三方库(例如angular-ui),因为我想避免开销。

非常感谢任何帮助。

更新 感谢Vasaka的暗示,我能够进一步发展。问题略有改变,因为嵌套指令现在似乎没有从$compile中受益,即我不相信它附加到范围。

要重现该行为,请单击日期(下面的plunker链接),单击popover中的日期(日期应递增)并关闭弹出窗口。再次重复这些步骤,您会注意到递增日期不再起作用。我尝试添加$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>

1 个答案:

答案 0 :(得分:1)

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

1)根据Vasaka的建议,弹出窗口的tip需要绑定到范围($compile(tip)(scope))。

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

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