2

I have define state for my shop application but I'm not sure I'm doing it right. Since I have more than one optional parameter in url I'm not sure how should I implement it.

.state('app.products', {
    abstract: true,
    views: {
        'content@': {
             templateUrl: 'app/products/views/product.html'
         },
         '[email protected]': {
             templateUrl: 'app/products/views/product-header.html'
          }
    }
})

Above is my abstract view for products page. Products will be separated in man/women and also subcategories like:

www.example.com/man/

www.example.com/man/footwear/

www.example.com/man/footwear/shoes

Man, footwear and shoes are all optional since man param can be woman, footwear can be cloth (where last param would be e.g. shirts) and all possible combinations of those above.

I'm not sure if I have to make every state separately or I can handle all this with one more state except this one?

Just to note, product header is not relevant here and if its required for good structure to remove it, surely I can do that.

I just can't find anything similar online, so link would be also be helpful if anyone has any.

1 Answer 1

1

I've done something very similar recently by nesting each subcategory state into its parent category state. Some benefits of doing it this way are that you save yourself from having to repeat a lot of code in a child state that was already defined in a parent state, and also from having to reload data and views that were already loaded in the parent state.

Here's an example to get you started:

.state('app.products', {
  abstract: true,
  url: '/products',
  views: {...}
})
.state('app.products.gender', {
  url: '/:gender',
  views: {...}
})
.state('app.products.gender.category', {
  url: '/:category',
  views: {...}
})
.state('app.products.gender.category.type', {
  url: '/:type',
  views: {...}
})

First, the urls automatically stack in child states. This means you only have to define one url parameter per child state and you still wind up getting urls like this /app/products/:gender/:category/:type.

The second benefit of doing it this way is that views defined in a parent state are automatically included in all of its child states, unless you explicitly override it:

.state('app.products.gender.category', {
  url: '/:category',
  views: {
    'foo@someParentState': {templateUrl: 'foo.html'},
    'bar@someParentState': {templateUrl: 'bar.html'}
  }
})
.state('app.products.gender.category.type', {
  url: '/:type',
  views: {
    // foo.html is still rendered here
    // bar.html is replaced by baz.html
    'bar@someParentState': {templateUrl: 'baz.html'}
  }
})

Another benefit seen from this example, is that foo.html won't be reloaded when the state changes to app.products.gender.category.type. For example, say foo.html has a long scrolling list of types in that category. If the user clicks on an item in the list that changes the state from app.products.gender.category to the child state app.products.gender.category.type, then foo's long scrolling list will not be reloaded, and the user can still see the item they clicked on. On the other hand, if that click had changed the state to a non-child state, then the list would probably have been reloaded (data and all), and the user might have to scroll to see the item they clicked on.

Some advice:

  • Keep your nested state names short.
  • Only include a state in the hierarchy if it's absolutely necessary (I'm looking at you app.products!).
  • There are plenty of ways that this technique can go wrong so be sure to review the ui-router docs for configurations that help you code less.
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, great suggestion, although I wanted to avoid so many states, it seems much better now. I added app.products state as abstract and defined url as such: '?{page,brands}, since all children (one you wrote above) will have those optional parameters. Is this the right way to define optional query params on abstract state? Of course I added params: { page: { value: '1', squash: true }, brands: { value: null, squash: true } }.

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.