3

I want to inherit states/URLs using parent.child notation in UI router. I don't want to inherit views (or nest views inside other views), or inherit controllers, I just want to inherit URLs. I'm using 'ui.router' as a dependency.

This is an example of a router:

$stateProvider
.state('products', {
    url: '/products',
    templateUrl: 'view1.html',
    controller: 'products#index'
})

.state('products.show', {
    url: '/:id',        
    templateUrl: 'view2.html',
    controller: 'products#show'
})

.state('products.buy', {
    url: '/:id/:moreParams',
    templateUrl: 'view3.html',
    controller: 'products#buy'
})

.state('products.sell', {
    url: '/:id/:moreParams/:moreParams',
    templateUrl: 'view4.html',
    controller: 'products#sell'
});

And the controllers are:

angular.module('productsModule', [])

.controller('products#index', function($scope){
})
.controller('products#show', function($scope){
})
.controller('products#buy', function($scope){
})
.controller('products#sell', function($scope){
})

Here, all views are completely different, and I don't want to nest any view inside any other view. Also, all controllers are different too, and I don't want to inherit controllers, they are all separate with different functions.

Here's my expected result. What I want to achieve is Angular to allow me to only inherit URLs, so the URLs become:

/products
/products/:id
/products/:id/:moreParams
/products/:id/:moreParams/:moreParams

(and then have each URL its own view and controller, as specified above)

So far it's not working, and my research is beginning to tell me that this kind of inheritance using parentState.childState is only for when you want to have nested views (which is what I don't want. I only want to re-use URLs).

My workaround is to create router URLs like products_show, that is, using an underscore instead of a dot, so they are treated as new independent URLs rather than inheritance ones. I'm not sure if this is the best idea, mostly because it looks ugly (though it works perfectly).

Perhaps I should just use products_show in case it can't be done with a dot? Ideas?

2
  • I'm not sure what you mean by moreParams in /products/:id/:moreParams /products/:id/:moreParams/:moreParams Commented May 20, 2016 at 20:26
  • moreParams could be anything, it's just to make an URL different. It could just be url: '/:id/different/URL', Commented May 20, 2016 at 23:11

2 Answers 2

3

You can have a parent child relationship between the routes without nesting their respective views. You achieve that by specifying an absolute target for your view. Like this:

$stateProvider
.state('products', {
    url: '/products',
    templateUrl: 'view1.html',
    controller: 'products#index'
})

.state('products.show', {
    url: '/:id',
    views: {'@': {
      templateUrl: 'view2.html',
      controller: 'products#show'
    }}
})

.state('products.buy', {
    url: '/:id/:moreParams',
    views: {'@': {
      templateUrl: 'view3.html',
      controller: 'products#buy'
    }}
})

.state('products.sell', {
    url: '/:id/:moreParams/:moreParams',
    views: {'@': {
      templateUrl: 'view4.html',
      controller: 'products#sell'
    }}
});

By doing that you're basically telling ui-router to render your view inside the unnamed ui-view in your main index.html, thus, overriding the parent view. Instead of looking for a ui-view in the parent view's template.

To understand why this works, you'll have to understand how ui-router decides where to render the view for your route. So, for example, when you do:

.state('parent.child', {
    url: '/:id',
    templateUrl: 'child-view.html',
    controller: 'ChildCtrl'
})

ui-router will by default translate this to something like:

.state('parent.child', {
    url: '/:id',
    views: {'@parent': {
      templateUrl: 'child-view.html',
      controller: 'ChildCtrl'
    }}
})

which will cause it to look for an unnamed ui-view inside the parent's view template and render the child view's template inside. You could also specify more than 1 view for a route, like:

.state('parent.child', {
    url: '/:id',
    views: {
      '@parent': {
        templateUrl: 'child-view.html',
        controller: 'ChildCtrl'
      },
      'sidebar@parent': {
        templateUrl: 'child-view-sidebar.html',
        controller: 'ChildViewSidebarCtrl'
      }
    }
})

In this case, child-view.html will be rendered inside the parent view's unnamed ui-view as before. In addition it will also look for a ui-view="sidebar" in the parent view's template and render child-view-sidebar.html inside.

For more info on this powerful views option and how to specify targets for your view, see the ui-router docs

Sign up to request clarification or add additional context in comments.

Comments

-1

This is how to write nested states:

$stateProvider
.state('products', {
    url: '/products',
    templateUrl: 'view1.html',
    controller: 'products#index'
})

.state('products.show', {
    parent:'products',
    url: '/:id',        
    templateUrl: 'view2.html',
    controller: 'products#show'
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.