2013-07-11 30 views
22

我正在努力围绕如何让ng-include不使用额外的DOM元素,因为我正在从纯HTML演示中构建一个角度应用程序。我正在使用完全开发,紧密DOM耦合CSS(由SASS构建)的非常苗条的HTML,重构是我想要不惜一切代价避免的。避免在使用nginclude时使用额外的DOM节点

下面是实际的代码:

<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> 

我需要<部分>是一个重复的元素,但有其自身的逻辑和不同的内容。内容和重复次数都取决于业务逻辑。如您所见,将ng-controller和ng-repeat放在<部分的>元素将不起作用。然而,什么会插入一个新的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> 

我之所以要使用相同的模板B(子头.html),代码清洁。我设想subheader.html有一些ng切换为了返回动态内容。

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


EDIT2:该解决方案需要是可重复使用的。 =)

+0

你可以添加一个变体的例子,现在确定你在问什么? – Chandermani

+0

对不起。编辑澄清。 –

+0

您可以使用ng-include作为标签'',而不是除了发布'url'的内容外的其他标签。 – Chandermani

回答

25

一些其他的答案表明replace:true,但请记住,replace:true模板是marked for deprecation

相反,an answer to a similar question,我们找到一种替代方案:它可以让你写:

<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()); 
     } 
    }; 
}); 

(cut'n'paste从对方的回答)

+1

不适用于动态内容(ng-repeat,...)。 请更新并使用此首选答案,该答案适用于我:http://stackoverflow.com/a/33508032/704246 –

6

您可以创建自定义指令,连接与templateUrl属性模板,并设置replacetrue

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

    } 
    } 
}); 

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

+0

有没有使templateUrl变为动态的方法,以便我可以重新使用该指令? –

+0

暂时没有。至少不是开箱即用的。我听说过一些我不推荐的解决方法。 @filiptc – finishingmove

+0

我想你是指这个:https://github.com/angular/angular.js/issues/1039 似乎是可能的angularjs> = 1.1.4 –

20

编辑:经过一番研究和为了完整起见,我添加了一些信息。由于1.1.4,以下工作:

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

用法:

<div include="'path/to/my/template.html'"></div> 

有,然而,有一个问题:模板不能是动态的(如,传递变量通过范围,因为$范围或任何DI在templateUrl中无法访问 - 请参阅this issue),只能传递一个字符串(就像上面的html代码片段一样)。要绕过这一特定问题,这段代码应该做的伎俩(荣誉给this plunker):

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)); 
       } 
      ); 
     } 
    }; 
}); 

用法:

<div include="myTplVariable"></div> 
+0

我不得不认为我的解决方案对于实际问题的解决方案还是比较好的。如果这对你有效,那很好。 – finishingmove

+0

你的回答是绝对正确的,并把我放在正确的方向(荣誉!)。我确实需要这个功能可以在我的整个模板结构中重用。我无法为每个包含声明一个新指令。 –

+0

......这完全是另一回事(没有提及 - 或者我没有很好的阅读?):)既然你基本上重新发明了'ng-include',如果遇到问题,请检查它的来源一路上。干杯:) – finishingmove

1

对于任何人谁碰巧访问了这个问题:

至于角1.1.4+,你可以使用templateURL中的一个函数来使其变为动态的。

退房这对方的回答here

0

有了正确的设置,您可以定义自己的ngInclude指令,可以改为运行由Angular.js提供的一个,防止内置指令永远执行。

为了防止角内置指令从执行关键的是要设定指令的优先级高于内置指令(400为ngIncludeterminal属性设置为true

后这一点,你需要提供获取模板,并与编译模板HTML替换元素的DOM节点的链接后功能

警告的话:这是相当严厉的,你重新定义ngInclude的行为你的整个应用程序,因此我设置了指令b不在myApp,但在我自己的指令之一,以限制其范围。如果您想在整个应用程序范围内使用它,您可能希望使其行为可配置,例如如果在HTML中设置了replace属性,则只有替换为元素,并且默认情况下回到设置innerHtml。

另外:这可能不适合动画。原始ngInclude指令的代码更长,所以如果您在应用程序中使用动画,请将原始代码与`$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); 
相关问题