1

I want to create sub-state (nested states) based on the state params being passed.

For example I have a dynamic state parameter, 'pageId'. If the $stateparams.pageId is 'page2', then I want to have two nested states created for that.

How can I do that? Thanks in advance.

Here is the plunkr created for this

Plnkr

app.config(['$stateProvider', '$urlRouterProvider',
    function($stateProvider, $urlRouterProvider){
        $stateProvider.state('page', {
            url: '/:pageId',
            templateUrl: function($stateParams){
              return $stateParams.pageId +".tpl.html";
            }
        });

        $urlRouterProvider.otherwise('/page1');
    }]);
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
Jinto
  • 847
  • 1
  • 11
  • 27

2 Answers2

2

There is a working plunker

We can create two states. One will NOT use nested views, the second will have them.

// state without nested
.state('pageWithout', {
  url: '/{pageId:(?:page1|page3|page5)}',
  templateUrl: "page1.tpl.html",
})
// state with nested
.state('pageWith', {
  url: '/:pageId',
  views : {
    '' : {
      templateUrl: "page2.tpl.html",
    },
    '@pageWith' : {
      template: "<h2>the SECOND content for state with nested views</h2",
    }
  }
});

So, the trick is to use some pattern to say which pageId values should go to first state. Check the

UrlMatcher

which is responsible for the url : 'url def...' processing

And this way we will have similar links translated into different states, with different nested view structure:

// without nested views
<a href="#/page1">
<a href="#/page3">
<a href="#/page5">

// with nested views
<a href="#/page2">
<a href="#/pageA">
<a href="#/pageB">

Check it here

EXEND, with a child state and some defaults. The udpated plunker

So, we can create few children of our second state:

// children
.state('pageWith.defaultChild', {
  url: '/default',
  views : { 
    '' : {
      template: "<h3>the pageWith.defaultChild </h3",
    }
  }
}) 
.state('pageWith.childWithParams', {
  url: '/{id:int}',
  views : {
    '' : {
      template: "<h3>the child with ID param {{$stateParams.id}} </h3",
    }
  }
});

Based on this solution:

Redirect a state to default substate with UI-Router in AngularJS

We can decorate our parent state with redirectTo

.state('pageWith', {
  url: '/:pageId',
  redirectTo: 'pageWith.defaultChild',
  ...

And just add this simple listener

.run(['$rootScope', '$state', function($rootScope, $state) {

    $rootScope.$on('$stateChangeStart', function(evt, to, params) {
      if (to.redirectTo) {
        evt.preventDefault();
        $state.go(to.redirectTo, params)
      }
    });
}]);

Check the default state redirect here

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • I liked this idea of using UrlMatcher. However, here when you are specifying '@pageWith' with a template, you are not creating a sub state right? Lets say I want to create two sub states for page2, with one sub state being the default one. How do we handle this kind of scenario? And, if I want to navigate to any particular sub state? – Jinto May 23 '15 at 17:14
  • We are really close, give me sec – Radim Köhler May 23 '15 at 17:14
  • So, in the updated answer I gave you updated plunker and added a link to some more detailed answer... now you should have that all to start to profit from mighty UI-Router ;) – Radim Köhler May 23 '15 at 17:25
  • I forgot to update the plunker! there is the latest and correct link http://plnkr.co/edit/d4iTnQaPTgXtLWnDB7PW?p=preview – Radim Köhler May 23 '15 at 17:33
  • Super. This is what I wanted. Thanks so much. I didn't get one part. '/{id:int}' can you please explain me this parttern? – Jinto May 23 '15 at 17:35
  • it is (as said in the link to UrlMatcher) - way how to say what is the type of the param - in this case integer... check the doc and this part: `'{' name ':' regexp|type '}' - curly placeholder with regexp or type name. Should the regexp itself contain curly braces, they must be in matched pairs or escaped with a backslash.` Does it help? – Radim Köhler May 23 '15 at 17:36
  • In the UrlMatcher documentation, I couldn't find a specification saying 'int' means integer. I understand that we can use regular expression. But, these types are also available for UrlMatcher? – Jinto May 23 '15 at 17:38
  • I cited that part from the doc above `'{' name ':' regexp|type '}'` ...see the **type** - it means **type name** – Radim Köhler May 23 '15 at 17:39
  • If you want to know how to create custom types: http://stackoverflow.com/a/27182177/1679310... anyhow good luck with UI-Router ;) – Radim Köhler May 23 '15 at 17:40
0

I am not sure clearly understand what you are trying to do, is this what you are trying to do ?

app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider){
    $stateProvider
        .state('page', {
            url: '/:pageId',
            templateUrl: function($stateParams){
                return $stateParams.pageId +".tpl.html";
            },
        });
        .state('page.firstchild', {
            url: '/foo', // will have url /:pageId/foo because it inherits from its parent
        })
        .state('page.secondchild', {
            url: '/bar' // same here
        })

    $urlRouterProvider.otherwise('/page1');
}]);
Vincent Taing
  • 3,283
  • 2
  • 18
  • 24
  • In this case, it creates firstChild, and secondChild states everytime irrespective of the pageId passed right? I want to create sub states only for page2. In page2.tpl.html, I am putting a ui-view because I want a substate for that. However in page1.tpl.html, I dont want these substates. So, even if I put a ui-view in page1.tpl.html, it shouldn't work. lets say I have separate module itself for each page. So I want to create these states within the config of page2 module only. Hope I made it clear. – Jinto May 23 '15 at 13:49