thor
thor

Reputation: 1358

AngularJS: How to have default nested state using UI Router?

I currently have a root index.html with a single ui-view which gets replaced depending on which "page" the user is on, e.g. Books, Games etc. Taking the Books page as an example, this view has content that I'd like to display on all pages which are part of the "Books" space, but the central content will differ depending on if the user is on the Books "homepage" or looking at a specific book. To facilitate this, my books.html has a nested state which either includes books_list.html or books_detail.html.

The url structure I'd like to have is:

How can I set up my states to have the books.html template AND books_list.html template in the nested view when navigating to /books, but have books.html AND books_detail.html when navigating to /books/1 ?

I'm currently getting round this problem by having a "home" sub-state, but this means that I have to have /books/home, and /books displays no central content so is currently useless.

.state('books', {
    url: '/books',
    templateUrl: CONFIG.static_url + '/html/books.html',
    ...
})
.state('books.home', {
    url: '/home',
    templateUrl: CONFIG.static_url + '/html/books_list.html',
    ...
})
.state('books.detail', {
    url: '/:bookId',
    templateUrl: CONFIG.static_url + '/html/books_detail.html',
    ...
})

Upvotes: 9

Views: 5969

Answers (3)

thor
thor

Reputation: 1358

I achieved what I needed by declaring an abstract state:

.state('books', {
    abstract: true,
    url: '/books',
    templateUrl: CONFIG.static_url + '/html/books.html',
    ...
})
.state('books.home', {
    url: '',
    templateUrl: CONFIG.static_url + '/html/books_list.html',
    ...
})
.state('books.detail', {
    url: '/:bookId',
    templateUrl: CONFIG.static_url + '/html/books_detail.html',
    ...
})

This means that /books loads both 'books' and 'books.home' states, and /books/1 loads both 'books' and 'books.detail' states, which is what I needed.

Upvotes: 15

Radim Köhler
Radim Köhler

Reputation: 123861

I created working example here. This is following your needs, because there are only two levels of nesting.

  • books is a parent for both children
    • books.home fills the middle erea - and is NOT parent of books.detail
    • books.detail replaces the list view - but that means that its $scope (books.home) is lost

State definition:

.state('books', {
    url: '/books',
    views: {
      '@' : {
        templateUrl: 'layout.html',
      },
      'left@books' : { templateUrl: 'tpl.left.html',},
      'right@books' : { templateUrl: 'tpl.right.html',},
    },
  })
.state('books.home', {
    url: '/home',
    templateUrl: 'list.html',
  })
.state('books.detail', {
    url: '/:bookId',
    templateUrl: 'detail.html',
    controller: 'DetailCtrl'
  })

Check it here

But there is also a different approach, which I like more. The list view, is parent of its child, and therefore it could keep its $scope, while navigating among details. Similar stuff discussed here

Upvotes: 1

maybe try it

$urlRouterProvider.otherwise('/');
.....
.state('index', {
    url: '/',
    templateUrl: CONFIG.static_url + '/html/index.html',
    ...
})    

Upvotes: -1

Related Questions