如何在AngularJS指令中定义另外绑定的HTML?

时间:2016-01-15 10:27:06

标签: angularjs angularjs-directive angularjs-ng-repeat

我的主视图使用了一个名为fileUploader的指令。 fileUploader指令使用ng-repeat来表示对象列表(文件详细信息)。我希望这个file-uploader指令可以重用,所以我希望在使用它的视图中放置特定于用户的UI。

这是我的主要观点。在这种情况下,我希望看到每个项目的标准文件上传器模板以及我将在对象上找到的另外两个元数据(reference / destinationFolder)。

    <file-uploader class="col-md-10 file-uploader" file-uploader-upload-url="/x/upload">
        <dl>
            <dt>Reference</dt>
<!-- Note the binding on the next line, how do I evaluate it to the "item" in the directive's ng-repeat? -->
            <dd>{{ item.reference }}</dd>
            <dt>Folder</dt>
            <dd>{{ item.destinationFolder }}</dd>
        </dl>
    </file-uploader>

我的指令使用ng-transclude包含上面的<dl>内容。似乎{{item.reference}}在主视图中进行了评估,然后多次插入,我想要的是它按原样转换它,然后在指令的上下文中评估表达式。 -重复。 transclude等工作正常,但绑定无法正常工作。

    <ul class="file-upload-list">
        <li ng-repeat="item in controller.fileUploader.queue">
            <div class="file-upload-item" drag-container drag-data="controller.fileUploader.queue[$index]">
                <div class="file-upload-icon">
                    <img src="/Icons/FileExtension/{{item.file.name | fileExtension}}" alt="Icon" class="file-upload-icon" />
                </div>
                <div class="file-upload-filename">
                    <a href="" title="{{ item.file.name }}">
                        {{ item.file.name | limitTo : -28 }}
                    </a>
                </div>
<!-- Here is where I want the main view's template repeated and data-bound -->
                <ng-transclude class="file-upload-meta-data"/>
                <div class="progress">
                    <div class="progress-bar" role="progressbar" ng-style="{ 'width': item.progress + '%' }"></div>
                </div>
            </div>
        </li>
    </ul>

2 个答案:

答案 0 :(得分:1)

可悲的是,这不是ng-transclude翻译的工作原理。你要做的是创建一个容器指令,该指令利用它的子节点作为你自己的指令内部标记的“模板”。

根据定义,被转换的内容绑定到实例化指令的地方的范围;不是指令模板的范围。

所以实际上你并不需要在这里使用transclusion,因为你真正想做的只是将内部HTML注入到你自己的模板中。您可以在编译函数中执行此操作:

app.directive('test', function(){

  return {
    restrict: 'E',
    compile: function compile(tElement, tAttrs, tTransclude) {

      // Extract the children from this instance of the directive
      var children = tElement.children();

      // Wrap the chidren in our template
      var template = angular.element('<div ng-repeat="item in collection"></div>');
      template.append(children);

      // Append this new template to our compile element
      tElement.html('');
      tElement.append(template);

      return {
        pre: function preLink(scope, iElement, iAttrs, crtl, transclude) {
        },
        post: function postLink(scope, iElement, iAttrs, controller) {
        }
      };
    }
  };
});

- Angular Issue #7874: ng-repeat problem with transclude

答案 1 :(得分:0)

解决方案是在指令中使用ng-include。

首先,我在我的指令中添加了一个额外的属性,开发人员可以在其中指定模板的ID,如下所示:

<file-uploader file-uploader-metadata-template-id="someID" class="col-md-10 file-uploader" file-uploader-upload-url="/x/upload">

然后在指令中我只需要使用ng-include

<div class="file-upload-meta-data" ng-include="controller.fileUploaderMetadataTemplateId"/>

然后我可以像这样使用指令

<file-uploader class="col-md-10 file-uploader" file-uploader-upload-url="/x/upload" file-uploader-metadata-template-id="file-meta-template"/>
<script type="text/ng-template" id="file-meta-template">
    <dl>
        <dt>Application</dt>
        <dd>{{ item.meta.applicationName }}&nbsp;</dd>
        <dt>Reference</dt>
        <dd>{{ item.meta.referenceName }}&nbsp;</dd>
        <dt>Folder</dt>
        <dd>{{ item.meta.targetFolderName }}&nbsp;</dd>
    </dl>
</script>

请注意,我绑定到控制器,其中controllerAs设置为&#34; controller&#34; - 这是感兴趣的人的打字稿......

module MyApp.Directives.FileUploaderDirective {
    export class FileUploaderDirectiveController {
        public uploadUrl: string;
        public metaTemplateId: string;
    }

    class FileUploaderDirective implements angular.IDirective {
        public restrict: string = "E";
        public templateUrl: string = "/app/Directives/FileUploaderDirective/FileUploaderDirective.html";
        public scope: any = {
            uploadUrl: "@fileUploaderUploadUrl",
            metaTemplateId : "@fileUploaderMetadataTemplateId"
        };
        public controller: string = "MyApp.Directives.FileUploaderDirective.FileUploaderDirectiveController";
        public controllerAs: string = "controller";
        public bindToController: boolean = true;
        public transclude: boolean = true;
        public replace: boolean = true;
    }

    export function register(app: angular.IModule) {
        app.controller("MyApp.Directives.FileUploaderDirective.FileUploaderDirectiveController", FileUploaderDirectiveController);
        app.directive("fileUploader", () => new FileUploaderDirective()); 
    }
}