Anidamiento complejo de parciales y plantillas


Mi pregunta involucra cómo lidiar con el anidamiento complejo de plantillas (también llamadas parciales) en una aplicación AngularJS.

La mejor manera de describir mi situación es con una imagen que he creado:

Diagrama de Página de AngularJS

Como puede ver, esto tiene el potencial de ser una aplicación bastante compleja con muchos modelos anidados.

La aplicación es de una sola página, por lo que carga un índice .html que contiene un elemento div en el DOM con el ng-view atributo.

Para el círculo 1 , verá que hay una navegación primaria que carga las plantillas apropiadas en el ng-view. Estoy haciendo esto pasando $routeParams al módulo principal de la aplicación. Este es un ejemplo de lo que hay en mi aplicación:

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

    }]);

En el círculo 2 , la plantilla que se carga en el ng-view tiene un sub-navegación adicional . Este sub-nav luego necesita cargar plantillas en el área debajo de él, pero como ng-view ya se está utilizando, no estoy seguro cómo hacer esto.

Sé que puedo incluir plantillas adicionales dentro de la 1a plantilla, pero todas estas plantillas serán bastante complejas. Me gustaría mantener todas las plantillas separadas para hacer que la aplicación sea más fácil de actualizar y no tener una dependencia de la plantilla padre que tiene que cargarse para acceder a sus hijos.

En el círculo 3 , se puede ver que las cosas se vuelven aún más complejas. Existe el potencial de que la sub-navegación las plantillas tendrán un 2nd sub-navigation que necesitará cargar sus propias plantillas también en el área en circle 4

¿Cómo se puede estructurar una aplicación AngularJS para lidiar con un anidamiento tan complejo de plantillas mientras se mantienen separadas unas de otras?

Author: Blackhole, 2012-10-12

6 answers

Bueno, ya que actualmente solo puede tener una directiva ngView... Uso controles de directiva anidados. Esto le permite configurar plantillas y heredar (o aislar) ámbitos entre ellos. Fuera de eso, uso ng-switch o incluso solo ng-show para elegir qué controles estoy mostrando en función de lo que viene de rout routeParams.

EDIT Aquí hay un ejemplo de pseudo-código para darte una idea de lo que estoy hablando. Con una navegación secundaria anidada.

Aquí está la aplicación principal page

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

Directiva para la sub-navegación

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

Plantilla para la navegación secundaria

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

Plantilla para una página principal (de nav primario)

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

Controlador para una página principal. (del nav primario)

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

Directiva relativa a una subzona

app.directive('mySubArea1', function(){
    return {
        restrict: 'E',
        templateUrl: 'mySubArea1.html',
        controller: function($scope) {
            //controller for your sub area.
        }
    };
});
 167
Author: Ben Lesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-12 17:44:19

ACTUALIZAR: Echa un vistazo al nuevo proyecto de AngularUI para abordar este problema


Para subsecciones es tan fácil como aprovechar cadenas en 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>

O puede crear un objeto en caso de que tenga enlaces a subpáginas en todo el lugar:

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

O incluso puedes usar $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>

También puede poner un controlador ng en el nivel más alto de cada parcial

 197
Author: ProLoser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-01 08:32:44

Usted puede comprar esta biblioteca para el mismo propósito también:

Http://angular-route-segment.com

Se parece a lo que está buscando, y es mucho más simple de usar que ui-router. Desde el sitio de demostración :

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 nivel superior:

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

<h4>Section 1</h4>
Section 1 contents.
<div app-view-segment="1"></div>
 26
Author: artch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-22 20:26:02

Yo también estaba luchando con vistas anidadas en Angular.

Una vez que obtuve un control de ui-router Supe que nunca volvería a la funcionalidad de enrutamiento predeterminado de angular.

Aquí hay una aplicación de ejemplo que utiliza múltiples niveles de anidamiento de vistas

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

Como se puede ver,hay 4 vistas principales (view1,view2,view3, view4) y view1 tiene 3 vistas secundarias.

 17
Author: Dan Ochiana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-03 11:51:44

Puede usar ng-include para evitar usar ng-views anidadas.

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

Mi página de índice uso ng-view. Luego en mis subpáginas que necesito tener marcos anidados. Yo uso ng-include. La demostración muestra un menú desplegable. Reemplacé el mío con un link ng-click. En la función yo pondría scope alcance.template =scope scope.plantillas [0]; o scope scope.plantilla = $alcance.plantillas [1];

$scope.clickToSomePage= function(){
  $scope.template = $scope.templates[0];
};
 4
Author: Henry Mac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-27 17:28:33

Angular ui-router soporta vistas anidadas. Aún no lo he usado, pero parece muy prometedor.

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

 2
Author: Adriaan Bouman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-23 15:41:30