Nested views in ui-router - angularjs

I'm working with some nested states in angularjs and everything goes well till a part of the URL is dynamic.
This works well
.state('company', {
url: "/company",
templateUrl: 'views/company/index.html'
})
.state('company.list', {
url: "/",
views: {
"c_list": {
templateUrl: 'views/company/list.html',
controller: 'CompanyCtrl'
}
}
})
.state('company.view', {
url: "/:company_id",
views: {
"c_info": {
templateUrl: 'views/company/view.html',
controller: 'CompanyCtrl'
},
"c_menu": {
templateUrl: 'views/company/menu.html',
controller: 'MenuCtrl'
}
}
})
But when it comes to extend the company.view, as it has a dynamic parameter, it fails.
.state('company.view.user', {
url: "/user",
views: {
"c_nested":{
templateUrl: 'views/user/index.html',
}
}
})
.state('company.view.user.list', {
url: "/",
views: {
"u_list": {
templateUrl: 'views/user/list.html',
controller: 'UserCtrl'
}
}
})
If I extend user from company instead of company.view the nested views are shown but if I extend from company.view only the main content is shown, not the nested one.
For company/index.html I've got:
<div ui-view="c_list"></div>
<div ui-view="c_info"></div>
<div ui-view="c_menu"></div>
<div ui-view="c_nested"></div>
For user/index.html I've got:
<div ui-view="u_list"></div>
<div ui-view="u_info"></div>
<div ui-view="u_menu"></div>
<div ui-view="u_nested"></div>
Presume all other html are as simple as
<div>hi</div>
The URLs I use are:
/company [works]
/company/92 [works]
/company/92/user [no way]
What should I do to make this work with dynamic params?

I have not solved this but came around it:
.state('company.user.view', {
url: '/{user_id:[0-9]{1,8}}',
...
})
.state('company.user.edit', {
url: '/{user_id:[0-9]{1,8}}/edit',
...
})
I have to specify an id in every single url

Related

How to redefine a view in a state inheritance in angularJS

I need to have to states in order to show different views if the user is logged in or not. My problem is that in the app.dashboard state does not show the view, but if I put that view in the views part in the state app it works. I want to inherit because in different states I will need to show different pages.
This is that part of the code:
$stateProvider
.state('welcome',{
url:"/",
controller: "HomeController as home",
views: {
'topbar-menu-view': {
templateUrl: '/partials/topbar/loginForm.html'
},
'home-view': {
templateUrl: '/partials/login.html'
}
},
data: {
requireLogin: false
}
})
.state('app', {
abstract: true,
url: '/home',
views: {
'topbar-menu-view': {
templateUrl: '/partials/topbar/userOptions.html'
}
},
data: {
requireLogin: true
}
})
.state('app.dashboard',{
url:"/",
controller: "HomeController as home",
views: {
'home-view': {
templateUrl: '/partials/home.html'
}
}
})
Am I doing something wrong? Because I looked for some examples and it seems to be like this.
The index file is something like this:
<body ng-controller="HomeController as home">
<topbar home="home"></topbar>
<div id="homeScreen">
<div ui-view="home-view"></div>
</div>
</body>
Thank you!

controller undefined in named views

Following works perfect.
In my application file app.js, i have states like
.state('nna.home',
{
url: '/home',
views: {
templateUrl: 'views/home.html'
}
})
//home.html is like
<script src="../controllers/home.js"></script>
<div class="container cf" ng-controller="home">
// my home.js is included correctly in all cases have code like
alert(2); // works
app.controller('home', function ($scope) {
alert(2); // works
});
But as soon as I try to use named views like following. It stops routing
.state('nna.home', {
url: '/home',
views: {
'v1' : {
templateUrl: 'home.html',
controller: 'home',
resolve: {
deps: function ($ocLazyLoad) {
return $ocLazyLoad.load('homecontroller.js');
}
}
},
}
// my home.js is included correctly in all cases have code like
alert(2); // works
app.controller('home', function ($scope) {
alert(2); // Does not work
});
Plunker
I can use them fine as long as i load all controller files in index but i want to load controllers only with views not all the way in index
Probably the issue is with my understanding about named views, but i am stuck to know the reason that why the home is undefined even when i can show with alert that file had been successfully added
Try this:
.state('nna.home',
{
url: '/home',
views: {
'v1': {
templateUrl: 'views/home.html',
controller: 'home'
}
}
})
There is a working plunker
These could be the states:
.state('nna', {
template: '<div ui-view="v1"></div>',
})
.state('nna.home', {
url: '/home',
views: {
'v1' : {
templateUrl: 'views/home.html',
controller: 'home',
},
}
});
And these links are working now:
<a href="#/home">
<a ui-sref="nna.home">
Check it in action here

Angular routing ui-view inside another ui-view

Conception overview:
We have two tabs on index html. There we routing those tabs like that:
<div ui-view></div>
On a second tab we have a selector, that switch tab's content in another ui-view like that:
<div ui-view="{{vm.currentView}}"></div>
where vm.currentView is a name of routing state ('book1' and etc.).
.state('tab2', {
abstract: true,
templateUrl: 'tab2.html',
controller: 'Tab2Controller',
controllerAs: 'vm'
})
.state('tab2.content', {
url: '/tab2',
views: {
'': {
templateUrl: 'tab2.html'
},
'book1#tab2': {
templateUrl: 'tab2-book1.html'
},
'book2#tab2': {
templateUrl: 'tab2-book2.html'
},
'book3#tab2': {
templateUrl: 'tab2-book3.html'
},
'book4#tab2': {
templateUrl: 'tab2-book4.html'
}
}
});
Everything is fine, except one thing: data content and name of a view is changing, but a template content isn't.
I resolved it by another way (based on exclude 'ui-view inside another ui-view' conception and separate views in states). But i still want to know: "How to do this with using 'ui-view inside ui-view' conception?"
Here's a Plunker Example
Its possible to make 'ui-view inside another ui-view'.
Lets say you have an index.html
<div ui-view="content"></div>
and state provider is like this :-
$stateProvider
.state('books', {
parent: 'pages',
url: '/books',
views: {
'content#': {
templateUrl: 'books.html',
controller: 'BooksController'
}
}
})
In books.html you have some links and another ui-view (nested ui-view). On click of links populate the nested ui-view.
books.html
<div>
<a ui-sref="book1"></a>
<a ui-sref="book2"></a>
<a ui-sref="book3"></a>
</div>
<!-- nested ui-view -->
<div ui-view="bookDetails"></div>
now state provider is :-
$stateProvider
.state('books', {
parent: 'pages',
url: '/books',
views: {
'content#': {
templateUrl: 'books.html',
controller: 'BooksController'
}
}
})
.state('book1', {
parent: 'books',
views: {
'bookDetails#books': {
templateUrl: 'book1.html',
controller: 'BookOneController'
}
}
})
.state('book2', {
parent: 'books',
views: {
'bookDetails#books': {
templateUrl: 'book2.html',
controller: 'BookTwoController'
}
}
})
.state('book3', {
parent: 'books',
views: {
'bookDetails#books': {
templateUrl: 'book3.html',
controller: 'BookThreeController'
}
}
})
bookDetails#books :- populate 'bookDetails' ui-view in 'books' state or we can say that find 'bookDetails' ui-view inside 'books' state and populate it with 'views' object.
As i explained earlier i just want to make 'ui-view inside another ui-view', but it seems impossible. I found two ways to resolve this "bug"(?).
First way: Exclude 'ui-view inside another ui-view' and use 'ng-include'
Simplest variant with minimal change of code. As you see here, i replaced
<div ui-view="{{vm.currentView}}"></div>
with
<ng-include src="vm.getTemplateUrl(vm.selectedBook.id)"/>
and add function to controller, thats switch templates:
function getTemplateUrl(id) {
switch (id) {
case 0:
return 'tab2-book1.html';
case 1:
return 'tab2-book2.html';
case 2:
return 'tab2-book3.html';
case 3:
return 'tab2-book4.html';
default:
return 'tab2-book4.html';
}
}
Second way: Formally save 'ui-view inside another ui-view' and separate views by states
And as you see here, formally i save 'ui-view inside ui-view', but in fact i just fully replace single ui-view by template from another single ui-view (can't set second ui-view by name).
$urlRouterProvider
.when('/tab2', '/tab2/book4');
$stateProvider
.state('tab2', {
url: '/tab2',
templateUrl: 'tab2.html'
})
.state('tab2.book1', {
url: '/book1',
params: {
id: 0
},
templateUrl: 'tab2-book1.html',
controller: 'Tab2Controller',
controllerAs: 'vm'
})
.state('tab2.book2', {
url: '/book2',
params: {
id: 1
},
templateUrl: 'tab2-book2.html',
controller: 'Tab2Controller',
controllerAs: 'vm'
})
.state('tab2.book3', {
url: '/book3',
params: {
id: 2
},
templateUrl: 'tab2-book3.html',
controller: 'Tab2Controller',
controllerAs: 'vm'
})
.state('tab2.book4', {
url: '/book4',
params: {
id: 3
},
templateUrl: 'tab2-book4.html',
controller: 'Tab2Controller',
controllerAs: 'vm'
});
Where content of tab2.html is:
<ui-view class="page-container"></ui-view>
When selector changed i call vm.changeHandbook(vm.selectedBook) to switch templates:
function changeHandbook(ref) {
$state.go(ref.value);
}
This is most weird and difficult way, but in the end we get more cleaner code.

Same html page for different tabs in Angular UI Router

My angular app is routed as following:
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
// Each tab has its own nav history stack:
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab-dotnet.html',
controller: 'QuestionsCtrl'
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab-sql.html',
controller: 'QuestionsCtrl'
}
}
})
The above two routes use the same controller but different html pages.
Since both the pages are same, I want to have a single html page in my application instead of two different tab-sql and tab-dotnet pages.
But I will need a differentiation variable to be injected to the controller when selecting the tabs.
Basically I need something like this:
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
type: 'dotnet' // so that i get this type in my Controller
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
type: 'sql'
}
}
})
How to achieve this?
You can pass data to controllers in a state using resolve.
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
resolve: {
type: 'dotnet';
}
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
resolve: {
type: 'sql';
}
}
}
})
https://github.com/angular-ui/ui-router/wiki#resolve

Angular UI-Router multiple views

I am using angular UI-Router. I have the following in my route config
.config(function config($stateProvider) {
$stateProvider.state('newsFeedView', {
url: '/newsFeed',
controller: 'newsFeedController',
templateUrl: '../src/app/bulletinBoard/views/newsFeed.part.html',
data: {
pageTitle: 'News Feed'
}
})
.state('tradeFeedView', {
url: '/tradeFeed',
controller: 'tradeFeedController',
templateUrl: '../src/app/bulletinBoard/views/tradeFeed.part.html',
data: {
pageTitle: 'Trade Feed'
}
})
.state('bulletinBoard', {
url: '/bulletinBoard',
views: {
'tradeFeed': {
url: "",
controller: 'tradeFeedController',
templateUrl: '../src/app/bulletinBoard/views/tradeFeed.part.html'
},
'newsFeed': {
url: "",
controller: 'newsFeedController',
templateUrl: '../src/app/bulletinBoard/views/newsFeed.part.html'
}
},
templateUrl: '../src/app/bulletinBoard/views/bulletinBoard.part.html'
});
})
In my index page I just invoke the view using:
<div class="container" ui-view></div>
In My bulletinBoard.html i want to have a nested view:
<div ui-view="tradeFeed"></div>
<div ui-view="newsFeed"></div>
For the /newsFeed page and the /tradeFeed pages this works perfectly but for the bulletin board i can't see anything on the page. Where am i going wrong?
I find the example on the official GitHub wiki to be very unintuitive. Here is a better one:
https://scotch.io/tutorials/angular-routing-using-ui-router
For instance:
...
.state('bulletinBoard', {
url: '/bulletinBoard',
views: {
// the main template will be placed here (relatively named)
'': { templateUrl: '../src/app/bulletinBoard/views/bulletinBoard.part.html' },
// the child views will be defined here (absolutely named)
'tradeFeed#bulletinBoard': { template: ..... },
// another child view
'newsFeed#bulletinBoard': {
templateUrl: ......
}
}
});
The syntax of each view attribute being viewName#stateName.
The .state() method's templateUrl is ignored when using the views object. See the ui-router wiki for more info:
https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views#user-content-views-override-states-template-properties

Resources