Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid using extra DOM nodes when using nginclude

Tags:

I'm struggling to wrap my mind around how to have an ng-include not use an extra DOM element as I'm building an angular app from a plain-HTML demo. I'm working with pretty slim HTML with fully developed, tightly DOM-coupled CSS (built from SASS) and refactoring is something I want to avoid at all costs.

Here's the actual code:

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

I need <section> to be a repeating element but have its own logic and different content. Both, content and number of repetitions are dependent on business logic. As you can see, putting the ng-controller and the ng-repeat on the <section> element will not work. What would, however, is to insert a new DOM node, which is what I'm trying to avoid.

What am I missing out? Is this best practice or is there a better way?


EDIT: just to clarify as asked in comments, the final HTML I'm trying to generate would be:

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

The reason I want to use the same template B (subheader.html), is for code cleanliness. I conceive subheader.html to have some kind of ng-switch in order to return dynamic content.

But basically, the underlaying quiestion is: is there a way to include the contents of a template transparently, without using a DOM node?


EDIT2: The solution needs to be reusable. =)

like image 669
Phil Thomas Avatar asked Jul 11 '13 09:07

Phil Thomas


2 Answers

Some of the other answers suggest replace:true, but keep in mind that replace:true in templates is marked for deprecation.

Instead, in an answer to a similar question, we find an alternative: It allows you to write:

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

Custom Directive:

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

(cut'n'paste from the other answer)

like image 142
Peter V. Mørch Avatar answered Oct 21 '22 09:10

Peter V. Mørch


Edit: After some research and for the sake of completeness, I've added some info. Since 1.1.4, the following works:

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

Usage:

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

There is, however, one gotcha: the template cannot be dynamic (as in, passing a variable through scope because $scope, or any DI for that matter, is not accessible in templateUrl - see this issue), only a string can be passed (just like the html snippet above). To bypass that particular issue, this piece of code should do the trick (kudos to 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));                 }             );         }     }; }); 

Usage:

<div include="myTplVariable"></div> 
like image 37
14 revs, 2 users 99% Avatar answered Oct 21 '22 11:10

14 revs, 2 users 99%