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. =)
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)
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With