Inject a template in parent's view with ui-router

2.7k views Asked by At

I have an abstract state declared as

$stateProvider.state('myapp', {
    abstract: true,
    templateUrl : 'index.html'
});

And all the <ui-view> in the 'index.html' template will be populated by the children states:

$stateProvider.state('myapp.home', {
    url : "/",
    views : {
        "main" : {
            controller : 'HomeCtrl',
            templateUrl : 'includes/home.html'
        }
    }
});

What I don't understand is why the template from the home state isn't injected in the parent named view but it works when using "main@" as view name.

If I understood correctly, "@" target the absolute root state and just using "main" targets the parent state.

But isn't the abstract state the parent of myapp.home here?

Thanks

2

There are 2 answers

1
Radim Köhler On BEST ANSWER

I would say, that a significant confusion could come from the fact, that our super root state 'myapp' uses template named index.html.

I would suggest to change that naming and this adjusted example then should work. The index.html, will be used only as a starting page (referencing angular, UI-Router...)

<!DOCTYPE html>
<html ng-app="MyApp" ng-strict-di>

  <head>
    <title>my app</title>
    <script src="angular.js"></script>
    <script src="angular-ui-router.js"></script>
    <script ...
  </head> 

  <body>
    // place for our root state        
    <div ui-view=""></div>

  </body> 

</html>

Now, we can target this ui-view 3 ways. We can use implicit, or explicti relative or explicit aboslute naming build as viewName@stateName. These three defintions are the same:

// I. no views : {} needed, we target parent unnamed
.state('myapp', {
    abstract: true,
    templateUrl: 'tpl.myapp.html'
})
// II. we target explicit parent unnamed view - relative notation
.state('myapp', {
    abstract: true,
    views : {
        '': {
            templateUrl: 'tpl.myapp.html'
        }
    }
})
// III. we target explicit parent unnamed view - absolute notation
.state('myapp', {
    abstract: true,
    views : {
        '@': { // before @ is view name, after @ is state name, empty for root
            templateUrl: 'tpl.myapp.html'
        }
    }
})

As we can se,, for the 'myapp' state we used different templateUrl: 'tpl.myapp.html'. Its content is different the index.html, it could be:

<div>
  <h2>the root myapp template</h2>

  place for child states:
  <div ui-view="main"></div>

</div>

And now we have to target this view only explicit way (but could be relative or absolute:

  .state('myapp.home', {
      url: "/",
      views: {
        // could be "main@myapp" as well
        "main": {
          controller: 'HomeCtrl',
          templateUrl: 'includes/home.html'
        }
      }
  })

Check the example here

Read more about it here:

0
Nikhil Aggarwal On

You are using named views. Using main@ specifies that child view will be added to ui-view with name "main". In case your parent does not have any ui-view with name main, then view will not be inserted in the html.

For parent child relationship, it is not necessary you need named views. Just update your state to following and it will work. Also, you will have to remove the name from ui-view in html.

$stateProvider.state('myapp.home', {
    url : "/",
   controller : 'HomeCtrl',
   templateUrl : 'includes/home.html'

});