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

Angularjs 在使用nginclude时避免使用额外的DOM节点,angularjs,angularjs-ng-repeat,angularjs-ng-include,Angularjs,Angularjs Ng Repeat,Angularjs Ng Include,在我从一个简单的HTML演示构建一个有角度的应用程序时,我正在努力思考如何让ng include不使用额外的DOM元素。我正在使用非常纤细的HTML和完全开发的、紧密耦合的CSS(从SASS构建),重构是我想不惜一切代价避免的事情 以下是实际代码: 我需要是一个重复的元素,但有自己的逻辑和不同的内容。内容和重复次数都取决于业务逻辑。如您所见,在元素上放置ng控制器和ng repeat将不起作用。然而,插入一个新的DOM节点是可行的,这正是我试图避免的 我错过了什么?这是最佳实践还是有更好的方

在我从一个简单的HTML演示构建一个有角度的应用程序时,我正在努力思考如何让ng include不使用额外的DOM元素。我正在使用非常纤细的HTML和完全开发的、紧密耦合的CSS(从SASS构建),重构是我想不惜一切代价避免的事情

以下是实际代码:


我需要是一个重复的元素,但有自己的逻辑和不同的内容。内容和重复次数都取决于业务逻辑。如您所见,在元素上放置ng控制器和ng repeat将不起作用。然而,插入一个新的DOM节点是可行的,这正是我试图避免的

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


编辑:正如评论中所要求的那样,我试图生成的最终HTML是:


...
来自控制器A和模板B的一些内容(例如
) 来自同一控制器A和模板B的不同内容(例如…) ... (重复次数在控制器A中定义,例如通过某些服务) ...
我想使用相同的模板B(subheader.html)的原因是为了代码整洁。我设想subheader.html具有某种ng开关,以便返回动态内容

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



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

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

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

    }
  }
});

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

编辑:经过一些研究,为了完整性,我添加了一些信息。自1.1.4起,以下工作:

用法:

用法:


对于碰巧访问此问题的任何人:

从angular 1.1.4+开始,您可以使用templateURL中的函数使其成为动态的


检查另一个答案

通过正确的设置,您可以定义自己的
ngInclude
指令,该指令可以运行,而不是Angular.js提供的指令,并防止内置指令永远执行

为了防止执行Angular内置指令,必须将指令的优先级设置为高于内置指令的优先级(400表示
ngInclude
,并将
终端
属性设置为
true

之后,您需要提供一个post link函数,用于获取模板并用编译后的模板HTML替换元素的DOM节点

一句警告:这相当严厉,您为整个应用程序重新定义了
ngInclude
的行为。因此,我将下面的指令设置为
myApp
而不是
myApp
,以限制其范围。如果您想在整个应用程序范围内使用它,您可能需要将其行为配置为le,例如,仅当HTML中设置了
replace
属性时才替换元素,并且默认情况下返回到设置innerHtml

另外:这可能不适用于动画。原始的
ngInclude
-指令的代码要长得多,因此如果在应用程序中使用动画,请c&p原始代码并将
`$element.replaceWith()
嵌入其中

var includeDirective = ['$http', '$templateCache', '$sce', '$compile',
                        function($http, $templateCache, $sce, $compile) {
    return {
        restrict: 'ECA',
        priority: 600,
        terminal: true,
        link: function(scope, $element, $attr) {
            scope.$watch($sce.parseAsResourceUrl($attr.src), function ngIncludeWatchAction(src) {    
                if (src) {
                    $http.get(src, {cache: $templateCache}).success(function(response) {
                        var e =$compile(response)(scope);
                        $element.replaceWith(e);
                    });       
                }
            }); 
        }
    };
}];

myApp.directive('ngInclude', includeDirective);

其他一些答案建议使用
replace:true
,但请记住,模板中的
replace:true

相反,在中,我们找到了另一种选择:它允许您编写:

<div ng-include src="dynamicTemplatePath" include-replace></div>

(从另一个答案中删去“n”paste)

现在确定您的要求是什么了,您可以为变体添加一个示例吗?很抱歉。编辑以澄清。您可以使用ng include作为标记
,而不是发出
url
内容以外的标记。是的,但我正试图避免接触与DOM树紧密耦合的样式表(使用层次选择器)并使用nginclude将迫使我(因为生成的include模板成为ng include的子级)。有没有一种方法可以使templateUrl动态化,这样我就可以重复使用该指令?目前没有。至少没有现成的方法。我听说过一些我不推荐的解决方法。@filiptcI猜想你指的是:据我所知,angularjs>=1.1.4似乎是可能的,“可能在1.1.4+中”部分引用了
$routeProvider
配置中的
templateUrl
。但也许您可以在该线程之后找到一些有趣的内容。@filiptcI不得不争辩说,对于实际问题,我的解决方案仍然更好。如果这对您有效,那么很好。您的答案绝对正确,让我处于正确的位置Action(值得称赞!)。我只需要在整个模板结构中重复使用此功能。我不能为每个include声明一个新指令……这完全是另一回事(没有提到——或者我读得不好:)因为你基本上是用这个重新发明了
ng include
,如果你在这一过程中遇到问题,请检查它的来源。干杯:)非常好(第二个例子)的解决方案!它甚至可以在元素上工作,而且它们不会被抛出表外:)!编辑:在第二个示例中将
.data
添加到
tplContent
tplContent
是一个HTTP响应对象,而不是字符串,因此$compile会阻塞它。请在发布前测试代码!无法处理动态内容(ng重复,…)。请更新并使用这个对我有用的首选答案:
<div include="myTplVariable"></div>
var includeDirective = ['$http', '$templateCache', '$sce', '$compile',
                        function($http, $templateCache, $sce, $compile) {
    return {
        restrict: 'ECA',
        priority: 600,
        terminal: true,
        link: function(scope, $element, $attr) {
            scope.$watch($sce.parseAsResourceUrl($attr.src), function ngIncludeWatchAction(src) {    
                if (src) {
                    $http.get(src, {cache: $templateCache}).success(function(response) {
                        var e =$compile(response)(scope);
                        $element.replaceWith(e);
                    });       
                }
            }); 
        }
    };
}];

myApp.directive('ngInclude', includeDirective);
<div ng-include src="dynamicTemplatePath" include-replace></div>
app.directive('includeReplace', function () {
    return {
        require: 'ngInclude',
        restrict: 'A', /* optional */
        link: function (scope, el, attrs) {
            el.replaceWith(el.children());
        }
    };
});