Nesting routes in Angular UI Router - angularjs

(AngularJS v1.2.0-rc.3 + Angular UI-Router v0.2.0)
In my index.html, I have the following code:
<div class="container" ui-view></div>
In my app.js, I have the following code:
$stateProvider
.state('projects', {
abstract: true,
url: '/projects',
template: '<ui-view />',
})
// below display properly
.state('projects.list', {
url: '',
templateUrl: 'views/project_list.html',
controller: 'ProjectListCtrl'
})
// below display properly
.state('projects.one', {
url: '/{projectId:[0-9]{1,8}}',
templateUrl: 'views/project_dashboard.html',
controller: 'ProjectCtrl'
})
// below does not display at all
.state('projects.one.campaigns', {
url: '/campaigns',
template: 'I cannot seem to display this text'
})
I can hit the following routes just fine: index.html/projects, index.html/projects/1, but I cannot hit this route: index.html/projects/1/campaigns
Does anyone know why I can't?
Bonus points if you can answer how I could display the projects.one.campaigns state on the same URL page as the projects.one state.

The reason is because projects.one matches before projects.one.campaigns
Add a projects.one abstract state and then add a projects.one.default state with the templateUrl.
.state('projects.one', {
url: '/{projectId:[0-9]{1,8}}',
abstract:true,
template: '<ui-view/>',
})
.state('projects.one.default', {
url: '',
templateUrl: 'views/project_dashboard.html',
controller: 'ProjectCtrl'
})
.state('projects.one.campaigns', {
url: '/campaigns',
template: 'I cannot seem to display this text'
}
To display the template of the campaigns on the same page of the projects.one you should not use a state but a directive instead and toggle with ng-show on the same page.

I just spent whole day dealing with this problem.
I found out, that you don't need abstract states at all!
Try this:
index.html:
<div class="container"><ui-view/></div>
use directive ui-view as a tag in the top level template.
Now all your nested templates wrap like this:
<ui-view>
<div>
template code
</div>
</ui-view>
and now you can just:
$stateProvider
.state('list', {
url: '',
templateUrl: 'views/project_list.html',
controller: 'ProjectListCtrl'
})
// below display properly
.state('one', {
url: '/{projectId:[0-9]{1,8}}',
templateUrl: 'views/project_dashboard.html',
controller: 'ProjectCtrl'
})
// below does not display at all
.state('one.campaigns', {
url: '/campaigns',
template: 'I cannot seem to display this text'
})
I needed general solution for the nesting and this works. Now you can create very deep nesting easily (for example one.campaing.group.member.note). If you will use ui-view on the top level and wrap all templates with the ui-view, they contact of each template will replace content of the top level ui-view (which is empty).

Related

angular nested state uirouter not loading template

With the following code, I'm trying to create a page with the url /admin, that would lead you to /admin/devices after clicking a button and after clicking another button to /admin/devices/new. The first part works properly and I get redirected to /admin/devices. The second part not quite, since it changes the url to /admin/devices/new but it doesn't change the template.
To change through url's I use $state.go(admin.devices) and $state.go(admin.devices.new)
Any idea?
$stateProvider
.state('admin', {
url: '/users',
abstract: true
})
.state('admin.devices', {
url: '/devices',
template: require('../templates/admin/devices/index.html'),
controller: 'AdminDevicesCtrl',
controllerAs: 'ctrl'
})
.state('admin.devices.new', {
url: '/new',
template: require('../templates/admin/devices/new.html'),
controller: 'AdminDevicesNewCtrl',
controllerAs: 'ctrl'
});

Angular UI-Router childs

I have an app.config with UI-Router. It has a login page with it's controller, recoverLogin and I want to put a template with footer, header and more stuff with new states that could be loaded into the template (in an especificplace).
My module is:
var app = angular.module("app", [
"ui.router",
"pascalprecht.translate"
]);
My routes are;
app.config(function($stateProvider, $urlRouterProvider)
{
$stateProvider
.state("login", {
url: "/login",
templateUrl: "views/accessControl/login.html",
controller: "loginCtrl"
});
$stateProvider
.state("recoverLogin", {
url: "/recoverLogin",
templateUrl: "views/accessControl/recoverLogin.html",
controller: "recoverLoginCtrl"
});
$stateProvider
.state("template", {
url: "/template",
templateUrl: "views/templates/template.html",
controller: "templateCtrl"
})
.state("template.dashboard", {
url: "/dashboard",
templateUrl: "views/dashboard/dashboard.html",
controller: "dashboardCtrl"
})
$urlRouterProvider.otherwise("login");
})
I have in my index <ui-view></ui-view> for the place of the loadings and another <ui-view></ui-view> in template.html int he place where I want to load more stuff like dashboard.html, but this doesn't works. it loads dashboard.html without the template created in template.html. I have founded lot of documentation that doesn´t works for me. Any Idea?
Here there are a plunker example of the idea: https://plnkr.co/edit/ZsGZjDKOBTIXFpPtXasN?p=preview
There is updated plunker and working plunker.
The template of the mainTemplate state is now lookin like this:
place for main:
<div ui-view="main"></div>
place for other:
<div ui-view="other"></div>
so it has two (could be more) places for more stuff. And this is the state redefined:
.state("mainTemplate.dashboard", {
name: "main",
url: "/dashboard",
views: {
'main' : {
templateUrl: "dashboard.html",
controller: "dashboardCtrl"
},
'other' : {
template: "<h2>other view</h2>",
}
}
});
What we can see is views : {} object being used to defined multiple content for more targets. Read about that more details here:
Angular UI Router - Nested States with multiple layouts
Nested states or views for layout with leftbar in ui-router?
play or observe the changes here

Different states doesn't show template content

I have a basic Index.html file which following structure:
<body class="{{$state.current.name.replace('.','-')}}">
<div ui-view>
<div ng-include src="'partials/menu.html'"></div>
<!-- <div ng-menu class="ui top blue sidebar menu active"></div> -->
<div class="view-height-100"></div>
</div>
...
</body>
When I am in the login state, it's working very well:
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'partials/login-area.html',
controller: 'LoginController',
});
But, when I am routing to the user.management state, nothing gets shown (but Chrome is loading the template, so I can access the scope and the .html file is there):
$stateProvider
.state('user', {
url: '/:buildingName',
controller: 'CurrentBuildingController',
data: {
access: ['user']
}
})
.state('user.management', {
url: '/management',
templateUrl: '/views/management.html',
controller: 'ManagementController'
})
Can someone explain me why?
Parent state simply must have target for its child (unless we use absolute naming to target some super parent, but it is another approach)
.state('user', {
url: '/:buildingName',
template: "<div ui-view></div>",
controller: 'CurrentBuildingController',
data: {
access: ['user']
}
})
see that we now have template: "<div ui-view></div>", which will serve as a view target for any child state 'user.xxx'
Check also:
AngularJS UI-Router : Abstract state + child states not working
EXTEND - let child to target the index.html
We can use absolute naming and child will then be injected directly into index.html. There is a working plunker (by intention parent won't load, it does not have any template)
.state('parent', {
url: "/parent",
//templateUrl: 'tpl.html',
})
.state('parent.child', {
url: "/child",
views: {
'#': {
templateUrl: 'tpl.html',
controller: 'ChildCtrl',
}
}
})
Check this for more info:
Angularjs ui-router not reaching child controller

Angular UI-router switch between multi views to single view

I have an app which has three views (ui-view using Angular ui-router):
header, sidebar and content.
my index.html looks like this: (I omitted the actual classes for clearness)
<body>
<div ui-view="header" class="..."></div>
<div class="page-container">
<div ui-view="sidebar" class="..."></div>
<div class="page-content">
<div ui-view="content"></div>
</div>
</div>
</div>
</body>
This pattern works well with pages that have the header and sidebar.
But I have some pages that I don't want to display the header and sidebar, for example a login page that should fit on all page.
For this kind of pages I need something like:
ui-view which should look like this:
<body>
<div ui-view="content"></div>
</body>
So it won't be nested and under the other views <div>'s and affected by their classes.
I have some solutions in mind, but none of them gave me a good enough UX.
I tried adding <ng hide> to the header and sidebar depending on the state. It worked but there was annoying flickering (that I couldn't eliminate with ng-cloak for some reason..)
To make things more clear, here is an example of two states , one is "one pager" and the other is full page with header and sidebar:
.state('Login', {
url: '/login',
views: {
'content': {
templateUrl: './../templates/login.html',
controller: 'LoginCtrl'
}
}
})
.state('Users', {
url: '/users',
views: {
'header': {
templateUrl: './../templates/header.html',
controller: 'HeaderCtrl'
},
'sidebar': {
templateUrl: './../templates/sidebar.html',
controller: 'SidebarCtrl'
},
'content': {
templateUrl: './../templates/users.html',
controller: 'UsersCtrl'
}
}
})
I also think using nested views, but not sure whether this is the right approach.
Maybe try using nested states, ie:
.state('app', {
url: '/app',
abstract: true,
templateUrl: './../templates/treeViewTemplate.html'
})
.state('login', {
url: '/login',
templateUrl: './../templates/login.html',
controller: 'LoginCtrl'
})
.state('app.users', {
url: '/users',
views: {
'header': {
templateUrl: './../templates/header.html',
controller: 'HeaderCtrl'
},
'sidebar': {
templateUrl: './../templates/sidebar.html',
controller: 'SidebarCtrl'
},
'content': {
templateUrl: './../templates/users.html',
controller: 'UsersCtrl'
}
}
})
In your root abstract state you define a template for 3 view-layout. login state will instead take whole display.

Angular UI-Router: child using parent's view

In story form:
What I am looking for here is a master-detail setup. The master is in list form and when I click on a link (relative to a particular row/record (or Account in this case)) I want to see the details in the main view (literally, the "main" view: <div class="container" ui-view="main"></div>).
I want to do this and maintain my URL structure (/accounts for the list of Accounts; /accounts/:id for the detailed version) but I want the detail view to use the view that the list was using.
What I currently have
index.html
...
<div class="container" ui-view="main"></div>
...
accounts.js
$stateProvider
.state ('accounts', {
url: '/accounts',
views: {
'main': {
controller: 'AccountsCtrl',
templateUrl: 'accounts/accounts.tpl.html'
}
},
data: { pageTitle: 'Account' }
})
.state ('accounts.detail', {
url: '/:id',
views: {
'main': {
controller: 'AccountDetailCtrl',
templateUrl: 'accounts/detail.tpl.html'
}
},
data: { pageTitle: 'Account Detail' }
});
At this point, the /accounts route works as expected. It displays accounts/accounts.tpl.html correctly in the main view. In that html each line in the repeater links it to its appropriate /accounts/:id URL, which I am handling with the nested state accounts.detail.
What is probably obvious to the majority of you who know more than me about this, my accounts.detail will render to the view main if that named view exists in the template accounts/accounts.tpl.html. That is indeed true.
But that is not what I want. I want the accounts.detail stuff to render in the parent main view; I want the html of accounts/detail.tpl.html to replace the html of accounts/accounts.tpl.html found in index.html: <div class="container" ui-view="main"></div>.
So how could I accomplish this?
MY SOLUTION IN CONTEXT
The trick is, as the answer says, to set up the URL scheme to identify which child state is "default". The way I interpret this code in plain English is that the parent class is abstract with the proper URL and the "default" child class has the "same" URL (indicated by '').
If you need further clarity, just post a comment and I'll share any more guidance.
.config(function config( $stateProvider ) { $stateProvider
.state ('accounts', {
abstract: true,
url: '/accounts',
views: {
'main': {
templateUrl: 'accounts/accounts.tpl.html',
controller: 'AccountsCtrl'
}
},
data: { pageTitle: 'Accounts' }
})
.state ('accounts.list', {
url: '',
views: {
'main': {
templateUrl: 'accounts/list.tpl.html',
controller: 'AccountsListCtrl'
}
},
data: { pageTitle: 'Accounts List' }
})
.state ('accounts.detail', {
url: '/:id',
views: {
'main': {
templateUrl: 'accounts/detail.tpl.html',
controller: 'AccountDetailCtrl'
}
},
data: { pageTitle: 'Account Detail' }
});
Sounds like you simply don't want the views to be hierarchical. To do this, simply change the name of the second state to detail.
Note however, that in doing so you will lose any hierarchical properties of the state tree (the controller code state of accounts for example).
If you want to keep the controllers hierarchical, but perform a replace of the html, I would create another parent above both others that takes care of the controller logic, but only has an extremely simple view <div ui-view=""></div>.
For example:
$stateProvider
.state('app', { url: '', abstract: true, template: 'parent.html', controller: 'ParentCtrl' })
.state('app.accounts', { url: '/accounts', templateUrl: 'accounts.tpl.html', controller: 'AccountsCtrl' })
.state('app.detail', { url: '/accounts/:id', templateUrl: 'detail.tpl.html', controller: 'AccountDetailCtrl' });
You can use '#' to define an absolute path to the ui-view of your choice. For example: "detail#contacts" : { }, where this absolutely targets the 'detail' view in the 'contacts' state. within contacts.html
Source: https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views

Resources