Replace self partial with another partial with angularjs ui router
angular-ui-router, angularjs
Solution
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:
- View Names - Relative vs. Absolute Names
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?
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
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
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 `"@"`
Problem
In the customers view I have a create customer button which should load a `customers.create.html` partial view where the `customers.html` is positioned. How can the current view `"customers.html"` be replaced by another view `"customers.create.html"` ? customers.html ``` <div> <button ng-click="create()" class="btn btn-default" ui-sref="customers.create">Create</button> </div> <div style="height:500px;" ng-grid="myOptions"></div> ``` app.js ``` $stateProvider .state('customers', { url: "/customers", templateUrl: "../views/customers.html", controller: ['$scope', '$stateParams', '$state', function ( $scope, $stateParams, $state){ }] }) .state('customers.create', { url: "/create", templateUrl: "../views/customers.create.html" }) ``` At the moment when the create button is clicked the route changes to /customers/create but not the html view it just stays the same. I can not put the `<div ui-view></div>` under the create button because then the customers datagrid and the create button would still be visible. Maybe I should not use a hierarchical customers.create view ?