I did resolve the issue. I also posted about this on the angular-ui github, and their response was basically, "well, that case isn't really what the router has been designed for, so if you want "fancier" state management, put the data in parameters and look at them yourself and implement whatever logic you need". I kinda felt that this was what the ui-router was designed for, so I extended it a bit (no source code changes) to accomplish this. The solution is a combination of abstract states, a fake "off" state, parameters in the router urls, and extending the $urlRouterProvider service.
First extend the $urlRouterProvider:
urlRouterProvider.when(/^((?!leftpanel).)*$/, ['$state', '$location', function ($state, $location) {
//we've got just /app or /app/3434, nothing that contains /leftpanel, so turn off
$state.transitionTo("off");
}]);
Then add that "off" state:
$stateProvider.state('off',{
//url: //there is no url
views:{
container:{
template: 'blank',
controller:['$scope', '$stateParams', function($scope, $stateParams){
console.log("off yay"); //just for sanity, not necessary
}]
}
}});
Then setup the rest of the app routing:
appModule.constant('LEFT_PANEL_STATES', function() {
var leftPanelRoot = {
name: 'root.leftpanel', //mandatory
template: '',
url: "/app/:primaryId/leftpanel",
views:{
'container@': {
templateUrl: "partials/leftpanel_container_partial.html",
controller:"LeftPanelRootCtrl",
resolve: {
//etc
}
}
},
"abstract":true //makes this view only viewable from one of its child states
};
var leftPanelItemsList = {
name: 'root.leftpanel.itemslist', //mandatory
parent: leftPanelRoot, //mandatory
url: "/items-list",
views:{
'childview@root.leftpanel': {
templateUrl: "partials/leftpanel_items_list.html",
controller:"LeftPanelItemsListCtrl",
resolve: {
//etc
}
}
}};
var leftPanelListDetail = {
name:"root.leftpanel.itemslist.detail",
parent:leftPanelItemsList,
url:"/:id/detail",
views:{
"detail":{
templateUrl:"partials/leftpanel_item_detail.html",
controller:"LeftPanelItemListDetailCtrl"
}
}};
var leftPanelExtendedDetailList = {
name:"root.leftpanel.itemslist.extendedlist",
parent:leftPanelItemsList,
url:"/:id/extendedDetail/list",
views:{
"extendeddetaillist":{
templateUrl:"partials/leftpanel_extended_detail_list.html",
controller:"LeftPanelExtendedDetailListCtrl"
}
}};