web-dev-qa-db-fra.com

Imbrication complexe de partiels et de modèles

Ma question concerne la gestion de l’imbrication complexe de templates (également appelé partiels) dans une application AngularJS.

La meilleure façon de décrire ma situation est d'utiliser une image que j'ai créée:

AngularJS Page Diagram

Comme vous pouvez le constater, cette application est potentiellement complexe et comporte de nombreux modèles imbriqués.

L'application est à page unique, elle charge donc un index.html qui contient un élément div dans le DOM avec l'attribut ng-view.

Pour le cercle 1, vous voyez qu’une navigation principale charge les modèles appropriés dans le ng-view. Je le fais en passant $routeParams au module principal de l'application. Voici un exemple de ce que contient mon application:

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

    }]);

Dans le cercle 2, le modèle chargé dans le ng-view a un autre sous-navigation. Ce sous-navigateur doit ensuite charger des modèles dans la zone située en dessous - mais, vu que ng-view est déjà utilisé, je ne sais pas comment procéder.

Je sais que je peux inclure des modèles supplémentaires dans le premier modèle, mais ces modèles seront tous assez complexes. Je souhaite que tous les modèles soient séparés afin de rendre l'application plus facile à mettre à jour et de ne pas avoir à dépendre du modèle parent devant être chargé pour pouvoir accéder à ses enfants.

Dans le cercle, vous pouvez voir que les choses deviennent encore plus complexes. Il est possible que les modèles de sous-navigation aient un 2ème sous-navigation qui devra également charger ses propres modèles dans la zone cercle 4

Comment peut-on structurer une application AngularJS pour gérer une imbrication aussi complexe de modèles tout en les gardant séparés les uns des autres?

499
PhillipKregg

Eh bien, comme vous ne pouvez actuellement avoir qu’une seule directive ngView ... j’utilise des contrôles de directive imbriqués. Cela vous permet de configurer des modèles et d'hériter (ou d'isoler) des étendues entre eux. En dehors de cela, j'utilise ng-switch ou même simplement ng-show pour choisir les commandes à afficher en fonction de ce qui vient de $ routeParams.

EDIT Voici un exemple de pseudo-code pour vous donner une idée de ce dont je parle. Avec une sous navigation imbriquée.

Voici la page principale de l'application

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

Directive pour la sous navigation

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

modèle pour la sous navigation

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

modèle pour une page principale (depuis le navigateur principal)

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

Contrôleur pour une page principale. (du nav primaire)

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

Directive pour une sous-zone

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

UPDATE: Découvrez le nouveau projet d'AngularUI pour résoudre ce problème


Pour les sous-sections, il est aussi simple que de tirer parti des chaînes dans 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>

Ou vous pouvez créer un objet au cas où vous auriez des liens vers des sous-pages partout:

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

Ou vous pouvez même utiliser $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>

Vous pouvez également mettre un contrôleur ng au plus haut niveau de chaque partiel

197
ProLoser

Vous pouvez également acheter cette bibliothèque dans le même but:

http://angular-route-segment.com

Cela ressemble à ce que vous recherchez et il est beaucoup plus simple à utiliser que ui-router. Depuis le site de démonstration :

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 de premier niveau:

<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 imbriqué:

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

Moi aussi, je me débattais avec des vues imbriquées dans Angular.

Une fois que j’ai eu la main sur i-router je savais que je ne revenais jamais à la fonctionnalité de routage par défaut angular.

Voici un exemple d'application utilisant plusieurs niveaux d'imbrication de vues.

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

Comme on peut le voir, il y a 4 vues principales (view1, view2, view3, view4) et view1 a 3 vues enfants.

17
Dan Ochiana

Vous pouvez utiliser ng-include pour éviter d'utiliser des vues ng imbriquées.

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

Ma page d'index j'utilise ng-view. Ensuite, sur mes sous-pages, il me faut des cadres imbriqués. J'utilise ng-include. La démo montre une liste déroulante. J'ai remplacé le mien par un lien ng-click. Dans la fonction, je mettrais $ scope.template = $ scope.templates [0]; ou $ scope.template = $ scope.templates [1];

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

Le routeur ui angulaire prend en charge les vues imbriquées. Je ne l'ai pas encore utilisé mais j'ai l'air très prometteur.

http://angular-ui.github.io/ui-router/

2
Adriaan Bouman