2013-07-11 12 views
22

プレーンHTMLデモから角型アプリケーションを構築する際に、ng-includeに余分なDOM要素を使用しないように心がけています。私は非常にスリムなHTMLで、完全に開発されたしっかりとDOM結合されたCSS(SASSから構築されています)を使って作業しています。リファクタリングは、どうしても避けたいものです。私は繰り返し要素であることを<セクション>を必要としますが、独自のロジックと異なる内容を持っている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ノードを挿入するのは何でしょうか。

私は何が欠けていますか?このベストプラクティスですか、それとも良い方法がありますか?


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を使用したい理由(サブヘッダを.html)は、コードの清潔さを保つためのものです。私は、動的コンテンツを返すために、何らかの種類のng-switchを持つようにsubheader.htmlを考えます。

しかし、基本的に、下層の謙虚さは:は、DOMノードを使用せずに透過的にテンプレートの内容を含める方法はありますか?


EDIT2:ソリューションを再利用可能にする必要があります。 =)

+0

バリエーションの例を追加できますか、今あなたが求めているものは? – Chandermani

+0

申し訳ありません。明確にするために編集されました。 –

+0

ng-includeは、タグ ' 'として使用でき、 'url'の内容以外のタグは出力されません。 – Chandermani

答えて

25

他の回答の中には、replace:trueを提案するが、テンプレート内のreplace:truemarked 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プロパティをテンプレートにリンクする、カスタムディレクティブを作成し、truereplaceを設定することができます

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

    } 
    } 
}); 

せずに、任意のラッパー要素なしで、そのままテンプレートが含まれるであろう任意のラッパースコープ

+0

directiveを再利用できるように、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> 

、しかしながら、一つの落とし穴:テンプレートは(動的ことができない、のようにスコープを介して変数を渡すため$ scope、または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

をチェックアウト、あなたはAngular.jsによって提供される一つの代わりに実行し、これまでに実行するための組み込みのディレクティブを防ぐことができ、独自のngIncludeディレクティブを定義することができます。

実行からの角度-内蔵のディレクティブを防ぐためには、ngInclude用(400ビルトインディレクティブのそれよりも高い、あなたのディレクティブの優先順位を設定し、trueterminalプロパティを設定することが重要である。

後それは、あなたがテンプレートをフェッチし、コンパイル済みのテンプレートのHTMLで要素のDOMノードを置き換え後のリンク機能を提供する必要が

警告の言葉を:これはかなり厳しいです、あなたはngIncludeの行動のための再定義しますあなたの全体のアプリケーション。したがって私は、ディレクティブbを設定しました。 myAppにはありませんが、スコープを制限するための私の指示の中にあります。アプリケーション全体で使用したい場合は、その動作を構成可能にすることができます。 の要素を置き換えます。replace属性がHTMLに設定され、デフォルトではinnerHtmlの設定に戻ります。

また、これはアニメーションではうまく動作しない可能性があります。オリジナルのngIncludeディレクティブのコードは長くなります。そのため、アプリケーションでアニメーションを使用する場合は、p元のコードと`$element.replaceWith()にshoehornを貼り付けてください。

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); 
関連する問題