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 ?
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 "@"