パーシャルとテンプレートの複雑な入れ子


503

私の質問は、AngularJSアプリケーションでテンプレートパーシャルとも呼ばれる)の複雑なネストを処理する方法に関係しています。

私の状況を説明する最良の方法は、私が作成した画像を使用することです:

AngularJSページ図

ご覧のように、これは多くのネストされたモデルを持つかなり複雑なアプリケーションになる可能性があります。

アプリケーションは単一ページであるため、DOMに属性を持つdiv要素を含むindex.htmlをロードしng-viewます。

サークル1の場合、適切なテンプレートをにロードするプライマリナビゲーションがあることがわかりますng-view。これを行う$routeParamsには、メインアプリモジュールに渡します。これが私のアプリにあるものの例です:

angular.module('myApp', []).
    config(['$routeProvider', function($routeProvider) {
        $routeProvider.                     
            when("/job/:jobId/zones/:zoneId", { controller: JobDetailController, templateUrl: 'assets/job_list_app/templates/zone_edit.html' }).
            when("/job/:jobId/initial_inspection", { controller: JobDetailController, templateUrl: 'assets/job_list_app/templates/initial_inspection.html' }).
            when("/job/:jobId/zones/:zoneId/rooms/:roomId", { controller: JobDetailController, templateUrl: 'assets/job_list_app/templates/room_edit.html' })       

    }]);

サークル2では、に読み込まれるテンプレートにng-view追加のサブナビゲーションがあります。このサブナビゲーションは、その下の領域にテンプレートをロードする必要があります-ng-viewはすでに使用されているため、これを実行する方法がわかりません。

追加のテンプレートを1番目のテンプレートに含めることができることはわかっていますが、これらのテンプレートはすべてかなり複雑になります。アプリケーションを更新しやすくし、子にアクセスするためにロードする必要がある親テンプレートに依存しないようにするために、すべてのテンプレートを別々に保持したいと思います。

サークル3では、状況がさらに複雑になっていることがわかります。サブナビゲーションテンプレートには、独自のテンプレートをサークル4の領域にロードする必要がある2番目のサブナビゲーションが含まれる可能性があります。

AngularJSアプリを構造化して、テンプレートのこのような複雑な入れ子を処理しながら、テンプレートをすべて互いに分離したままにするにはどうすればよいですか?


3
まだこのスレッドをフォローしている場合は、これに対処するための新しいAngularUIプロジェクトへのリンクと、私の回答へのディレクティブを必要とせずにサブルートを利用する3番目のデモを追加しました。
ProLoser 2013年

2
これはどうですか?bennadel.com/blog/...
ericbae

82
私が長い間見た中で最も美しい質問:)
Mark Nadig 2013年

2
同意した!モックアップの使用が大好き
ブライアンホン

4
ここの質問に直接代替案へのリンクを追加するとよいでしょう。github.com/angular-ui/ui-router github.com/artch/angular-route-segment github.com/dotJEM/angular-routing
Jens

回答:


171

ええと、現在1つのngViewディレクティブしか持てないので...ネストされたディレクティブコントロールを使用しています。これにより、テンプレートを設定し、それらの間でスコープを継承(または分離)できます。それ以外では、ng-switchまたはng-showを使用して、$ routeParamsからの入力に基づいて、表示しているコントロールを選択します。

編集これが私が話していることのアイデアをあなたに与えるためのいくつかの疑似コードの例です。ネストされたサブナビゲーション。

こちらがアプリのメインページです

<!-- primary nav -->
<a href="#/page/1">Page 1</a>
<a href="#/page/2">Page 2</a>
<a href="#/page/3">Page 3</a>

<!-- display the view -->
<div ng-view>
</div>

サブナビゲーションのディレクティブ

app.directive('mySubNav', function(){
    return {
        restrict: 'E',
        scope: {
           current: '=current'
        },
        templateUrl: 'mySubNav.html',
        controller: function($scope) {
        }
    };
});

サブナビゲーション用のテンプレート

<a href="#/page/1/sub/1">Sub Item 1</a>
<a href="#/page/1/sub/2">Sub Item 2</a>
<a href="#/page/1/sub/3">Sub Item 3</a>

メインページのテンプレート(プライマリナビゲーションから)

<my-sub-nav current="sub"></my-sub-nav>

<ng-switch on="sub">
  <div ng-switch-when="1">
      <my-sub-area1></my-sub-area>
  </div>
  <div ng-switch-when="2">
      <my-sub-area2></my-sub-area>
  </div>
  <div ng-switch-when="3">
      <my-sub-area3></my-sub-area>
  </div>
</ng-switch>

メインページのコントローラー。(プライマリナビゲーションから)

app.controller('page1Ctrl', function($scope, $routeParams) {
     $scope.sub = $routeParams.sub;
});

サブエリアのディレクティブ

app.directive('mySubArea1', function(){
    return {
        restrict: 'E',
        templateUrl: 'mySubArea1.html',
        controller: function($scope) {
            //controller for your sub area.
        }
    };
});

9
私はProLoserのソリューションの方が好きです。私たちはアプリでそのようなことを行い、それはうまくいきました。bleshのソリューションの問題は、ディレクティブに入るコントローラーコードです。通常、ディレクティブで指定するコントローラーは、exおよびngModelCtrlのディレクティブと密接に連携するコントローラーで、入力およびその他のディレクティブと密接に連携します。コントローラーコードをディレクティブ内に配置すると、コードのにおいがしますが、実際には独立したコントローラーです。
ChrisOdney

@blesh、いいね!説明は本当に良さそうですが、優れたJSプログラマーであり、AngularJSの初心者として、私はそれをうまく理解できます...私とコミュニティは、そのアプローチを使用して動作するサンプルへのJSFiddleリンクを本当に楽しんでいます。それを掘り下げることは理解しやすいでしょう!:)ありがとう
Roger Barreto

8
このソリューションは、「ネストされたビューが機能しなかった」という質問に対する最初の回答になるはずだと思います。ui-routerなどを使用するのではなく、Angularイデオロギーにはるかに近いからです。ありがとうございます。
セルゲイパンフィロフ2013年

答えはディレクティブですか?
Marc M.

これを使用できるサブナビゲーション項目を強調表示するには:coder1.com/articles/angularjs-managing-active-nav-elementsこれはこれを行う良い方法ですか?
escapeccat 2014年

198

更新: この問題に対処するためにAngularUIの新しいプロジェクトをチェックしてください


サブセクションの場合、ng-includeで文字列を利用するのと同じくらい簡単です。

<ul id="subNav">
  <li><a ng-click="subPage='section1/subpage1.htm'">Sub Page 1</a></li>
  <li><a ng-click="subPage='section1/subpage2.htm'">Sub Page 2</a></li>
  <li><a ng-click="subPage='section1/subpage3.htm'">Sub Page 3</a></li>
</ul>
<ng-include src="subPage"></ng-include>

または、至る所にサブページへのリンクがある場合は、オブジェクトを作成できます。

$scope.pages = { page1: 'section1/subpage1.htm', ... };
<ul id="subNav">
  <li><a ng-click="subPage='page1'">Sub Page 1</a></li>
  <li><a ng-click="subPage='page2'">Sub Page 2</a></li>
  <li><a ng-click="subPage='page3'">Sub Page 3</a></li>
</ul>
<ng-include src="pages[subPage]"></ng-include>

またはあなたも使うことができます $routeParams

$routeProvider.when('/home', ...);
$routeProvider.when('/home/:tab', ...);
$scope.params = $routeParams;
<ul id="subNav">
  <li><a href="#/home/tab1">Sub Page 1</a></li>
  <li><a href="#/home/tab2">Sub Page 2</a></li>
  <li><a href="#/home/tab3">Sub Page 3</a></li>
</ul>
<ng-include src=" '/home/' + tab + '.html' "></ng-include>

各パーシャルの最上位レベルにng-controllerを置くこともできます


8
私はあなたの解決策がより好きです。私はAngularの初心者ですが、今日までのWebの見方から、これははるかに理解しやすいようです。誰が知っているか、ブレッシュはそれを行うためにより多くの角度のフレームワークを使用するかもしれませんが、より賢明な方法でより少ないコード行でそれを釘付けにしたようです。ありがとう!
Gleeb 2013年

2
@ProLooserは、おそらくこのリンクgithub.com/angular-ui/ui-routerを意味していました ...貼り付けたものは壊れています
simonC

4
OPと同じデザインの問題があります。誰かがAngularUIの状態メカニズムを試しましたか?私はさらに別のサードパーティライブラリを使用することにかなり消極的で、AngularJSの「やり方」に固執したいと思います。しかし、一方で、ルーティングシステムはそのアキレス腱のようです... @PhillipKregg、このシナリオを解決するために何を使用したのですか?
2013

4
<div ng-include="'/home/' + tab + '.html'" ng-controller="SubCtrl"></div>サブテンプレートに別のコントローラー/スコープを使用するように指定できます。またはngController、サブテンプレート内の任意の場所でディレクティブを指定して、パーシャルごとに異なるコントローラーを使用します。
colllin 2013

2
@DerekAdairプロジェクトはかなり安定していて(バージョン番号はありますが)、いくつかの場所で本番環境で使用されています。不必要なコントローラーのリロードを防ぎ、私の提案するソリューションのはるかに優れた代替手段です。
ProLoser 2013

26

同じ目的でこのライブラリをチェックアウトすることもできます:

http://angular-route-segment.com

それはあなたが探しているもののように見え、ui-routerよりもはるかに簡単に使用できます。デモサイトから:

JS:

$routeSegmentProvider.

when('/section1',          's1.home').
when('/section1/:id',      's1.itemInfo.overview').
when('/section2',          's2').

segment('s1', {
    templateUrl: 'templates/section1.html',
    controller: MainCtrl}).
within().
    segment('home', {
        templateUrl: 'templates/section1/home.html'}).
    segment('itemInfo', {
        templateUrl: 'templates/section1/item.html',
        controller: Section1ItemCtrl,
        dependencies: ['id']}).
    within().
        segment('overview', {
            templateUrl: 'templates/section1/item/overview.html'}).

トップレベルHTML:

<ul>
    <li ng-class="{active: $routeSegment.startsWith('s1')}">
        <a href="/section1">Section 1</a>
    </li>
    <li ng-class="{active: $routeSegment.startsWith('s2')}">
        <a href="/section2">Section 2</a>
    </li>
</ul>
<div id="contents" app-view-segment="0"></div>

ネストされたHTML:

<h4>Section 1</h4>
Section 1 contents.
<div app-view-segment="1"></div>

アルテム、あなたのものは私が今までに見つけた最高のソリューションです!Angular UIのように置き換えるのではなく、Angle Routeを拡張するのが好きです。
LastTribunal 2014

17

私もAngularでネストされたビューに苦労していました。

ui-routerを手に入れたら、角度のあるデフォルトのルーティング機能に戻ることはないことを知りました。

複数のレベルのビューのネストを使用するアプリケーションの例を次に示します

app.config(function ($stateProvider, $urlRouterProvider,$httpProvider) {
// navigate to view1 view by default
$urlRouterProvider.otherwise("/view1");

$stateProvider
    .state('view1', {
        url: '/view1',
        templateUrl: 'partials/view1.html',
        controller: 'view1.MainController'
    })
    .state('view1.nestedViews', {
        url: '/view1',
        views: {
            'childView1': { templateUrl: 'partials/view1.childView1.html' , controller: 'childView1Ctrl'},
            'childView2': { templateUrl: 'partials/view1.childView2.html', controller: 'childView2Ctrl' },
            'childView3': { templateUrl: 'partials/view1.childView3.html', controller: 'childView3Ctrl' }
        }
    })

    .state('view2', {
        url: '/view2',
    })

    .state('view3', {
        url: '/view3',
    })

    .state('view4', {
        url: '/view4',
    });
});

ご覧のとおり、4つのメインビュー(view1、view2、view3、view4)があり、view1には3つの子ビューがあります。


2
注射の目的は何$httpProviderですか?私はそれがどこでも使われるのを見ません。
アーロン

@Aaron app.configはこのコードの一部で終わっておらず、$ httpProviderが別の場所で使用されている可能性があり ます
Vlad

4

ng-includeを使用して、ネストされたng-viewsの使用を回避できます。

http://docs.angularjs.org/api/ng/directive/ngInclude
http://plnkr.co/edit/ngdoc:example-example39@snapshot?p=preview

私のインデックスページはng-viewを使用しています。次に、フレームを入れ子にする必要のあるサブページに。ng-includeを使用しています。デモはドロップダウンを示しています。私はリンクをng-clickに置き換えました。関数に$ scope.template = $ scope.templates [0];を配置します。または$ scope.template = $ scope.templates [1];

$scope.clickToSomePage= function(){
  $scope.template = $scope.templates[0];
};

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.