Angular routing ui-view inside another ui-view

Problem

Conception overview:

We have two tabs on index html. There we routing those tabs like that:

<div ui-view></div>

On a second tab we have a selector, that switch tab's content in another ui-view like that:

<div ui-view="{{vm.currentView}}"></div>

where vm.currentView is a name of routing state ('book1' and etc.).

 .state('tab2', {
        abstract: true,
        templateUrl: 'tab2.html',
        controller: 'Tab2Controller',
        controllerAs: 'vm'
    })
    .state('tab2.content', {
        url: '/tab2',
        views: {
            '': {
                templateUrl: 'tab2.html'
            },
            'book1@tab2': {
                templateUrl: 'tab2-book1.html'
            },
            'book2@tab2': {
                templateUrl: 'tab2-book2.html'
            },
            'book3@tab2': {
                templateUrl: 'tab2-book3.html'
            },
            'book4@tab2': {
                templateUrl: 'tab2-book4.html'
            }
        }
    });

Everything is fine, except one thing: data content and name of a view is changing, but a template content isn't.

I resolved it by another way (based on exclude 'ui-view inside another ui-view' conception and separate views in states). But i still want to know: "How to do this with using 'ui-view inside ui-view' conception?"

Here's a Plunker Example

Problem courtesy of: SanSan-

Solution

Its possible to make 'ui-view inside another ui-view'.

Lets say you have an index.html

<div ui-view="content"></div>

and state provider is like this :-

$stateProvider
   .state('books', {
        parent: 'pages',
        url: '/books',                   
        views: {
            'content@': {
                 templateUrl: 'books.html',
                 controller: 'BooksController'
             }
        }
   })

In books.html you have some links and another ui-view (nested ui-view). On click of links populate the nested ui-view.

books.html

<div>
     <a ui-sref="book1"></a>
     <a ui-sref="book2"></a>
     <a ui-sref="book3"></a>
</div>
<!-- nested ui-view -->
<div ui-view="bookDetails"></div>

now state provider is :-

 $stateProvider
    .state('books', {
        parent: 'pages',
        url: '/books',                   
        views: {
            'content@': {
                 templateUrl: 'books.html',
                 controller: 'BooksController'
             }
        }
    })
    .state('book1', {
        parent: 'books',                  
        views: {
            'bookDetails@books': {
                 templateUrl: 'book1.html',
                 controller: 'BookOneController'
             }
        }
    })
    .state('book2', {
        parent: 'books',                 
        views: {
            'bookDetails@books': {
                 templateUrl: 'book2.html',
                 controller: 'BookTwoController'
             }
        }
    })
    .state('book3', {
        parent: 'books',                
        views: {
            'bookDetails@books': {
                 templateUrl: 'book3.html',
                 controller: 'BookThreeController'
             }
        }
    })

bookDetails@books :- populate 'bookDetails' ui-view in 'books' state or we can say that find 'bookDetails' ui-view inside 'books' state and populate it with 'views' object.

Solution courtesy of: Sanjay Singh Rawat

Discussion

As i explained earlier i just want to make 'ui-view inside another ui-view', but it seems impossible. I found two ways to resolve this "bug"(?).

First way: Exclude 'ui-view inside another ui-view' and use 'ng-include'

Simplest variant with minimal change of code. As you see here, i replaced

 <div ui-view="{{vm.currentView}}"></div>

with

 <ng-include src="vm.getTemplateUrl(vm.selectedBook.id)"/>

and add function to controller, thats switch templates:

function getTemplateUrl(id) {
            switch (id) {
                case 0:
                    return 'tab2-book1.html';
                case 1:
                    return 'tab2-book2.html';
                case 2:
                    return 'tab2-book3.html';
                case 3:
                    return 'tab2-book4.html';
                default:
                    return 'tab2-book4.html';
            }
        }

Second way: Formally save 'ui-view inside another ui-view' and separate views by states

And as you see here, formally i save 'ui-view inside ui-view', but in fact i just fully replace single ui-view by template from another single ui-view (can't set second ui-view by name).

$urlRouterProvider
        .when('/tab2', '/tab2/book4');

    $stateProvider
        .state('tab2', {
            url: '/tab2',
            templateUrl: 'tab2.html'
        })
        .state('tab2.book1', {
            url: '/book1',
            params: {
                id: 0
            },
            templateUrl: 'tab2-book1.html',
            controller: 'Tab2Controller',
            controllerAs: 'vm'
        })
        .state('tab2.book2', {
            url: '/book2',
            params: {
                id: 1
            },
            templateUrl: 'tab2-book2.html',
            controller: 'Tab2Controller',
            controllerAs: 'vm'
        })
        .state('tab2.book3', {
            url: '/book3',
            params: {
                id: 2
            },
            templateUrl: 'tab2-book3.html',
            controller: 'Tab2Controller',
            controllerAs: 'vm'
        })
        .state('tab2.book4', {
            url: '/book4',
            params: {
                id: 3
            },
            templateUrl: 'tab2-book4.html',
            controller: 'Tab2Controller',
            controllerAs: 'vm'
        });

Where content of tab2.html is:

<ui-view class="page-container"></ui-view>

When selector changed i call vm.changeHandbook(vm.selectedBook) to switch templates:

function changeHandbook(ref) {
            $state.go(ref.value);
        }

This is most weird and difficult way, but in the end we get more cleaner code.

Discussion courtesy of: SanSan-

This recipe can be found in it's original form on Stack Over Flow.