私はangularアプリをプレーンHTMLデモから作成しているので、ng-includeが余分なDOM要素を使用しないようにする方法に頭を悩ませています。私は働いています。完全に開発された、DOMで結合されたCSS(SASSから作成)を使用したかなりスリムなHTMLで、リファクタリングは絶対に避けたいものです。
実際のコードは次のとおりです。
<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>
<section>を繰り返し要素にする必要がありますが、独自のロジックと異なるコンテンツを持っています。内容と繰り返し回数はどちらもビジネスロジックに依存します。ご覧のとおり、ng-controllerとng-repeatを<section>要素に配置しても機能しません。ただし、新しいDOMノードを挿入するとどうなるでしょうか。これは、回避しようとしていることです。
私は何を逃していますか?これはベストプラクティスですか、それとももっと良い方法がありますか?
[〜#〜] edit [〜#〜]:コメントで尋ねられたように明確にするために、私が生成しようとしている最終的な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(subheader.html)を使用したいのは、コードをクリーンにするためです。動的コンテンツを返すために、subheader.htmlになんらかのng-switchがあると思います。
しかし、基本的に、下層の静止はDOMノードを使用せずにテンプレートのコンテンツを透過的に含める方法はありますか?
EDIT2:ソリューションは再利用可能である必要があります。 =)
他の回答のいくつかはreplace:true
を示唆していますが、テンプレートのreplace:true
は 非推奨としてマークされています であることに注意してください。
代わりに、 同様の質問への回答 で代替案を見つけます。これにより、次のように記述できます。
<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());
}
};
});
(他の答えからカットアンドペースト)
編集:いくつかの調査の後、完全を期すために、いくつかの情報を追加しました。 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>
ただし、1つの落とし穴があります。つまり、テンプレートを動的にすることはできません($ scopeなどのスコープを介して変数を渡すなど) [〜#〜] di [〜#〜] templateUrlではアクセスできません- この問題 を参照)、渡せるのは文字列だけです(上記のhtmlスニペットのように)。この特定の問題を回避するために、このコードはトリックを実行する必要があります(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));
}
);
}
};
});
使用法:
<div include="myTplVariable"></div>
カスタムディレクティブを作成し、templateUrl
プロパティを使用してテンプレートにリンクし、replace
をtrue
に設定できます。
app.directive('myDirective', function() {
return {
templateUrl: 'url/to/template',
replace: true,
link: function(scope, elem, attrs) {
}
}
});
これには、ラッパー要素なし、ラッパースコープなしのテンプレートがそのまま含まれます。
適切な設定で、Angular.jsによって提供されるものの代わりに実行できる独自のngInclude
ディレクティブを定義して、組み込みディレクティブが実行されるのを防ぐことができます。
Angular-built-inディレクティブが実行されないようにするには、ディレクティブの優先度を組み込みディレクティブよりも高く設定することが重要です(ngInclude
の場合は400、terminal
プロパティをtrue
に設定します。
その後、テンプレートをフェッチし、要素のDOMノードをコンパイルされたテンプレートHTMLで置き換えるポストリンク関数を提供する必要があります。
警告の言葉:これはかなり厳しいです。アプリケーション全体に対してngInclude
の動作を再定義します。したがって、以下のディレクティブをmyApp
ではなく、自分のディレクティブの1つに設定して、スコープを制限します。アプリケーション全体で使用する場合は、その動作を構成可能にすることができます。のみreplacereplace
属性がHTMLに設定されている場合、デフォルトではinnerHtmlの設定にフォールバックします。
また、これはアニメーションではうまく機能しない可能性があります。元のngInclude
- directiveのコードははるかに長いため、アプリケーションでアニメーションを使用する場合は、元のコードを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);