501 votes

Emboîtement complexe de partiels et de modèles

Ma question porte sur la manière de traiter les imbrications complexes de modèles (é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, il s'agit d'une application potentiellement assez complexe, avec de nombreux modèles imbriqués.

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

Pour le cercle 1 Vous voyez qu'il y a une navigation primaire qui charge les modèles appropriés dans le fichier 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 qui est chargé dans le ng-view dispose d'un sous-navigation . Cette sous-navigation doit ensuite charger des modèles dans la zone située en dessous d'elle - mais comme ng-view est déjà utilisé, je ne sais pas trop comment m'y prendre.

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

Dans le cercle 3 Vous pouvez voir que les choses deviennent encore plus complexes. Il est possible que les modèles de sous-navigation aient une valeur de 2ème sous-navigation qui devra également charger ses propres modèles dans la zone située à l'adresse cercle 4

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

198voto

ProLoser Points 2927

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


Pour les sous-sections, il suffit d'utiliser les chaînes de caractères 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>

Vous pouvez également créer un objet au cas où vous auriez des liens vers des sous-pages un peu 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>

Vous pouvez également 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 placer un ng-controller au niveau le plus élevé de chaque partiel

171voto

Ben Lesh Points 39290

Eh bien, puisque vous ne pouvez actuellement avoir qu'une seule directive ngView... J'utilise des contrôles de directives imbriquées. Cela vous permet de mettre en place un modèle et d'hériter (ou d'isoler) des champs d'application entre eux. En dehors de cela, j'utilise ng-switch ou même simplement ng-show pour choisir les contrôles que j'affiche en fonction de ce qui vient de $routeParams.

EDITAR 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 de page principale (à partir de la navigation principale)

<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. (à partir de la page principale)

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

Directive pour un sous-domaine

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

26voto

artch Points 780

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

http://angular-route-segment.com

Il ressemble à ce que vous recherchez, et il est beaucoup plus simple à utiliser que ui-router. Depuis le site 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="http://stackoverflow.com/section1">Section 1</a>
    </li>
    <li ng-class="{active: $routeSegment.startsWith('s2')}">
        <a href="http://stackoverflow.com/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>

17voto

Dan Ochiana Points 56

J'ai moi aussi eu du mal avec les vues imbriquées dans Angular.

Une fois que j'ai mis la main sur ui-routeur Je savais que je ne reviendrais jamais à la fonctionnalité de routage par défaut d'Angular.

Voici un exemple d'application qui utilise 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 (vue 1, vue 2, vue 3, vue 4) et la vue 1 a 3 vues enfant.

4voto

Henry Mac Points 21

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

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

Pour ma page d'index, j'utilise ng-view. Ensuite, sur mes pages secondaires qui ont besoin d'avoir des cadres imbriqués, j'utilise ng-include. 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];
};

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X