Replace self partial with another partial with angularjs ui router

We need to use absolute view name, to precisely inform ui-router, where to (re-)place the child template. (check this example) Read more here:

cite:

// absolutely targets the unnamed view in root unnamed state.
// <div ui-view/> within index.html
"@" : { } 

So, the root view name is empty string, which for a child could be represented as ‘@’

$stateProvider
  .state('customers', {
      url: "/customers",
      templateUrl: "../views/customers.html",
      controller: ['$scope', '$stateParams', '$state',
        function($scope, $stateParams, $state) {
      }]
  })
  .state('customers.create', {
    url: "/create",
    views: {
      '@': {
        templateUrl: "../views/customers.create.html"
      }
    }
  })

See more here in this plunker

Extend. Any state defintion, is defining the view name, where its template/templateUrl/templateProvider belongs to. If there is only one template to be injected into parent ui-view=”” (unnamed) we can use this syntax:

.state('customers', {
      url: "/customers",          
      templateUrl: "tpl.customers.html",
      controller: ....            
  })

which is equal to this syntax:

.state('customers', {
      url: "/customers",
      views: {
        // explicit information that we target unnamed view
        '': {
          templateUrl: "tpl.customers.html",
          controller: ... 
        }
      }
  })

So, if we do have to ui-view targets on the root level

<h4 data-ui-view="header"></h4>
<div data-ui-view=""></div>

we can define states like this:

$stateProvider
  .state('customers', {
      url: "/customers",
      views: {
        'header': {
          template: '<div>customers</div>',
          // controller...
        },
        '': {
          templateUrl: "tpl.customers.html",
          controller: ...
        }
      }
  })
  .state('customers.create', {
    url: "/create",
    views: {
      'header@': {
        template: "<div>create</div>",
      },
      '@': {
        templateUrl: "tpl.customers.create.html",
      }
    }
  })
  ;

See extended example plunker

EXTEND: to give THE answer to a comment:

… I have no idea why it works now here…did the same as before I just put this in my code: ‘@’: { templateUrl: “tpl.customers.create.html”, }..

As mentioned here: View Names – Relative vs. Absolute Names:

Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname@statename, where viewname is the name used in the view directive and state name is the state’s absolute name, e.g. contact.item. You can also choose to write your view names in the absolute syntax.

So what happens?

  1. The ui-view="" placed in index.html is getting the absolute name “@”. Which does consist of three parts (while only one char). The delimiter is @, the chars left from it represent the viewName, the chars on a right side represent the stateName

  2. Having in a state 'customers' a view, with ui-view="header" its absolute name would be: "header@customers". So any child state can target this view with its own tamplate/tempalteUrl/templateProvider

  3. Having a state 'customers' with unnamed template ui-view="" its aboslute name would be "@customers" (left side from @ is unnamed empty string). If child state like 'customers.create' would like to target this view,

it can use one of these :

views : {
  "@customers" : {
      template: ....
   }
}
// or
template: ....

because the second just uses implicit notation, which will end up in “” (no vie name) + “@” (delimiter) + “customers” (parent stateName) == “@customers”

4. we can target the root (index.html) using the same notation.

The root name is “” and while the view Name is “” we end up in "" + "@" + "" == "@". And that’s why this magical setting does the job to place our view into root ui-view="" index.html via "@"

Leave a Comment