Bersarang parsial dan templat yang kompleks


503

Pertanyaan saya melibatkan bagaimana untuk pergi tentang berurusan dengan bersarang kompleks template (juga disebut parsial ) dalam aplikasi AngularJS.

Cara terbaik untuk menggambarkan situasi saya adalah dengan gambar yang saya buat:

Diagram Halaman AngularJS

Seperti yang Anda lihat ini berpotensi menjadi aplikasi yang cukup kompleks dengan banyak model bersarang.

Aplikasi ini satu halaman, sehingga memuat index.html yang berisi elemen div di DOM dengan ng-viewatribut.

Untuk lingkaran 1 , Anda melihat bahwa ada navigasi Utama yang memuat templat yang sesuai ke dalam ng-view. Saya melakukan ini dengan meneruskan $routeParamske modul aplikasi utama. Berikut ini contoh apa yang ada di aplikasi saya:

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' })       

    }]);

Di lingkaran 2 , templat yang dimuat ke dalam ng-viewmemiliki sub-navigasi tambahan . Sub-nav ini kemudian perlu memuat template ke area di bawahnya - tetapi karena ng-view sudah digunakan, saya tidak yakin bagaimana cara melakukan hal ini.

Saya tahu bahwa saya dapat menyertakan templat tambahan dalam templat pertama, tetapi templat ini semuanya akan menjadi sangat kompleks. Saya ingin menyimpan semua templat terpisah agar aplikasi lebih mudah diperbarui dan tidak memiliki ketergantungan pada templat induk yang harus dimuat untuk mengakses anak-anaknya.

Di lingkaran 3 , Anda dapat melihat berbagai hal semakin kompleks. Ada kemungkinan bahwa template sub-navigasi akan memiliki sub-navigasi ke-2 yang perlu memuat template-nya sendiri juga ke area dalam lingkaran 4

Bagaimana cara seseorang menyusun struktur aplikasi AngularJS untuk menangani templat templat yang begitu rumit sambil tetap memisahkannya satu sama lain?


3
Jika Anda masih mengikuti utas ini, saya menambahkan tautan ke proyek AngularUI baru untuk mengatasi ini dan demo ketiga yang didukung oleh subrout tanpa perlu arahan untuk jawaban saya.
ProLoser

2
bagaimana dengan yang ini? bennadel.com/blog/…
ericbae

82
pertanyaan tercantik yang pernah saya lihat dalam waktu yang lama :)
Mark Nadig

2
sepakat! Cinta penggunaan mockup
Bryan Hong

4
Akan bagus untuk menambahkan tautan ke alternatif secara langsung di pertanyaan di sini. github.com/angular-ui/ui-router github.com/artch/angular-route-segment github.com/dotJEM/angular-routing
Jens

Jawaban:


171

Yah, karena saat ini Anda hanya dapat memiliki satu arahan ngView ... Saya menggunakan kontrol arahan bersarang. Ini memungkinkan Anda untuk mengatur templating dan mewarisi (atau mengisolasi) cakupan di antaranya. Di luar itu saya menggunakan ng-switch atau bahkan hanya ng-show untuk memilih kontrol yang saya tampilkan berdasarkan apa yang datang dari $ routeParams.

EDIT Berikut ini beberapa contoh pseudo-code untuk memberi Anda gambaran tentang apa yang saya bicarakan. Dengan sub navigasi bersarang.

Inilah halaman aplikasi utama

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

Arahan untuk sub navigasi

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

template untuk sub navigasi

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

template untuk halaman utama (dari nav primer)

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

Kontroler untuk halaman utama. (dari nav utama)

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

Arahan untuk Sub Area

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

9
Saya suka solusi ProLoser dengan lebih baik, kami melakukan sesuatu seperti itu pada aplikasi kami dan itu telah bekerja dengan baik. Masalah dengan solusi blesh adalah kode pengontrol masuk ke arahan. Biasanya controller yang Anda tentukan dalam direktif adalah yang bekerja erat dengan direktif untuk ex: ngModelCtrl yang bekerja erat dengan input dan arahan lainnya. Jika Anda menempatkan kode pengontrol di dalam direktif akan menjadi bau kode, sebenarnya pengontrol independen.
ChrisOdney

@blesh, bagus! Tampaknya sangat bagus dijelaskan tetapi sebagai programmer JS yang baik dan pemula di AngularJS saya tidak bisa menangkap itu dengan baik ... Saya dan masyarakat akan sangat menikmati tautan JSFiddle ke sampel yang berfungsi menggunakan pendekatan itu. Diggin sekitar itu akan mudah dimengerti! :) Terima kasih
Roger Barreto

8
Saya pikir solusi ini harus menjadi jawaban pertama untuk setiap pertanyaan 'pandangan bersarang tidak berfungsi'. Hanya karena jauh lebih dekat dengan ideologi Angular daripada menggunakan ui-router dan lain-lain. Terima kasih.
Sergei Panfilov

Jadi jawabannya adalah arahan?
Marc M.

untuk menyorot sub-item nav Anda bisa menggunakan ini: coder1.com/articles/angularjs-managing-active-nav-elements apakah ini cara yang baik untuk melakukannya?
escapedcat

198

PEMBARUAN: Lihat proyek baru AngularUI untuk mengatasi masalah ini


Untuk subbagian semudah memanfaatkan string di ng-meliputi:

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

Atau Anda dapat membuat objek jika Anda memiliki tautan ke sub halaman di semua tempat:

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

Atau Anda bahkan bisa menggunakannya $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>

Anda juga dapat menempatkan ng-controller di level paling atas dari setiap parsial


8
Saya lebih suka solusi Anda. Saya seorang pemula untuk Angular dan ini tampaknya jauh lebih dimengerti dari bagaimana saya melihat web sampai hari ini. siapa tahu, mungkin blesh menggunakan lebih banyak kerangka angular untuk melakukannya, tetapi sepertinya Anda memakukannya dengan lebih sedikit baris kode dengan cara yang lebih masuk akal. Terima kasih!
Gleeb

2
@ProLooser mungkin maksud Anda tautan ini github.com/angular-ui/ui-router ... yang Anda
tempelkan

4
Saya mengalami masalah desain yang sama dengan OP. Adakah yang pernah mencoba mekanisme status AngularUI? Saya cukup enggan untuk menggunakan perpustakaan pihak ke-3 dan saya lebih suka tetap dengan AngularJS 'cara melakukan sesuatu'. Tetapi di sisi lain, sistem perutean tampaknya menjadi kelemahan Achilles ... @PhillipKregg, apa yang akhirnya Anda gunakan untuk menyelesaikan skenario ini?
Sam

4
Anda dapat menentukan <div ng-include="'/home/' + tab + '.html'" ng-controller="SubCtrl"></div>untuk menggunakan pengontrol / ruang lingkup terpisah untuk sub-template. Atau cukup tentukan ngControllerarahan di mana saja dalam sub-templat Anda untuk menggunakan pengontrol yang berbeda untuk setiap parsial.
colllin

2
@DerekAdair proyek ini cukup stabil (meskipun nomor versi) dan digunakan dalam produksi di beberapa tempat. Ini mencegah reload yang tidak perlu, dan merupakan alternatif yang jauh lebih baik untuk solusi yang saya sarankan.
ProLoser

26

Anda dapat checkout perpustakaan ini untuk tujuan yang sama juga:

http://angular-route-segment.com

Sepertinya apa yang Anda cari, dan itu jauh lebih mudah digunakan daripada ui-router. Dari situs demo :

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 tingkat atas:

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

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

Artem, solusi Anda adalah yang terbaik yang saya temukan hingga saat ini! Saya suka fakta bahwa Anda memperluas rute sudut daripada menggantikannya seperti sudut ui.
LastTribunal

17

Saya juga berjuang dengan pandangan bersarang di Angular.

Setelah saya mendapatkan ui-router saya tahu saya tidak akan pernah kembali ke fungsi routing default sudut.

Berikut adalah contoh aplikasi yang menggunakan beberapa tingkat penayangan bersarang

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',
    });
});

Seperti dapat dilihat ada 4 tampilan utama (view1, view2, view3, view4) dan view1 memiliki 3 tampilan anak.


2
Apa tujuan dari suntikan $httpProvider? Saya tidak melihatnya digunakan di mana pun.
Aaron

@Aaron app.config tidak berakhir pada bagian kode ini dan mungkin $ httpProvider digunakan di tempat lain
Vlad

4

Anda dapat menggunakan ng-include untuk menghindari penggunaan n-ng dilihat.

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

Halaman indeks saya saya gunakan ng-view. Kemudian pada halaman saya yang saya perlu memiliki frame bersarang. Saya menggunakan ng-include. Demo menunjukkan dropdown. Saya mengganti milik saya dengan tautan ng-klik. Dalam fungsi ini saya akan meletakkan $ scope.template = $ scope.templates [0]; atau $ scope.template = $ scope.templates [1];

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.