使用包装器HTML的指令$ compile问题

时间:2014-11-21 22:00:01

标签: javascript html angularjs directive

我正在尝试创建一个指令,如果我声明:

<input my-directive show-button-bar="true" ng-model="fooBar"\>

它将创建以下HTML:

<div on-toggle="toggled(open)" is-open="dpModel.displayDatePicker" dropdown="" class="btn-group ng-scope">
  <input my-directive show-button-bar="true" ng-model="fooBar"\>
  <ul ng-click="$event.stopPropagation()" class="dropdown-menu datepicker-popup dropdown-menu-right">
    <div ng-if="showButtonBar">
      <div role="group" class="btn-group pull-left">
        <button ng-click="setToday()" class="btn btn-xs btn-info" type="button">Today</button>
        <button ng-click="clear()" class="btn btn-xs btn-danger" type="button">Clear</button>
      </div>
      <button ng-click="toggled(false)" class="btn btn-xs pull-right btn-success" type="button">Done</button>
    </div>
  </ul>
</div>

以下是我的指令中的代码片段,我尝试实现此目的:

var dropdown = $compile(angular.element('<div class=\"btn-group\" dropdown is-open=\"dpModel.displayDatePicker\" on-toggle=\"toggled(open)\"/>'))(scope);

var ulTemplate = '<ul id=\"list2\"ng-if=\"showButtonBar\" class=\"dropdown-menu datepicker-popup\" ng-class=\"direction === \'right\' ? \'dropdown-menu-right\':\'dropdown-menu-left\'\" role=\"menu\" ng-click=\"$event.stopPropagation()\">' +
                '<li ng-if=\"dpModel.displayDatePicker\">' +
                '<datepicker ng-model=\"dpModel.value\" show-weeks=\"false\"></datepicker>' +
                '</li>' +
                '<div ng-if=\"showButtonBar\">' +
                '<div class=\"btn-group pull-left\" role=\"group\">' +
                '<button type=\"button\" class=\"btn btn-xs btn-info\" ng-click=\"setToday()\">Today</button>' +
                '<button type=\"button\" class=\"btn btn-xs btn-danger\" ng-click=\"clear()\">Clear</button>' +
                '</div>' +
                '<button type=\"button\" class=\"btn btn-xs pull-right btn-success\" ng-click=\"toggled(false)\">Done</button>' +
                '</div>' +
                '</ul>';
var ul = $compile(angular.element(ulTemplate))(scope);
element.wrap(dropdown);
ul.insertAfter(element);

我遇到的问题是ul部分

var ul = $compile(angular.element(ulTemplate)(scope))

将正确编译范围,但包装器部分dropdown无法正确获取范围。这怎么可能?我做错了什么?

更新: 忘了还提到我需要在输入字段上有一个ng-model。

2 个答案:

答案 0 :(得分:0)

[编辑]

第一个例子中有错误。它应该是$ attrs。$ attr [this.name]而不是$ attrs [this.name]。 这是一个使用模板返回函数的清理返回示例: http://jsfiddle.net/numtpyL7/2/

module.directive('myDirective', function () {

    var wrapperTemplate = '\
<div>\
    <ul>\
        <li>Some Text</li>\
    </ul>\
</div>';

    return {
        template: function($element, $attrs) {
            var directiveTag = $attrs.$attr[this.name];
            var inputElem = $element.clone().removeAttr(directiveTag);
            var replacementHtml = angular.element(wrapperTemplate);
            replacementHtml.prepend(inputElem);

            return replacementHtml[0].outerHTML;
        },
        replace: true,
        priority: 999999
    };

});

[原文]

在高优先级终端指令中使用$ compile是这样的方法。 高优先级和终端意味着它将首先在元素上运行,并且它下面的任何内容都不会运行。然后在指令编译代码中从元素中删除该指令,用新DOM包装它,并用它替换当前元素。

module.directive('myDirective', function ($compile) {

    var wrapperTemplate = '\
    <div on-toggle="toggled(open)" is-open="dpModel.displayDatePicker" dropdown="" class="btn-group ng-scope">\
        <ul ng-click="$event.stopPropagation()" class="dropdown-menu datepicker-popup dropdown-menu-right">\
            <div ng-if="showButtonBar">\
                <div role="group" class="btn-group pull-left">\
                    <button ng-click="setToday()" class="btn btn-xs btn-info" type="button">Today</button>\
                    <button ng-click="clear()" class="btn btn-xs btn-danger" type="button">Clear</button>\
                </div>\
                <button ng-click="toggled(false)" class="btn btn-xs pull-right btn-success" type="button">Done</button>\
            </div>\
        </ul>\
    </div>';

    return {
        terminal: true,
        priority: 999999,
        compile: function($element, $attrs) {
            // Remove this directive from the new wrapped template so that it does not get run again.
            var inputElement = $element.removeAttr($attrs.$attr[this.name]);

            // Add the new template to the DOM and remove the DOM of the current directive
            var replacementHtml = angular.element(wrapperTemplate).prepend(inputElement.clone());
            $element.after(replacementHtml);
            $element.remove();

            var subLink = $compile(replacementHtml);
            return {
                pre: function(scope, element, attrs) {
                    subLink(scope);
                },
                post: function(scope, element, attrs) {
                }
            }
        }
    };

});

答案 1 :(得分:-1)

这是因为在.wrap()内部克隆了下拉元素。虽然它仍然与范围绑定,但这对内部表达式和指令没有影响,必须重新编译。更简单的解决方案是创建包装<my-directive>,以便下拉列表成为此结构中最顶层的元素。可以使用transclude插入input

<div my-directive><input show-button-bar="true"></div>

//within directive
return {
  transclude: true,
  template: '<div class="btn-group" dropdown is-open="dpModel.displayDatePicker" on-toggle="toggled(open)">' +
              '<ng-transclude></ng-transclude>' +
              '<ul ...></ul>' + // UL template goes here
            '</div>',
  link: function (scope, element) {
    //... link function code
  } 
}

在这种情况下,你似乎不需要编译。