使用nginclude时避免使用额外的DOM节点

Phi*_*mas 22 angularjs angularjs-ng-repeat angularjs-ng-include

我正在努力思考如何使用ng-include不使用额外的DOM元素,因为我正在从简单的HTML演示中构建一个角度应用程序.我正在使用非常纤薄的HTML与完全开发的,严格的DOM耦合的CSS(由SASS构建)和重构是我想不惜一切代价避免的.

这是实际的代码:

<div id="wrapper">
    <header
        ng-controller="HeaderController"
        data-ng-class="headerType"
        data-ng-include="'/templates/base/header.html'">
    </header>
    <section
        ng-controller="SubheaderController"
        data-ng-class="subheaderClass"
        ng-repeat="subheader in subheaders"
        data-ng-include="'/templates/base/subheader.html'">
    </section>
    <div
        class="main"
        data-ng-class="mainClass"
        data-ng-view>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

我需要<section>作为重复元素,但有自己的逻辑和不同的内容.内容和重复次数都取决于业务逻辑.如您所见,将ng-controller和ng-repeat放在<section>元素上将不起作用.但是,插入一个新的DOM节点会是什么,这正是我想要避免的.

我错过了什么?这是最佳做法还是有更好的方法?


编辑:只是为了澄清评论中的问题,我试图生成的最终HTML将是:

<div id="wrapper">
    <header>...</header>
    <section class="submenuX">
        some content from controller A and template B (e.g. <ul>...</ul>)
    </section>
    <section class="submenuY">
        different content from same controller A and template B (e.g. <div>...</div>)
    </section>
    <section class="submenuZ">
        ... (number of repetitions is defined in controller A e.g. through some service)
    </section>

    <div>...</div>
</div>
Run Code Online (Sandbox Code Playgroud)

我想使用相同的模板B(subheader.html)的原因是为了代码清洁.我设想subheader.html有一些ng-switch来返回动态内容.

但基本上,底层的静态是:有没有一种方法可以透明地包含模板的内容,而不使用DOM节点?


EDIT2:解决方案需要可重用.=)

Pet*_*rch 26

其他一些答案表明replace:true,但请记住,replace:true在模板中标记为弃用.

相反,在对类似问题的回答中,我们找到了另一种选择:它允许您编写:

<div ng-include src="dynamicTemplatePath" include-replace></div>
Run Code Online (Sandbox Code Playgroud)

自定义指令:

app.directive('includeReplace', function () {
    return {
        require: 'ngInclude',
        restrict: 'A', /* optional */
        link: function (scope, el, attrs) {
            el.replaceWith(el.children());
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

(cut'n'paste来自其他答案)


Phi*_*mas 20

编辑:经过一些研究,为了完整起见,我添加了一些信息.从1.1.4开始,以下工作:

app.directive('include',
    function () {
        return {
            replace: true,
            restrict: 'A',
            templateUrl: function (element, attr) {
                return attr.pfInclude;
            }
        };
    }
);
Run Code Online (Sandbox Code Playgroud)

用法:

<div include="'path/to/my/template.html'"></div>
Run Code Online (Sandbox Code Playgroud)

但是,有一个问题:模板不能是动态的(例如,通过范围传递变量因为$ scope,或任何DI,在templateUrl中无法访问 - 请参阅此问题),只能传递一个字符串(就像上面的html片段一样).为了绕过这个特定的问题,这段代码应该可以解决问题(对这个问题的赞誉):

app.directive("include", function ($http, $templateCache, $compile) {
    return {
        restrict: 'A',
        link: function (scope, element, attributes) {
            var templateUrl = scope.$eval(attributes.include);
            $http.get(templateUrl, {cache: $templateCache}).success(
                function (tplContent) {
                    element.replaceWith($compile(tplContent.data)(scope));
                }
            );
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

用法:

<div include="myTplVariable"></div>
Run Code Online (Sandbox Code Playgroud)


hol*_*ple 6

您可以创建自定义指令,使用templateUrl属性链接到模板,并设置replacetrue:

app.directive('myDirective', function() {
  return {
    templateUrl: 'url/to/template',
    replace: true,
    link: function(scope, elem, attrs) {

    }
  }
});
Run Code Online (Sandbox Code Playgroud)

这将包括模板原样,没有任何包装元素,没有任何包装范围.