Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple module nested ui-router with multiple ui-views

I'm working on a complex UI architecture based on Angular and Angular UI Router. I'm trying to define routes with nested ui-views on multiple modules.

Here is what I'm trying to do: http://plnkr.co/edit/sxJOPQAgyEZfcYfUReGR?p=preview

Files here:

index.html

<body ng-app="app">
    <h1 ui-view="title"></h1>
    <div ui-view="sidebar1"></div>
    <ul ui-view="sidebar2"></ul>
    <div ui-view="content"></div>
</body>

app.js

angular
.module('app', ['ui.router', 'page1'])
.config(['$locationProvider','$stateProvider', '$urlRouterProvider',
  function ($locationProvider, $stateProvider, $urlRouterProvider) {
    $locationProvider.html5Mode(true);
    $stateProvider.state({
      name: "page1",
      url: "/page1",
      abstract: true
    });
    $urlRouterProvider.otherwise('/page1');
}]);

page1.js

angular
.module('page1', ['ui.router'])
.config(function ($stateProvider) {
    $stateProvider.state({
        name: 'page1.main',
        views: {
            title: {
                template: "My Title"
            },
            sidebar1: {
                template: "<ul><li ng-repeat='item on items'>{{item}}</li></ul>",
                controller: function($scope) {
                    $scope.items = ['foo1', 'bar1'];
                }
            },
            sidebar2: {
                template: "<ul><li ng-repeat='item on items'></li></ul>",
                controller: function($scope) {
                    $scope.items = ['foo2', 'bar2'];
                }
            },
            content: {
                template: "<div ng-repeat='one in many'>{{one}}</div>",
                resolve: {
                    stuff: function () { 
                        return [1,2,3,4,5] 
                    }
                },
                controller: function($scope, stuff) {
                    $scope.many = stuff;
                }
            }
         }
    });
});

What am I missing?

Thanks a lot in advance.

like image 278
leog Avatar asked Nov 21 '25 03:11

leog


1 Answers

I've made few changes, and make it running here.

Firstly, as defined in doc: Abstract States, child state of an abstract state must be defined, i.e. must have some url defined (which will help ui-router to find out which state to use... abstract parent is unreachable)

$stateProvider.state({ name: 'page1.main', url : '/main',

And also the default route was changed to:

$urlRouterProvider.otherwise('/page1/main');

And the most important thing is to use correct ui-view naming:

$stateProvider.state({
    name: 'page1.main',
    url : '/main',
    views: {
            "title@": {
                template: "My Title"
            },
            "sidebar1@": {
                template: "<ul><li ng-repeat='item on items'>{{item}}</li></ul>",
                controller: function($scope) {
                    $scope.items = ['foo1', 'bar1'];
                }
            },
            "sidebar2@": {
                template: "<ul><li ng-repeat='item in items'>{{item}}</li></ul>",
                controller: function($scope) {
                    $scope.items = ['foo2', 'bar2'];
                }
            },
            "content@": {
            ...

What we can see, the view names are suffixed with the @, which means: search for them in the top root, unnamed view (usually index.html)

See more here: View Names - Relative vs. Absolute Names

a small extract from doc:

    ///////////////////////////////////////////////////////
    // Absolute Targeting using '@'                      //
    // Targets any view within this state or an ancestor //
    ///////////////////////////////////////////////////////

    // Absolutely targets the 'info' view in this state, 'contacts.detail'.
    // <div ui-view='info'/> within contacts.detail.html
    "[email protected]" : { }

    // Absolutely targets the 'detail' view in the 'contacts' state.
    // <div ui-view='detail'/> within contacts.html
    "detail@contacts" : { }

    // Absolutely targets the unnamed view in parent 'contacts' state.
    // <div ui-view/> within contacts.html
    "@contacts" : { }

The working plunker.

EDIT: How to preserve the /page1 in url

As (almost) always with ui-router, we can give us this behaviour. The trick is, to reset url evaluation to start on the root level - even for child (without parent url part). And this could be done with a magical "^" sign

$stateProvider.state({
    name: 'page1.main',
    url : '^/page1',
    views: {
       .... 

Here is doc:

  • Absolute Routes (^) (a cite)

    If you want to have absolute url matching, then you need to prefix your url string with a special symbol '^'.

Here is a working plunker
like image 126
Radim Köhler Avatar answered Nov 22 '25 17:11

Radim Köhler



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!